From 76b8831562ce73abf0dbdcf740439716834ac3bc Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Tue, 6 Jan 2026 10:44:43 +0800 Subject: [PATCH 01/44] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E8=B7=A8=E5=9F=9F?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/config/CorsConfig.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/config/CorsConfig.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/config/CorsConfig.java b/backend/src/main/java/com/unionbigdata/teaching/config/CorsConfig.java new file mode 100644 index 0000000..8861d30 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/config/CorsConfig.java @@ -0,0 +1,26 @@ +package com.unionbigdata.teaching.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration +public class CorsConfig { + + // 当前跨域请求最大有效时长。这里默认1天 + private static final long MAX_AGE = 24 * 60 * 60; + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址 + corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头 + corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法 + corsConfiguration.setMaxAge(MAX_AGE); + source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置 + return new CorsFilter(source); + } +} \ No newline at end of file -- Gitee From 2ff0c405dd18c34d89a4f69b5ad5df664ce8327c Mon Sep 17 00:00:00 2001 From: lxm <3318952246@qq.com> Date: Tue, 6 Jan 2026 11:49:25 +0800 Subject: [PATCH 02/44] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E5=BB=BA=E7=AB=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/web-management-vue3/src/App.vue | 73 +----------- .../web-management-vue3/src/assets/main.css | 4 +- frontend/web-management-vue3/src/main.ts | 6 +- .../web-management-vue3/src/router/index.ts | 64 +++++++--- .../src/views/Data/index.vue | 19 +++ .../src/views/Layout/index.vue | 111 ++++++++++++++++++ .../src/views/Quality/index.vue | 19 +++ .../src/views/Task/index.vue | 19 +++ 8 files changed, 222 insertions(+), 93 deletions(-) create mode 100644 frontend/web-management-vue3/src/views/Data/index.vue create mode 100644 frontend/web-management-vue3/src/views/Layout/index.vue create mode 100644 frontend/web-management-vue3/src/views/Quality/index.vue create mode 100644 frontend/web-management-vue3/src/views/Task/index.vue diff --git a/frontend/web-management-vue3/src/App.vue b/frontend/web-management-vue3/src/App.vue index 7905b05..b9de61b 100644 --- a/frontend/web-management-vue3/src/App.vue +++ b/frontend/web-management-vue3/src/App.vue @@ -1,85 +1,14 @@ - - - - - - - Home - About - - - diff --git a/frontend/web-management-vue3/src/assets/main.css b/frontend/web-management-vue3/src/assets/main.css index 36fb845..cd97abd 100644 --- a/frontend/web-management-vue3/src/assets/main.css +++ b/frontend/web-management-vue3/src/assets/main.css @@ -1,9 +1,9 @@ @import './base.css'; #app { - max-width: 1280px; + /* max-width: 1280px; */ margin: 0 auto; - padding: 2rem; + padding: 1rem; font-weight: normal; } diff --git a/frontend/web-management-vue3/src/main.ts b/frontend/web-management-vue3/src/main.ts index 5dcad83..f45dbbb 100644 --- a/frontend/web-management-vue3/src/main.ts +++ b/frontend/web-management-vue3/src/main.ts @@ -6,9 +6,13 @@ import { createPinia } from 'pinia' import App from './App.vue' import router from './router' +import ElementPlus from 'element-plus' +// 引入 Element Plus 样式(关键!没有这个布局样式不生效) +import 'element-plus/dist/index.css' + const app = createApp(App) app.use(createPinia()) app.use(router) - +app.use(ElementPlus) app.mount('#app') diff --git a/frontend/web-management-vue3/src/router/index.ts b/frontend/web-management-vue3/src/router/index.ts index 3e49915..35b8e3a 100644 --- a/frontend/web-management-vue3/src/router/index.ts +++ b/frontend/web-management-vue3/src/router/index.ts @@ -1,23 +1,51 @@ -import { createRouter, createWebHistory } from 'vue-router' -import HomeView from '../views/HomeView.vue' +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' // 1. 导入 TS 类型 +// 导入布局组件 +import LayoutContainer from '@/views/Layout/index.vue' +// 优化:改为懒加载(减小初始打包体积,符合最佳实践) +const TaskFormulation = () => import('@/views/Task/index.vue') +const DataCollection = () => import('@/views/Data/index.vue') +const QualityInspectionResult = () => import('@/views/Quality/index.vue') + +// 2. 显式标注 routes 类型为 RouteRecordRaw[] +const routes: RouteRecordRaw[] = [ + { + path: '/', + redirect: '/task-formulation', // 3. 修正重定向路径(小写 + 有效路径) + component: LayoutContainer, + children: [ + { + path: 'task-formulation', // 和侧边栏菜单 index="/task-formulation" 完全匹配 + name: 'TaskFormulation', + component: TaskFormulation, + meta: { title: '任务制定' } + }, + { + path: 'data-collection', // 和侧边栏菜单 index="/data-collection" 匹配 + name: 'DataCollection', + component: DataCollection, + meta: { title: '采集任务' } + }, + { + path: 'quality-inspection-result', // 和侧边栏菜单 index="/quality-inspection-result" 匹配 + name: 'QualityInspectionResult', + component: QualityInspectionResult, + meta: { title: '质检结果库' } + } + ] + } +] const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: '/', - name: 'home', - component: HomeView, - }, - { - path: '/about', - name: 'about', - // route level code-splitting - // this generates a separate chunk (About.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import('../views/AboutView.vue'), - }, - ], + routes +}) + +// 可选优化:路由守卫 - 自动设置页面标题 +router.beforeEach((to, from, next) => { + if (to.meta.title) { + document.title = `${to.meta.title} - 数据采集系统` + } + next() }) -export default router +export default router \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Data/index.vue b/frontend/web-management-vue3/src/views/Data/index.vue new file mode 100644 index 0000000..ec2814b --- /dev/null +++ b/frontend/web-management-vue3/src/views/Data/index.vue @@ -0,0 +1,19 @@ + + + 采集任务 + 这里是采集任务的核心功能区,可查看任务列表、执行状态、手动触发采集等。 + + + + + + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Layout/index.vue b/frontend/web-management-vue3/src/views/Layout/index.vue new file mode 100644 index 0000000..a2c3d84 --- /dev/null +++ b/frontend/web-management-vue3/src/views/Layout/index.vue @@ -0,0 +1,111 @@ + + + + + 数据采集系统 + + + + + + + + + + 任务制定 + + + + + 采集任务 + + + + + 质检结果库 + + + + + + + + + + + + + + + diff --git a/frontend/web-management-vue3/src/views/Quality/index.vue b/frontend/web-management-vue3/src/views/Quality/index.vue new file mode 100644 index 0000000..cf7c2a9 --- /dev/null +++ b/frontend/web-management-vue3/src/views/Quality/index.vue @@ -0,0 +1,19 @@ + + + 质检结果库 + 这里是质检结果库的核心功能区,可查看质检记录、统计分析、导出报告等。 + + + + + + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Task/index.vue b/frontend/web-management-vue3/src/views/Task/index.vue new file mode 100644 index 0000000..abdd4af --- /dev/null +++ b/frontend/web-management-vue3/src/views/Task/index.vue @@ -0,0 +1,19 @@ + + + 任务制定 + 这里是任务制定的核心功能区,可添加任务配置、规则设置等内容。 + + + + + + \ No newline at end of file -- Gitee From 99f84cc37be2f0cad221ac8e8fbf4020da2a9ea2 Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Wed, 7 Jan 2026 17:25:51 +0800 Subject: [PATCH 03/44] =?UTF-8?q?=E6=95=8F=E6=84=9F=E8=AF=8D=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/DTO/SensitiveWordBatchDTO.java | 16 +++ .../controller/SensitiveWordController.java | 67 ++++++++++++ .../teaching/entity/SensitiveWord.java | 27 +++++ .../teaching/mapper/SensitiveWordMapper.java | 41 +++++++ .../teaching/mapper/xml/SensitiveWMapper.xml | 50 +++++++++ .../sevice/ISensitiveWordService.java | 27 +++++ .../sevice/impl/SensitiveWordServiceImpl.java | 102 ++++++++++++++++++ .../teaching/vo/SensitiveWordVO.java | 20 ++++ 8 files changed, 350 insertions(+) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/SensitiveWord.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/SensitiveWordVO.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java b/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java new file mode 100644 index 0000000..a72b987 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java @@ -0,0 +1,16 @@ +package com.unionbigdata.teaching.DTO; + +import com.unionbigdata.teaching.entity.SensitiveWord; +import lombok.Data; + +import java.util.List; + +@Data +public class SensitiveWordBatchDTO { + // 新增的敏感词列表 + private List add; + // 修改的敏感词列表 + private List update; + // 删除的敏感词列表 + private List delete; +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java new file mode 100644 index 0000000..58ea974 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java @@ -0,0 +1,67 @@ +package com.unionbigdata.teaching.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.unionbigdata.teaching.DTO.SensitiveWordBatchDTO; +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.entity.SensitiveWord; +import com.unionbigdata.teaching.sevice.ISensitiveWordService; +import com.unionbigdata.teaching.vo.SensitiveWordVO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/sensitiveWord") +public class SensitiveWordController { + + @Autowired + private ISensitiveWordService sensitiveWordService; + + @GetMapping("/list")//返回全部敏感词 + public Result> findAllSensitiveWord(){ + return Result.ok(sensitiveWordService.findAllSensitiveWord()); + } + +/** + * 添加敏感词的接口方法 + * @param sensitiveWord 敏感词信息,通过请求体传递 + * @return 返回操作结果,包含添加的敏感词ID + */ + @PostMapping//添加敏感词 + public Result addSensitiveWord(@RequestBody SensitiveWord sensitiveWord){ + return Result.ok(sensitiveWordService.addSensitiveWord(sensitiveWord)); + } + + @DeleteMapping("/{id}")//根据id删除敏感词 + public Result deleteSensitiveWord(@PathVariable Integer id){ + return Result.ok(sensitiveWordService.deleteSensitiveWord(id)); + } + +// // 批量修改 +// @PostMapping("/updateSensitiveWordBatch") +// public Result updateSensitiveWordBatch(@RequestBody List sensitiveWordList) { +// // 调用Service的批量修改方法 +// int count = sensitiveWordService.updateSensitiveWordBatch(sensitiveWordList); +// return Result.ok(count); // 返回修改的记录数 +// } + + // 批量修改 + @PostMapping("/batch") + public Result updateSensitiveWordBatch(@RequestBody SensitiveWordBatchDTO batchDTO) { + return Result.ok(sensitiveWordService.updateSensitiveWordBatch(batchDTO.getAdd(), batchDTO.getUpdate(), batchDTO.getDelete())); + } + + @GetMapping("/page")//分页查询 + public Result findPage(@RequestParam Integer pageNum, + @RequestParam Integer pageSize) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //queryWrapper.orderByDesc(User::getId); //设置降序查询,默认升序 + + Page page = new Page<>(pageNum,pageSize);//Page中的User要与userSerice对应 + + return Result.ok(sensitiveWordService.page(page, queryWrapper)); + } +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/SensitiveWord.java b/backend/src/main/java/com/unionbigdata/teaching/entity/SensitiveWord.java new file mode 100644 index 0000000..d67bbcb --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/SensitiveWord.java @@ -0,0 +1,27 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +@TableName("sensitive_word") +@Data +public class SensitiveWord { + @TableId(value = "id",type = IdType.AUTO) + private Long id; + + //敏感词 + private String wordContent; + + //创建时间 + private LocalDateTime createTime; + + //更新时间 + private LocalDateTime updateTime; + + //是否启用 0不启用,1启用 + private Integer isEnabled; +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java new file mode 100644 index 0000000..8b30046 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java @@ -0,0 +1,41 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.SensitiveWord; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SensitiveWordMapper extends BaseMapper { + List findSensitiveWordList(); + +/** + * 根据ID删除记录 + * @param id 要删除的记录ID + * @return 删除操作的结果,通常返回受影响的行数或成功/失败标志 + */ + Integer deleteById(Integer id); + +/** + * 保存敏感词信息的方法声明 + * + * @param sensitiveWord 包含敏感词信息的对象 + * @return 如果保存成功返回true,否则返回false + */ + boolean save(SensitiveWord sensitiveWord); // 声明一个保存敏感词的方法,返回布尔值表示操作是否成功 + +/** + * 批量更新敏感词信息 + * @param sensitiveWordList 敏感词列表,包含需要更新的敏感词信息 + * @return 更新操作影响的记录数,用于判断更新是否成功 + */ + int updateBatch(List sensitiveWordList); + +/** + * 根据敏感词ID查询敏感词信息 + * @param id 敏感词的唯一标识ID + * @return 返回对应的敏感词对象,如果未找到则返回null + */ + SensitiveWord findSensitiveWordById(Integer id); +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml new file mode 100644 index 0000000..c78c798 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml @@ -0,0 +1,50 @@ + + + + + + + select id, is_enabled, word_content + from sensitive_word + + + + + delete from sensitive_word + where id = #{id} + + + + select id, is_enabled, word_content + from sensitive_word + where id = #{id} + + + + + insert into sensitive_word (is_enabled, word_content) + values (#{isEnabled}, #{wordContent}) + + + + + update sensitive_word + + word_content = case id + + when #{item.id} then #{item.wordContent} + + end, + is_enabled = case id + + when #{item.id} then #{item.isEnabled} + + end + + where id in + + #{item.id} + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java new file mode 100644 index 0000000..6911ae5 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java @@ -0,0 +1,27 @@ +package com.unionbigdata.teaching.sevice; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.unionbigdata.teaching.entity.SensitiveWord; +import com.unionbigdata.teaching.vo.SensitiveWordVO; +import org.springframework.stereotype.Service; + +import java.util.List; + +public interface ISensitiveWordService extends IService { + + List findAllSensitiveWord(); + +/** + * 删除敏感词的方法 + * @param id 需要删除的敏感词的id + * @return 返回操作结果,Integer类型,通常用于表示删除的记录数或操作状态 + */ + Integer deleteSensitiveWord(Integer id); + + + boolean addSensitiveWord(SensitiveWord sensitiveWord); + + Integer updateSensitiveWordBatch(List add, List update, List delete); + +// int updateSensitiveWordBatch(List sensitiveWordList); +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java new file mode 100644 index 0000000..b114b53 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java @@ -0,0 +1,102 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.unionbigdata.teaching.entity.SensitiveWord; +import com.unionbigdata.teaching.entity.UserEntity; +import com.unionbigdata.teaching.mapper.SensitiveWordMapper; +import com.unionbigdata.teaching.sevice.ISensitiveWordService; +import com.unionbigdata.teaching.vo.SensitiveWordVO; +import com.unionbigdata.teaching.vo.UserVO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.util.List; + +@Service +public class SensitiveWordServiceImpl extends ServiceImpl implements ISensitiveWordService{ + + @Resource + private SensitiveWordMapper sensitiveWordMapper; + +/** + * 查找所有敏感词信息 + * @return 返回敏感词视图对象列表(SensitiveWordVO) + */ + @Override + public List findAllSensitiveWord() { + // 从数据库中获取所有敏感词数据 + List sensitiveWordList = sensitiveWordMapper.findSensitiveWordList(); + // 将实体对象列表转换为视图对象列表并返回 + return sensitiveWordList.stream().map(this::convertSensitiveWordVO).toList(); + } + +/** + * 删除敏感词方法 + * @param id 敏感词ID + * @return 返回删除的记录数,通常为1表示成功删除,0表示未找到对应记录 + */ + @Override + public Integer deleteSensitiveWord(Integer id) { + // 调用敏感词数据访问层的删除方法,根据ID删除敏感词 + return sensitiveWordMapper.deleteById(id); + } + + +/** + * 添加敏感词方法 + * @param sensitiveWord 敏感词对象,包含需要添加的敏感词信息 + * @return 返回操作结果,true表示添加成功,false表示添加失败 + */ + @Override + public boolean addSensitiveWord(SensitiveWord sensitiveWord) { + // 调用敏感词映射器的save方法,保存敏感词信息并返回操作结果 + return sensitiveWordMapper.save(sensitiveWord); + } + +/** + * 批量更新敏感词信息的方法 + * 包括新增、修改和删除三种操作 + * + * @param addSensitiveWordList 需要新增的敏感词列表 + * @param updateSensitiveWordList 需要修改的敏感词列表 + * @param deleteSensitiveWordList 需要删除的敏感词列表 + * @return 返回操作结果,此处固定返回0 + */ + @Override + public Integer updateSensitiveWordBatch(List addSensitiveWordList, List updateSensitiveWordList, List deleteSensitiveWordList) { + // 遍历新增敏感词列表,逐个保存 + for (SensitiveWord sensitiveWord : addSensitiveWordList) { + sensitiveWordMapper.save(sensitiveWord); + } + // 遍历更新敏感词列表,逐个更新 + for (SensitiveWord sensitiveWord : updateSensitiveWordList) { + sensitiveWordMapper.updateById(sensitiveWord); + } + // 遍历删除敏感词列表,逐个删除 + for (Integer id : deleteSensitiveWordList) { + sensitiveWordMapper.deleteById(id); + } + return 0; + } + + // 批量修改的实现 +// @Override +// public int updateSensitiveWordBatch(List sensitiveWordList) { +// for( SensitiveWord sensitiveWord : sensitiveWordList){ +// Long id = sensitiveWord.getId(); +// } +// // 调用Mapper的批量更新方法 +// return sensitiveWordMapper.updateBatch(sensitiveWordList); +// } + + private SensitiveWordVO convertSensitiveWordVO(SensitiveWord sensitiveWord) { + SensitiveWordVO sensitiveWordVO = new SensitiveWordVO(); + if (!ObjectUtils.isEmpty(sensitiveWord)) { + sensitiveWordVO.setId(sensitiveWord.getId()); + sensitiveWordVO.setWordContent(sensitiveWord.getWordContent()); + sensitiveWordVO.setIsEnabled(sensitiveWord.getIsEnabled()); + } + return sensitiveWordVO; + } +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/SensitiveWordVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/SensitiveWordVO.java new file mode 100644 index 0000000..3048837 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/SensitiveWordVO.java @@ -0,0 +1,20 @@ +package com.unionbigdata.teaching.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "敏感词VO") +@Data +public class SensitiveWordVO { + + @Schema(description = "敏感词ID") + private Long id; + + //敏感词 + @Schema(description = "敏感词") + private String wordContent; + + //是否启用 + @Schema(description = "是否启用") + private Integer isEnabled; +} -- Gitee From f0b45e883ff89736d763d1d902da273cddb307b6 Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Wed, 7 Jan 2026 19:51:35 +0800 Subject: [PATCH 04/44] =?UTF-8?q?=E6=95=8F=E6=84=9F=E8=AF=8D=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pom.xml | 3 +- .../teaching/DTO/SensitiveWordBatchDTO.java | 2 +- .../teaching/controller/UserController.java | 6 ++ .../teaching/mapper/SensitiveWordMapper.java | 9 +++ .../sevice/impl/SensitiveWordServiceImpl.java | 6 +- .../teaching/sevice/impl/UserServiceImpl.java | 2 - .../teaching/utils/SensitiveWordManager.java | 70 +++++++++++++++++++ backend/src/main/resources/application.yml | 7 +- 8 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/utils/SensitiveWordManager.java diff --git a/backend/pom.xml b/backend/pom.xml index 34e1ce2..7e02cb9 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -59,8 +59,7 @@ org.projectlombok lombok - 1.18.34 - provided + 1.18.42 diff --git a/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java b/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java index a72b987..c4e5994 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java +++ b/backend/src/main/java/com/unionbigdata/teaching/DTO/SensitiveWordBatchDTO.java @@ -6,7 +6,7 @@ import lombok.Data; import java.util.List; @Data -public class SensitiveWordBatchDTO { +public class SensitiveWordBatchDTO {//用于前端“敏感词设置”页面 // 新增的敏感词列表 private List add; // 修改的敏感词列表 diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/UserController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/UserController.java index a9baf2f..76c3974 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/UserController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/UserController.java @@ -24,6 +24,12 @@ public class UserController { return Result.ok(testService.findById(id)); } + @GetMapping("/a") + public String ces(){ + String a = "123"; + return a; + } + @Operation(summary = "新增用户") @PostMapping public Result saveUser(@RequestBody UserVO userVO) { diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java index 8b30046..a58241e 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java @@ -3,6 +3,7 @@ package com.unionbigdata.teaching.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.unionbigdata.teaching.entity.SensitiveWord; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -38,4 +39,12 @@ public interface SensitiveWordMapper extends BaseMapper { * @return 返回对应的敏感词对象,如果未找到则返回null */ SensitiveWord findSensitiveWordById(Integer id); + +/** + * 查询所有启用的词语内容 + * + * @return 返回启用的词语内容列表,每个元素是一个字符串 + */ + @Select("select word_content from sensitive_word where is_enabled = 1") + List selectEnabledWordContents(); } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java index b114b53..223d408 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java @@ -2,11 +2,10 @@ package com.unionbigdata.teaching.sevice.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.unionbigdata.teaching.entity.SensitiveWord; -import com.unionbigdata.teaching.entity.UserEntity; import com.unionbigdata.teaching.mapper.SensitiveWordMapper; import com.unionbigdata.teaching.sevice.ISensitiveWordService; +import com.unionbigdata.teaching.utils.SensitiveWordManager; import com.unionbigdata.teaching.vo.SensitiveWordVO; -import com.unionbigdata.teaching.vo.UserVO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; @@ -19,6 +18,9 @@ public class SensitiveWordServiceImpl extends ServiceImpl enabledSensitiveWords = new HashSet<>(); + // 敏感词匹配的正则表达式(预编译,提升性能) + private Pattern sensitiveWordPattern; + + // 注入敏感词Mapper,用于从数据库查询敏感词 + private final SensitiveWordMapper sensitiveWordMapper; + public SensitiveWordManager(SensitiveWordMapper sensitiveWordMapper) { + this.sensitiveWordMapper = sensitiveWordMapper; + } + + /** + * 项目启动时自动加载【启用的敏感词】到缓存 + */ + @PostConstruct + public void loadEnabledSensitiveWords() { + // 从数据库查询:is_enabled=1的敏感词内容 + List words = sensitiveWordMapper.selectEnabledWordContents(); + enabledSensitiveWords.clear(); + enabledSensitiveWords.addAll(words); + + // 构建敏感词正则(转义特殊字符,避免正则语法错误) + if (!enabledSensitiveWords.isEmpty()) { + StringBuilder regexBuilder = new StringBuilder(); + for (String word : enabledSensitiveWords) { + // Pattern.quote():转义敏感词中的特殊字符(如.、*、|等) + regexBuilder.append(Pattern.quote(word)).append("|"); + } + // 移除最后一个多余的"|" + regexBuilder.deleteCharAt(regexBuilder.length() - 1); + // 编译正则(忽略大小写,避免漏检“美国”和“美國”) + sensitiveWordPattern = Pattern.compile(regexBuilder.toString(), Pattern.CASE_INSENSITIVE); + } + } + + /** + * 核心方法:对单个字符串做敏感词替换(替换为等长度的*) + * @param text 待检测的文本 + * @return 替换敏感词后的文本 + */ + public String replaceSensitiveWord(String text) { + // 空值/无敏感词时直接返回原文本 + if (text == null || text.isEmpty() || sensitiveWordPattern == null) { + return text; + } + + Matcher matcher = sensitiveWordPattern.matcher(text); + // 匹配到敏感词则替换为等长度的“*” + return matcher.replaceAll(matchResult -> { + String matchedWord = matchResult.group(); + return "*".repeat(matchedWord.length()); + }); + } +} \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 8f7cf05..bbf33db 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -1,13 +1,14 @@ server: port: 8080 + address: 0.0.0.0 # 关键:监听所有网络接口 spring: application: - name: data-acqusition-system + name: supplementary_data_collection datasource: - url: jdbc:mysql://localhost:3306/data-acqusition-system?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai + url: jdbc:mysql://localhost:3306/supplementary_data_collection?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root - password: 123456 + password: 1234 driver-class-name: com.mysql.cj.jdbc.Driver sql: init: -- Gitee From 810bece2ae6eb0320222729ed16739690608519c Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Fri, 9 Jan 2026 08:58:53 +0800 Subject: [PATCH 05/44] =?UTF-8?q?=E6=95=8F=E6=84=9F=E8=AF=8D=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/DTO/DynamicTableRequestDTO.java | 17 ++++++ .../controller/SensitiveWordController.java | 6 ++ .../teaching/mapper/SensitiveWordMapper.java | 4 ++ .../teaching/mapper/xml/SensitiveWMapper.xml | 1 + .../sevice/ISensitiveWordService.java | 3 + .../sevice/impl/SensitiveWordServiceImpl.java | 59 ++++++++++++++++--- 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/DTO/DynamicTableRequestDTO.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/DTO/DynamicTableRequestDTO.java b/backend/src/main/java/com/unionbigdata/teaching/DTO/DynamicTableRequestDTO.java new file mode 100644 index 0000000..4bb4a46 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/DTO/DynamicTableRequestDTO.java @@ -0,0 +1,17 @@ +package com.unionbigdata.teaching.DTO; +import lombok.Data; +import java.util.List; +import java.util.Map; + +/** + * 接收动态表格数据的DTO + */ +@Data +public class DynamicTableRequestDTO { + // 补充采集任务ID(关联该任务的字段配置) + private Integer taskId; + // 该表的字段名 + private List filedName; + // 动态表格行数据:每一行是“字段名→值”的键值对。一个Map可以装很多,一个Map存一行 + private List> tableRows; +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java index 58ea974..1ed91bd 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/SensitiveWordController.java @@ -2,6 +2,7 @@ package com.unionbigdata.teaching.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; import com.unionbigdata.teaching.DTO.SensitiveWordBatchDTO; import com.unionbigdata.teaching.common.Result; import com.unionbigdata.teaching.entity.SensitiveWord; @@ -64,4 +65,9 @@ public class SensitiveWordController { return Result.ok(sensitiveWordService.page(page, queryWrapper)); } + + @PostMapping("/dataFilter") + public Result checkAndReplaceSensitiveWord(@RequestBody DynamicTableRequestDTO dynamicDTO) {//如何接收不同表的实体? + return Result.ok(sensitiveWordService.checkAndReplaceSensitiveWord(dynamicDTO)); + } } diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java index a58241e..ddbebf4 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/SensitiveWordMapper.java @@ -9,6 +9,10 @@ import java.util.List; @Mapper public interface SensitiveWordMapper extends BaseMapper { +/** + * 查询敏感词列表的方法 + * @return 返回敏感词列表,包含所有敏感词信息的集合 + */ List findSensitiveWordList(); /** diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml index c78c798..bd031ce 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/SensitiveWMapper.xml @@ -2,6 +2,7 @@ + select id, is_enabled, word_content diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java index 6911ae5..4cea4c6 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ISensitiveWordService.java @@ -1,6 +1,7 @@ package com.unionbigdata.teaching.sevice; import com.baomidou.mybatisplus.extension.service.IService; +import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; import com.unionbigdata.teaching.entity.SensitiveWord; import com.unionbigdata.teaching.vo.SensitiveWordVO; import org.springframework.stereotype.Service; @@ -23,5 +24,7 @@ public interface ISensitiveWordService extends IService { Integer updateSensitiveWordBatch(List add, List update, List delete); + Object checkAndReplaceSensitiveWord(DynamicTableRequestDTO dynamicDTO); + // int updateSensitiveWordBatch(List sensitiveWordList); } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java index 223d408..ed23567 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java @@ -1,6 +1,8 @@ package com.unionbigdata.teaching.sevice.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; +import com.unionbigdata.teaching.common.Result; import com.unionbigdata.teaching.entity.SensitiveWord; import com.unionbigdata.teaching.mapper.SensitiveWordMapper; import com.unionbigdata.teaching.sevice.ISensitiveWordService; @@ -9,8 +11,11 @@ import com.unionbigdata.teaching.vo.SensitiveWordVO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import java.util.List; +import java.util.Map; @Service public class SensitiveWordServiceImpl extends ServiceImpl implements ISensitiveWordService{ @@ -33,6 +38,16 @@ public class SensitiveWordServiceImpl extends ServiceImpl filedName = dynamicDTO.getFiledName(); + // 获取表格所有行数据 + List> tableRows = dynamicDTO.getTableRows(); + + int rowNum = 1; // 新增:用于记录当前处理的行号 + // 2. 遍历每一行数据,进行敏感词检测+替换 + for (Map row : tableRows) { + // 遍历该行的每个字段 + // 新增:打印当前处理的行号 + 处理前的原始数据(方便对比) + System.out.println("========== 开始处理第 " + rowNum + " 行数据 =========="); + System.out.println("处理前的原始数据:" + row); + // 对每个字段进行处理 + for (String name : filedName) { + // 获取字段值(注意类型转换,前端传的是String) + String fieldValue = (row.get(name) == null) ? "" : row.get(name).toString(); + // 敏感词替换 + String replacedValue = sensitiveWordManager.replaceSensitiveWord(fieldValue); + // 替换后写回Map + row.put(name, replacedValue); + } + // 新增:打印处理后的行数据(对比原始数据,确认敏感词是否替换成功) + System.out.println("处理后的行数据:" + row); + System.out.println("========== 第 " + rowNum + " 行数据处理完成 ==========\n"); + rowNum++; } - return sensitiveWordVO; + return null; } } -- Gitee From 9ac917f9172a9943562b3efe067690200d6e32de Mon Sep 17 00:00:00 2001 From: lxm87954 <14417944+lxm87954@user.noreply.gitee.com> Date: Fri, 9 Jan 2026 10:44:18 +0800 Subject: [PATCH 06/44] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=88=B6=E5=AE=9A?= =?UTF-8?q?=E4=B8=8E=E8=B4=A8=E6=A3=80=E7=BB=93=E6=9E=9C=E5=BA=93=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E9=A1=B5=E9=9D=A2=EF=BC=8C=E6=96=B0=E5=A2=9Eaxios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-management-vue3/package-lock.json | 671 +++++++++++++ frontend/web-management-vue3/package.json | 2 + frontend/web-management-vue3/src/api/Task.ts | 115 +++ .../src/api/sensitiveWord.ts | 26 + .../web-management-vue3/src/router/index.ts | 108 ++- .../web-management-vue3/src/utils/request.ts | 76 ++ .../src/views/Layout/index.vue | 78 +- .../src/views/Quality/QualityCheckDetail.vue | 366 +++++++ .../src/views/Quality/index.vue | 299 +++++- .../src/views/Task/TaskAdd.vue | 908 ++++++++++++++++++ .../src/views/Task/index.vue | 445 ++++++++- 11 files changed, 3032 insertions(+), 62 deletions(-) create mode 100644 frontend/web-management-vue3/src/api/Task.ts create mode 100644 frontend/web-management-vue3/src/api/sensitiveWord.ts create mode 100644 frontend/web-management-vue3/src/utils/request.ts create mode 100644 frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue create mode 100644 frontend/web-management-vue3/src/views/Task/TaskAdd.vue diff --git a/frontend/web-management-vue3/package-lock.json b/frontend/web-management-vue3/package-lock.json index 86d964e..28a83a7 100644 --- a/frontend/web-management-vue3/package-lock.json +++ b/frontend/web-management-vue3/package-lock.json @@ -8,6 +8,7 @@ "name": "web-management-vue3", "version": "0.0.0", "dependencies": { + "axios": "^1.13.2", "element-plus": "^2.13.0", "pinia": "^3.0.4", "vue": "^3.5.26", @@ -32,6 +33,7 @@ "npm-run-all2": "^8.0.4", "oxlint": "~1.35.0", "prettier": "3.7.4", + "sass": "^1.97.2", "typescript": "~5.9.3", "vite": "npm:rolldown-vite@latest", "vite-plugin-vue-devtools": "^8.0.5", @@ -1277,6 +1279,330 @@ "win32" ] }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2705,6 +3031,23 @@ "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2821,6 +3164,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", @@ -2879,6 +3235,22 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", @@ -2899,6 +3271,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmmirror.com/commander/-/commander-10.0.1.tgz", @@ -3107,6 +3491,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", @@ -3117,6 +3510,20 @@ "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3233,6 +3640,24 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz", @@ -3240,6 +3665,33 @@ "dev": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", @@ -3717,6 +4169,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", @@ -3734,6 +4206,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", @@ -3749,6 +4237,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3759,6 +4256,43 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmmirror.com/glob/-/glob-10.5.0.tgz", @@ -3806,6 +4340,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", @@ -3816,6 +4362,45 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", @@ -3873,6 +4458,13 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "dev": true, + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", @@ -4602,6 +5194,15 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdn-data": { "version": "2.12.2", "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.12.2.tgz", @@ -4648,6 +5249,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", @@ -4729,6 +5351,14 @@ "dev": true, "license": "MIT" }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.27.tgz", @@ -5233,6 +5863,12 @@ "dev": true, "license": "ISC" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", @@ -5278,6 +5914,20 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", @@ -5384,6 +6034,27 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/sass": { + "version": "1.97.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.2.tgz", + "integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/saxes/-/saxes-6.0.0.tgz", diff --git a/frontend/web-management-vue3/package.json b/frontend/web-management-vue3/package.json index 17b78c3..52b918c 100644 --- a/frontend/web-management-vue3/package.json +++ b/frontend/web-management-vue3/package.json @@ -19,6 +19,7 @@ "format": "prettier --write --experimental-cli src/" }, "dependencies": { + "axios": "^1.13.2", "element-plus": "^2.13.0", "pinia": "^3.0.4", "vue": "^3.5.26", @@ -43,6 +44,7 @@ "npm-run-all2": "^8.0.4", "oxlint": "~1.35.0", "prettier": "3.7.4", + "sass": "^1.97.2", "typescript": "~5.9.3", "vite": "npm:rolldown-vite@latest", "vite-plugin-vue-devtools": "^8.0.5", diff --git a/frontend/web-management-vue3/src/api/Task.ts b/frontend/web-management-vue3/src/api/Task.ts new file mode 100644 index 0000000..cff2e16 --- /dev/null +++ b/frontend/web-management-vue3/src/api/Task.ts @@ -0,0 +1,115 @@ +// src/api/task.ts +import { ElMessage } from 'element-plus' + +// 扩展Task接口,包含所有需要展示的详情字段 +export interface Task { + id: number + taskName: string + taskVersion: string + taskDesc: string + sensitiveCheck: boolean + dataSource: string + updateTime: string + publishTime: string + // 新增:详情需要的字段 + selectedTable: string // 选中的数据表(table1/table2) + collectedColumns: string[] // 采集的列名列表 + checkRuleNames: string[] // 质检规则名称列表 +} + +// 模拟任务列表数据(补充新增字段) +let taskList: Task[] = [ + { + id: 1, + taskName: '初始测试任务', + taskVersion: 'V1.0', + taskDesc: '初始任务描述', + sensitiveCheck: true, + dataSource: 'db_connect_a', + updateTime: '2024/8/6 12:01:30', + publishTime: '2024/8/6 12:01:30', + selectedTable: 'table1', // 补充默认值 + collectedColumns: ['ID', 'username', 'email'], // 补充默认采集列 + checkRuleNames: ['XX字段不为空', '手机号格式校验'] // 补充默认质检规则 + }, +] + +// 生成格式化的当前时间(不变) +const getCurrentTime = (): string => { + const date = new Date() + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + const hours = String(date.getHours()).padStart(2, '0') + const minutes = String(date.getMinutes()).padStart(2, '0') + const seconds = String(date.getSeconds()).padStart(2, '0') + return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}` +} + +// 1. 获取任务列表(不变) +export const getTaskList = (): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + resolve([...taskList]) + }, 100) + }) +} + +// 2. 新增任务(扩展参数,接收数据表、采集列、质检规则) +export const addTask = (task: Omit): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + const newTask: Task = { + id: Date.now(), + ...task, + updateTime: getCurrentTime(), + publishTime: getCurrentTime(), + } + taskList.push(newTask) + ElMessage.success('任务新增成功') + resolve(true) + }, 100) + }) +} + +// 3. 根据ID获取任务详情(不变) +export const getTaskById = (id: number): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + const task = taskList.find((item) => item.id === id) || null + resolve(task) + }, 100) + }) +} + +// 4. 编辑任务(扩展参数) +export const editTask = (id: number, task: Partial): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + const index = taskList.findIndex((item) => item.id === id) + if (index > -1) { + taskList[index] = { + ...taskList[index], + ...task, + updateTime: getCurrentTime(), + } + ElMessage.success('任务编辑成功') + resolve(true) + } else { + ElMessage.error('任务不存在') + resolve(false) + } + }, 100) + }) +} + +// 5. 删除任务(不变) +export const deleteTask = (ids: number[]): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + taskList = taskList.filter((item) => !ids.includes(item.id)) + ElMessage.success('任务删除成功') + resolve(true) + }, 100) + }) +} \ No newline at end of file diff --git a/frontend/web-management-vue3/src/api/sensitiveWord.ts b/frontend/web-management-vue3/src/api/sensitiveWord.ts new file mode 100644 index 0000000..586c70d --- /dev/null +++ b/frontend/web-management-vue3/src/api/sensitiveWord.ts @@ -0,0 +1,26 @@ +// @/api/sensitiveWord.ts +import request from '@/utils/request' // 用你之前封装的axios实例 + +// 定义敏感词类型(和后端返回结构一致) +export interface SensitiveWord { + id: number; + wordContent: string; + isEnabled: number; +} + +// 1. 获取敏感词列表(后端接口:GET /sensitiveWord/list) +export const getSensitiveWordList = () => { + return request.get('sensitiveWord/list') +} + +// // 2. 保存敏感词列表(后端接口:POST /sensitiveWord/save,传整个列表) +// export const saveSensitiveWordList = (data: SensitiveWord[]) => { +// return request.post('/sensitiveWord/save', data) +// } +export const saveSensitiveWordChange = (data: { + add: SensitiveWord[] + update: SensitiveWord[] + delete: number[] +}) => { + return request.post('/sensitiveWord/batch', data) // 后端新接口地址 +} \ No newline at end of file diff --git a/frontend/web-management-vue3/src/router/index.ts b/frontend/web-management-vue3/src/router/index.ts index 35b8e3a..8890e1f 100644 --- a/frontend/web-management-vue3/src/router/index.ts +++ b/frontend/web-management-vue3/src/router/index.ts @@ -1,51 +1,121 @@ -import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' // 1. 导入 TS 类型 +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' // 导入布局组件 import LayoutContainer from '@/views/Layout/index.vue' -// 优化:改为懒加载(减小初始打包体积,符合最佳实践) -const TaskFormulation = () => import('@/views/Task/index.vue') -const DataCollection = () => import('@/views/Data/index.vue') -const QualityInspectionResult = () => import('@/views/Quality/index.vue') +import TaskAdd from '@/views/Task/TaskAdd.vue' +// 懒加载 + 增加加载失败兜底(避免异步加载导致的渲染错位) +const TaskFormulation = () => import(/* webpackChunkName: "task" */ '@/views/Task/index.vue') +const DataCollection = () => import(/* webpackChunkName: "data" */ '@/views/Data/index.vue') +const QualityInspectionResult = () => import(/* webpackChunkName: "quality" */ '@/views/Quality/index.vue') +const QualityCheckDetail = () => import(/* webpackChunkName: "quality-detail" */ '@/views/Quality/QualityCheckDetail.vue') -// 2. 显式标注 routes 类型为 RouteRecordRaw[] +// 显式标注 routes 类型 const routes: RouteRecordRaw[] = [ + // 根路由:严格重定向 + 明确布局 { path: '/', - redirect: '/task-formulation', // 3. 修正重定向路径(小写 + 有效路径) + redirect: { name: 'TaskFormulation' }, // 用name跳转(避免path拼写错误) component: LayoutContainer, children: [ + // 任务制定:增加alias + 明确meta标识 { - path: 'task-formulation', // 和侧边栏菜单 index="/task-formulation" 完全匹配 + path: 'task-formulation', name: 'TaskFormulation', + alias: ['/task'], // 可选:增加别名,避免路径输入错误 component: TaskFormulation, - meta: { title: '任务制定' } + meta: { + title: '任务制定', + key: 'task-formulation', // 唯一key,用于侧边栏匹配 + keepAlive: false // 关闭缓存,避免组件复用导致的错位 + } }, + // 新增任务:增加父路由关联 { - path: 'data-collection', // 和侧边栏菜单 index="/data-collection" 匹配 + path: 'task-formulation/add', + name: 'TaskAdd', + component: TaskAdd, + meta: { + title: '新增任务', + key: 'task-add', + keepAlive: false + } + }, + // 采集任务:唯一key + { + path: 'data-collection', name: 'DataCollection', component: DataCollection, - meta: { title: '采集任务' } + meta: { + title: '采集任务', + key: 'data-collection', + keepAlive: false + } }, + // 质检结果库:唯一key { - path: 'quality-inspection-result', // 和侧边栏菜单 index="/quality-inspection-result" 匹配 + path: 'quality-inspection-result', name: 'QualityInspectionResult', component: QualityInspectionResult, - meta: { title: '质检结果库' } + meta: { + title: '质检结果库', + key: 'quality-inspection-result', + keepAlive: false + } + }, + // 质检详情页:严格参数匹配 + 禁止缓存 + { + path: 'quality-inspection-result/detail/:id(\\d+)', // 限制id只能是数字,避免非法参数 + name: 'QualityCheckDetail', + component: QualityCheckDetail, + meta: { + title: '质检详情页', + key: 'quality-check-detail', + keepAlive: false + }, + props: true, + // 可选:路由独享守卫,确保参数合法 + beforeEnter: (to) => { + const id = Number(to.params.id); + if (isNaN(id) || id <= 0) { + return { name: 'QualityInspectionResult' }; // 参数非法跳回列表 + } + } } ] - } + }, + ] +// 初始化路由:修复BASE_URL + 增加滚动行为 const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes + history: createWebHistory(import.meta.env.BASE_URL || '/'), // 兜底BASE_URL + routes, + // 修复刷新/跳转时的滚动位置,避免历史记录异常 + scrollBehavior: (to, from, savedPosition) => { + if (savedPosition) { + return savedPosition; + } else { + return { top: 0 }; + } + } }) -// 可选优化:路由守卫 - 自动设置页面标题 +// 路由守卫:增加日志 + 严格匹配meta.title router.beforeEach((to, from, next) => { + // 调试日志:定位路由跳转异常 + console.log('路由跳转:', { from: from.fullPath, to: to.fullPath, name: to.name }); + + // 严格设置标题 if (to.meta.title) { - document.title = `${to.meta.title} - 数据采集系统` + document.title = `${to.meta.title} - 数据采集系统`; + } + + // 禁止从详情页刷新后跳转到错误模块 + if (from.name === 'QualityCheckDetail' && to.name === 'NotFound') { + next({ name: 'QualityInspectionResult' }); + return; } - next() + + next(); }) export default router \ No newline at end of file diff --git a/frontend/web-management-vue3/src/utils/request.ts b/frontend/web-management-vue3/src/utils/request.ts new file mode 100644 index 0000000..dba77f5 --- /dev/null +++ b/frontend/web-management-vue3/src/utils/request.ts @@ -0,0 +1,76 @@ +// src/utils/request.ts +import axios from 'axios' +// 关键修改:类型用 import type 导入(适配 verbatimModuleSyntax) +import type { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios' +import { ElMessage } from 'element-plus' + +// 创建axios实例 +const request = axios.create({ + baseURL: 'http://10.136.120.22:8080/', + timeout: 10000, + headers: { + 'Content-Type': 'application/json;charset=utf-8' + } +}) + +// 请求拦截器:注意参数类型标注不变,只是导入方式改了 +request.interceptors.request.use( + (config: AxiosRequestConfig) => { + const token = localStorage.getItem('token') + if (token && config.headers) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + (error: AxiosError) => { + ElMessage.error('请求发送失败,请检查网络') + return Promise.reject(error) + } +) + +// 响应拦截器 +request.interceptors.response.use( + (response: AxiosResponse) => { + const res = response.data + // 适配后端返回格式:code是字符串"200",数据在content里 + if (typeof res === 'object' && res.code) { + // 判断code是否为"200"(后端返回的是字符串) + if (res.code !== "200") { + ElMessage.error(res.msg || '请求失败') + return Promise.reject(res) + } + // 返回content字段(后端数据存在这里) + return res.content + } + // 兼容其他格式(若有的话) + return res + }, + (error: AxiosError) => { + const status = error.response?.status + switch (status) { + case 401: + ElMessage.error('登录已过期,请重新登录') + break + case 403: + ElMessage.error('暂无权限访问该接口') + break + case 500: + ElMessage.error('服务器内部错误,请稍后重试') + break + default: + console.error('请求错误详情:', error) + ElMessage.error(error.message || '请求出错') + } + return Promise.reject(error) + } +) + +// 导出类型:同样用 export type(适配规则) +export type RequestConfig = AxiosRequestConfig +export type ResponseData = { + code: number + data: T + msg: string +} + +export default request \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Layout/index.vue b/frontend/web-management-vue3/src/views/Layout/index.vue index a2c3d84..30e636e 100644 --- a/frontend/web-management-vue3/src/views/Layout/index.vue +++ b/frontend/web-management-vue3/src/views/Layout/index.vue @@ -9,14 +9,15 @@ - + 任务制定 @@ -43,18 +44,46 @@ - + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue b/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue new file mode 100644 index 0000000..bbcdcc1 --- /dev/null +++ b/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue @@ -0,0 +1,366 @@ + + + + + + + + + + 数据补充采集任务:{{ detailData?.taskName || '无' }} + + 上报日期:{{ detailData?.reportDate || '无' }} + 上报人:{{ detailData?.reporter || '无' }} + + + 返回 + + + + + 质检结果 + + 质检问题项:{{ detailData?.problemCount || 0 }}项 + + + + + + 质检数据查看 + 质检后,有问题的数据项进行红色高亮 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Quality/index.vue b/frontend/web-management-vue3/src/views/Quality/index.vue index cf7c2a9..0bec991 100644 --- a/frontend/web-management-vue3/src/views/Quality/index.vue +++ b/frontend/web-management-vue3/src/views/Quality/index.vue @@ -1,19 +1,298 @@ - - 质检结果库 - 这里是质检结果库的核心功能区,可查看质检记录、统计分析、导出报告等。 + + + + + + + + + + + + + + + + + + + + + + + + + 查询 + 重置 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 详情 + + + + + + + + + - \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Task/TaskAdd.vue b/frontend/web-management-vue3/src/views/Task/TaskAdd.vue new file mode 100644 index 0000000..40a6d87 --- /dev/null +++ b/frontend/web-management-vue3/src/views/Task/TaskAdd.vue @@ -0,0 +1,908 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 是否启动敏感词进行检测 + + + + + + + + + + + + + 取消 + + 下一步 + + + + + + + + + + + + + + + + + + + + + + + 数据配置 + + + + + + + + + + + + + + + + + + + + + + + + + 添加字段 + 删除选中字段 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 质检校验 + 新增质检 + + + + + + + + + 编辑 + 删除 + + + + + + + + + + + + + + + + + + + + + + + + + + + 添加条件 + + + + + ( + + + + + + + + + + + + + + + + ) + + + + + + {{ item.isInBracket ? '移除括号' : '+ 括号' }} + + + + - + + + + + + + + + + + + + 取消 + 确定 + + + + + + + + 上一步 + + 提交 + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Task/index.vue b/frontend/web-management-vue3/src/views/Task/index.vue index abdd4af..47e66eb 100644 --- a/frontend/web-management-vue3/src/views/Task/index.vue +++ b/frontend/web-management-vue3/src/views/Task/index.vue @@ -1,19 +1,442 @@ - - 任务制定 - 这里是任务制定的核心功能区,可添加任务配置、规则设置等内容。 - + + + + + 新增 + 删除 + 敏感词设置 + + + + + + + + + + + + + + + + + + + + + + + + + + 查询 + 重置 + + + + + + + + + + + + + + + + + + + + + + + + + 编辑 + 详情 + 删除 + + + + + + + + + + + + + + {{ detailTask?.sensitiveCheck ? '开启' : '关闭' }} + + + + + {{ detailTask?.selectedTable === 'table1' ? '数据表1' : '数据表2' }} + + + + + + + + + {{ col }} + + + - + + + + + + + {{ rule }} + + + - + + + + 关闭 + + + + + + + + 新增 + 敏感词检测后,将直接使用符号替换 + + + + + handleWordChange(scope.row)" /> + + + + + handleWordChange(scope.row)" + /> + + + + + + 删除 + + + + + pageSize.value = val" + @current-change="(val) => currentPage.value = val" :current-page="currentPage" + :page-sizes="[10, 20, 30]" :page-size="pageSize" layout="prev, pager, next, jumper, ->, 10条/页" + :total="total" style="text-align: right;" /> + + + 关闭 + 确定 + + + + - \ No newline at end of file -- Gitee From e15462f85b92b5896afb7319fa5329162a6aab5b Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Fri, 9 Jan 2026 15:43:24 +0800 Subject: [PATCH 07/44] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=BC=80=E5=8F=91=EF=BC=8C=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E3=80=81=E6=A0=B9=E6=8D=AE=E4=BB=BB=E5=8A=A1id=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/controller/TaskController.java | 73 ++++++++++++ .../unionbigdata/teaching/entity/Task.java | 48 ++++++++ .../teaching/mapper/TaskMapper.java | 7 ++ .../teaching/sevice/ITaskService.java | 30 +++++ .../teaching/sevice/impl/TaskServiceImpl.java | 111 ++++++++++++++++++ .../com/unionbigdata/teaching/vo/TaskVO.java | 30 +++++ 6 files changed, 299 insertions(+) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/Task.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/TaskVO.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java new file mode 100644 index 0000000..453dc2c --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java @@ -0,0 +1,73 @@ +package com.unionbigdata.teaching.controller; + +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.sevice.ITaskService; +import com.unionbigdata.teaching.vo.TaskVO; +import io.swagger.models.auth.In; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/task") +public class TaskController { + + @Autowired + private ITaskService taskService; + +/** + * 获取任务列表的方法 + * 该方法用于从服务层获取所有的任务信息,并将其转换为视图对象(TaskVO)返回 + * + * @return List 返回任务视图对象的列表,包含了所有任务的信息 + */ + @GetMapping + public Result> getTaskList(){ + // 调用taskService的getAllTask方法获取所有任务数据 + return Result.ok(taskService.getAllTask()); + } + + /** + * 用@RequestParam接收查询参数 + * @param timeType 前端下拉框的“发布时间”(可选) + * @param startDate 开始日期(可选,需指定格式) + * @param endDate 结束日期(可选,需指定格式) + * @param taskName 任务名称(可选) + */ + @GetMapping("/list") + public List getTaskList( + @RequestParam(value = "timeType", required = false) String timeType, + @RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, + @RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, + @RequestParam(value = "taskName", required = false) String taskName + ) { + // 将单个参数传给Service层处理 + return taskService.queryTaskList(timeType, startDate, endDate, taskName); + } + +/** + * 根据任务ID获取任务信息的接口方法 + * @param id 任务ID,通过路径变量传递 + * @return 返回一个Result对象,包含任务信息的Map集合 + */ + @GetMapping("/{id}") + public Result> getTaskById(@PathVariable Integer id){ + // 调用taskService的getTaskById方法获取任务信息,并封装到Result对象中返回 + return Result.ok(taskService.getTaskById(id)); + } + +/** + * 添加任务接口 + * @param taskVO 任务视图对象,包含任务的详细信息 + * @return 返回操作结果,包含操作状态和相关信息 + */ +// @PostMapping +// public Result addTask(@RequestBody TaskVO taskVO){ +// +// // 方法体为空,需要实现具体逻辑 +// } +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java new file mode 100644 index 0000000..d5266c9 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java @@ -0,0 +1,48 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +@TableName("task") +@Data +public class Task { + @TableId(value = "id",type = IdType.AUTO) + private Integer id; + + //任务名称 + private String taskName; + + //发布时间 + private LocalDateTime publishTime; + + //创建时间 + private LocalDateTime createTime; + + //更新时间 + private LocalDateTime updateTime; + + //状态 + private String status; + + //创建人id + private Long creatorId; + + //处理人id + private Long handlerId; + + //theme_id + private Integer themeId; + + //任务描述 + private String taskDescription; + + //是否开启敏感词检测 + private Integer isSensitiveDetection; + + //版本号 + private String version; +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java new file mode 100644 index 0000000..7ace959 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java @@ -0,0 +1,7 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.Task; + +public interface TaskMapper extends BaseMapper { +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java new file mode 100644 index 0000000..95a7ba1 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java @@ -0,0 +1,30 @@ +package com.unionbigdata.teaching.sevice; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.unionbigdata.teaching.entity.Task; +import com.unionbigdata.teaching.vo.TaskVO; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +public interface ITaskService extends IService { +/** + * 获取所有任务的方法 + * + * @return 返回一个TaskVO类型的列表,包含所有任务的信息 + */ + List getAllTask(); + + Map getTaskById(Integer id); + +/** + * 查询任务列表的方法 + * @param timeType 时间类型,用于指定查询的时间范围类型 + * @param startDate 开始日期,查询范围的起始时间 + * @param endDate 结束日期,查询范围的结束时间 + * @param taskName 任务名称,用于筛选特定名称的任务 + * @return 返回任务列表,包含符合条件的TaskVO对象集合 + */ + List queryTaskList(String timeType, LocalDate startDate, LocalDate endDate, String taskName); +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java new file mode 100644 index 0000000..ee773f0 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java @@ -0,0 +1,111 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.unionbigdata.teaching.entity.DataSource; +import com.unionbigdata.teaching.entity.Task; +import com.unionbigdata.teaching.mapper.DataSourceMapper; +import com.unionbigdata.teaching.mapper.TaskMapper; +import com.unionbigdata.teaching.sevice.ITaskService; +import com.unionbigdata.teaching.vo.DataSourceVO; +import com.unionbigdata.teaching.vo.TaskVO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class TaskServiceImpl extends ServiceImpl implements ITaskService { + + @Resource + private TaskMapper taskMapper; + + @Resource + private DataSourceMapper dataSourceMapper; + + @Override + public List getAllTask() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByDesc("create_time"); + List taskList = taskMapper.selectList(queryWrapper); + return taskList.stream().map(this::convertTaskVO).toList(); + } + + @Override + public Map getTaskById(Integer id) { + Map dynamicJson = new HashMap<>(); + Task task = taskMapper.selectById(id); + + //获取全部的数据源(可优化为查询特定数据源) + List dataSourceList = dataSourceMapper.selectList(null); + List dataSourceVOList = dataSourceList.stream() + .map(this::convertDataSourceVO) + .collect(Collectors.toList()); + + if (!ObjectUtils.isEmpty(task)) { + dynamicJson.put("id",task.getId()); + dynamicJson.put("taskName",task.getTaskName()); + dynamicJson.put("version",task.getVersion());//任务版本 + dynamicJson.put("taskDescription",task.getTaskDescription()); + dynamicJson.put("isSensitiveDetection",task.getIsSensitiveDetection()); + dynamicJson.put("dataSourceList",dataSourceVOList);//任务的数据源 + return dynamicJson; + } + return null; + } + + @Override + public List queryTaskList(String timeType, LocalDate startDate, LocalDate endDate, String taskName) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 1. 任务名称:仅当非空时添加模糊查询 + if (taskName != null && !taskName.trim().isEmpty()) { + queryWrapper.like("task_name", taskName.trim()); + } + + // 2. 时间范围:仅当startDate/endDate非空时添加区间条件 + // (timeType若仅用于区分时间字段,无值时不处理) + if (startDate != null) { + queryWrapper.ge(timeType, startDate); + } + if (endDate != null) { + queryWrapper.le(timeType, endDate); + } + + // 关键:若所有参数为空,QueryWrapper无任何条件 → 查询全部任务 + + //按创建时间降序 + queryWrapper.orderByDesc("create_time"); + List taskList = taskMapper.selectList(queryWrapper); + return taskList.stream() + .map(this::convertTaskVO) + .toList(); // Java16+简洁写法 + } + + private TaskVO convertTaskVO(Task task) { + TaskVO taskVO = new TaskVO(); + if (!ObjectUtils.isEmpty(task)) { + taskVO.setId(task.getId()); + taskVO.setTaskName(task.getTaskName()); + taskVO.setUpdateTime(task.getUpdateTime()); + taskVO.setUpdateTime(task.getUpdateTime()); + taskVO.setStatus(task.getStatus()); + taskVO.setTaskDescription(task.getTaskDescription()); + } + return taskVO; + } + + private DataSourceVO convertDataSourceVO(DataSource dataSource) { + DataSourceVO dataSourceVO = new DataSourceVO(); + if (!ObjectUtils.isEmpty(dataSource)) { + dataSourceVO.setId(dataSource.getId()); + dataSourceVO.setDataSourceName(dataSource.getDataSourceName()); + } + return dataSourceVO; + } +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/TaskVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/TaskVO.java new file mode 100644 index 0000000..5c87c37 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/TaskVO.java @@ -0,0 +1,30 @@ +package com.unionbigdata.teaching.vo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "任务VO") +@Data +public class TaskVO { + @Schema(description = "任务id") + private Integer id; + + @Schema(description = "任务名称") + private String taskName; + + @Schema(description = "发布时间") + private LocalDateTime publishTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "状态") + private String status; + + @Schema(description = "任务描述") + private String taskDescription; +} -- Gitee From 726c34a2634e6c7b2253a55da719af2897d5a4c9 Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Fri, 9 Jan 2026 15:44:47 +0800 Subject: [PATCH 08/44] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BC=80=E5=8F=91=EF=BC=8C=E5=BB=BA=E7=AB=8B=E4=BA=86?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90entity=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DataSourceController.java | 17 +++++++++++++++++ .../teaching/entity/DataSource.java | 19 +++++++++++++++++++ .../teaching/mapper/DataSourceMapper.java | 7 +++++++ .../teaching/vo/DataSourceVO.java | 17 +++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/DataSourceMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/DataSourceVO.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java new file mode 100644 index 0000000..65b19a6 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java @@ -0,0 +1,17 @@ +package com.unionbigdata.teaching.controller; + +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.entity.DataSource; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/datasource") +public class DataSourceController { + @RequestMapping("/list") + public Result> list(){ + return null; + } +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java b/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java new file mode 100644 index 0000000..152c85d --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java @@ -0,0 +1,19 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@TableName("data_source") +@Data +public class DataSource { + @TableId(value = "id",type = IdType.AUTO) + private Integer id; + + //数据源名称 + private String dataSourceName; + + //任务id + private String taskId; +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/DataSourceMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/DataSourceMapper.java new file mode 100644 index 0000000..03758d4 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/DataSourceMapper.java @@ -0,0 +1,7 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.DataSource; + +public interface DataSourceMapper extends BaseMapper { +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/DataSourceVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/DataSourceVO.java new file mode 100644 index 0000000..3d4b028 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/DataSourceVO.java @@ -0,0 +1,17 @@ +package com.unionbigdata.teaching.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class DataSourceVO { + @Schema(description = "数据源id") + private Integer id; + + @Schema(description = "数据源名称") + private String dataSourceName; + + //暂时没用? +// @Schema(description = "任务id") +// private String taskId; +} -- Gitee From b332a4c264208e742047265f56d769db3197a568 Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Fri, 9 Jan 2026 15:55:53 +0800 Subject: [PATCH 09/44] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86Task=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1entity=E7=B1=BB=E7=9A=84=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/unionbigdata/teaching/entity/Task.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java index d5266c9..9dd1f26 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java @@ -45,4 +45,10 @@ public class Task { //版本号 private String version; + + //数据源id,新建任务后,根据数据源id可以找到对应的数据库,进而找到对应的表 + private Integer dataSourceId; + + //数据表id,新建任务后,根据数据表id可以在对应数据源中找到对应的表 + private Integer tableId; } -- Gitee From 90d677e0eda8215bc23c844bf4593a8837b37ef8 Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Fri, 9 Jan 2026 16:24:32 +0800 Subject: [PATCH 10/44] =?UTF-8?q?=E5=BC=80=E5=8F=91=E4=BA=86=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=85=A8=E9=83=A8=E6=95=B0=E6=8D=AE=E6=BA=90=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=92=8C=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DataSourceController.java | 17 +++++++++++++++-- .../teaching/controller/TaskController.java | 15 ++++----------- .../teaching/entity/DataSource.java | 3 --- .../teaching/sevice/IDataSourceService.java | 7 +++++++ .../sevice/impl/DataSourceServiceImpl.java | 11 +++++++++++ 5 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/IDataSourceService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataSourceServiceImpl.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java index 65b19a6..c811ab0 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/DataSourceController.java @@ -2,6 +2,9 @@ package com.unionbigdata.teaching.controller; import com.unionbigdata.teaching.common.Result; import com.unionbigdata.teaching.entity.DataSource; +import com.unionbigdata.teaching.sevice.impl.DataSourceServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -10,8 +13,18 @@ import java.util.List; @RestController @RequestMapping("/datasource") public class DataSourceController { - @RequestMapping("/list") + + @Autowired + private DataSourceServiceImpl dataSourceService; + +/** + * 获取数据源列表的请求处理方法 + * 该方法映射到 "/list" 路径,用于处理获取数据源列表的请求 + * + * @return 返回一个包含数据源列表的Result对象,目前返回null + */ + @GetMapping("/list") public Result> list(){ - return null; + return Result.ok(dataSourceService.list()); } } diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java index 453dc2c..05c572b 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java @@ -3,7 +3,6 @@ package com.unionbigdata.teaching.controller; import com.unionbigdata.teaching.common.Result; import com.unionbigdata.teaching.sevice.ITaskService; import com.unionbigdata.teaching.vo.TaskVO; -import io.swagger.models.auth.In; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; @@ -60,14 +59,8 @@ public class TaskController { return Result.ok(taskService.getTaskById(id)); } -/** - * 添加任务接口 - * @param taskVO 任务视图对象,包含任务的详细信息 - * @return 返回操作结果,包含操作状态和相关信息 - */ -// @PostMapping -// public Result addTask(@RequestBody TaskVO taskVO){ -// -// // 方法体为空,需要实现具体逻辑 -// } + @PostMapping("/del/batch")//批量删除 + public Result deleteBatch(@RequestBody List ids) { + return Result.ok(taskService.removeBatchByIds(ids)); + } } diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java b/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java index 152c85d..f4ff2b8 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/DataSource.java @@ -13,7 +13,4 @@ public class DataSource { //数据源名称 private String dataSourceName; - - //任务id - private String taskId; } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataSourceService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataSourceService.java new file mode 100644 index 0000000..01e0eb8 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataSourceService.java @@ -0,0 +1,7 @@ +package com.unionbigdata.teaching.sevice; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.unionbigdata.teaching.entity.DataSource; + +public interface IDataSourceService extends IService { +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataSourceServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataSourceServiceImpl.java new file mode 100644 index 0000000..890c6d8 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataSourceServiceImpl.java @@ -0,0 +1,11 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.unionbigdata.teaching.entity.DataSource; +import com.unionbigdata.teaching.mapper.DataSourceMapper; +import com.unionbigdata.teaching.sevice.IDataSourceService; +import org.springframework.stereotype.Service; + +@Service +public class DataSourceServiceImpl extends ServiceImpl implements IDataSourceService{ +} -- Gitee From 9916bebabecf9eea57ab585c9f97329c3072da72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AE=B6=E8=BE=89?= <3236488932@qq.com> Date: Fri, 9 Jan 2026 12:04:43 +0000 Subject: [PATCH 11/44] update backend/src/main/resources/application.yml. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 黄家辉 <3236488932@qq.com> --- backend/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index bbf33db..7af1c4b 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -1,6 +1,6 @@ server: port: 8080 - address: 0.0.0.0 # 关键:监听所有网络接口 + address: 0.0.0.0 # 关键:监听所有网络接口111 spring: application: -- Gitee From 9da6e9aa6d4a3bd6807e8a61cc6c1ba2065d2d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AE=B6=E8=BE=89?= <3236488932@qq.com> Date: Fri, 9 Jan 2026 12:05:23 +0000 Subject: [PATCH 12/44] update backend/src/main/resources/application.yml. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 黄家辉 <3236488932@qq.com> --- backend/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 7af1c4b..bbf33db 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -1,6 +1,6 @@ server: port: 8080 - address: 0.0.0.0 # 关键:监听所有网络接口111 + address: 0.0.0.0 # 关键:监听所有网络接口 spring: application: -- Gitee From 20d49d7864e121287a8128f2d9aa100451ebb169 Mon Sep 17 00:00:00 2001 From: f10s <2010310561@qq.com> Date: Fri, 9 Jan 2026 20:37:45 +0800 Subject: [PATCH 13/44] =?UTF-8?q?feat:Data=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-management-vue3/package-lock.json | 25 +- .../src/views/Data/index.vue | 717 ++++++++++++++- .../src/views/Layout/index.vue | 835 +++++++++++++++--- 3 files changed, 1439 insertions(+), 138 deletions(-) diff --git a/frontend/web-management-vue3/package-lock.json b/frontend/web-management-vue3/package-lock.json index 28a83a7..793f3d1 100644 --- a/frontend/web-management-vue3/package-lock.json +++ b/frontend/web-management-vue3/package-lock.json @@ -137,6 +137,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -649,6 +650,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -692,6 +694,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -1953,6 +1956,7 @@ "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/lodash": "*" } @@ -2025,6 +2029,7 @@ "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.50.1", "@typescript-eslint/types": "8.50.1", @@ -2918,6 +2923,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3134,6 +3140,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3721,6 +3728,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3781,6 +3789,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -3838,6 +3847,7 @@ "integrity": "sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "natural-compare": "^1.4.0", @@ -4641,6 +4651,7 @@ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -5149,13 +5160,15 @@ "version": "4.17.21", "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash-es": { "version": "4.17.22", "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.22.tgz", "integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash-unified": { "version": "1.0.3", @@ -5833,6 +5846,7 @@ "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -6040,6 +6054,7 @@ "integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -6404,6 +6419,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6530,6 +6546,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6654,6 +6671,7 @@ "integrity": "sha512-5hI5NCJwKBGtzWtdKB3c2fOEpI77Iaa0z4mSzZPU1cJ/OqrGbFafm90edVCd7T9Snz+Sh09TMAv4EQqyVLzuEg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/runtime": "0.101.0", "fdir": "^6.5.0", @@ -6945,6 +6963,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6958,6 +6977,7 @@ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", @@ -7055,6 +7075,7 @@ "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.26.tgz", "integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/compiler-sfc": "3.5.26", diff --git a/frontend/web-management-vue3/src/views/Data/index.vue b/frontend/web-management-vue3/src/views/Data/index.vue index ec2814b..da2909e 100644 --- a/frontend/web-management-vue3/src/views/Data/index.vue +++ b/frontend/web-management-vue3/src/views/Data/index.vue @@ -1,19 +1,722 @@ - - 采集任务 - 这里是采集任务的核心功能区,可查看任务列表、执行状态、手动触发采集等。 + + + + 补充采集任务列表 + + + + + + {{ task.name }} + + + + + + + 补充采集执行 + + + + + + + + + 任务名称: + {{ currentTask?.name }} + + + 任务创建时间: + {{ currentTask?.createTime }} + + + + 任务描述: + {{ currentTask?.description }} + + + + + + + {{ editingIndex > -1 ? '编辑数据' : '数据填报' }} + 正在编辑第 {{ editingIndex + 1 }} 行 + + + + + + + + + + 请先选择任务以加载表单配置 + + + + 取消编辑 + + {{ editingIndex > -1 ? '保存修改' : '添加' }} + + + + + + + + 填报数据预览 + + 确认上报 + + + + + + + + + + + 编辑 + 删除 + + + + + + + + + + + + + + 任务名称: + {{ currentTask?.name }} + + + 任务创建时间: + {{ currentTask?.createTime }} + + + + 任务描述: + {{ currentTask?.description }} + + + + + + 上传文件: + + 点击上传文件 (Excel) + + + 请下载 标准模板 进行填写,否则可能导致解析失败。 + + + + + + + + + 上传数据预览区 + + 确认上报 + + + + + + + + + + + {{ scope.row[col.prop] }} + + + + + + + 保存 + 取消 + + + 编辑 + 删除 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Layout/index.vue b/frontend/web-management-vue3/src/views/Layout/index.vue index 30e636e..da2909e 100644 --- a/frontend/web-management-vue3/src/views/Layout/index.vue +++ b/frontend/web-management-vue3/src/views/Layout/index.vue @@ -1,145 +1,722 @@ - - - - 数据采集系统 - - - - - - + + + 补充采集任务列表 + + + + - - - - 任务制定 - - - - - 采集任务 - - - - - 质检结果库 - - - - - - - - - - + + {{ task.name }} + + + + + + + 补充采集执行 + + + + + + + + + 任务名称: + {{ currentTask?.name }} + + + 任务创建时间: + {{ currentTask?.createTime }} + + + + 任务描述: + {{ currentTask?.description }} + + + + + + + {{ editingIndex > -1 ? '编辑数据' : '数据填报' }} + 正在编辑第 {{ editingIndex + 1 }} 行 + + + + + + + + + + 请先选择任务以加载表单配置 + + + + 取消编辑 + + {{ editingIndex > -1 ? '保存修改' : '添加' }} + + + + + + + + 填报数据预览 + + 确认上报 + + + + + + + + + + + 编辑 + 删除 + + + + + + + + + + + + + + 任务名称: + {{ currentTask?.name }} + + + 任务创建时间: + {{ currentTask?.createTime }} + + + + 任务描述: + {{ currentTask?.description }} + + + + + + 上传文件: + + 点击上传文件 (Excel) + + + 请下载 标准模板 进行填写,否则可能导致解析失败。 + + + + + + + + + 上传数据预览区 + + 确认上报 + + + + + + + + + + + {{ scope.row[col.prop] }} + + + + + + + 保存 + 取消 + + + 编辑 + 删除 + + + + + + + + + + + + + + + + + + + + +} - \ No newline at end of file -- Gitee From 6858e8ec64e1cdcb3b8e96b954713484a0dc8c09 Mon Sep 17 00:00:00 2001 From: lxm87954 <14417944+lxm87954@user.noreply.gitee.com> Date: Sat, 10 Jan 2026 09:02:05 +0800 Subject: [PATCH 14/44] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=88=E6=AD=A3=E7=A1=AE=E7=89=88=E6=9C=AC?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/Layout/index.vue | 835 +++--------------- .../src/views/Quality/QualityCheckDetail.vue | 4 +- .../src/views/Quality/index.vue | 18 +- .../src/views/Task/TaskAdd.vue | 1 + .../src/views/Task/index.vue | 175 ++-- 5 files changed, 200 insertions(+), 833 deletions(-) diff --git a/frontend/web-management-vue3/src/views/Layout/index.vue b/frontend/web-management-vue3/src/views/Layout/index.vue index da2909e..30e636e 100644 --- a/frontend/web-management-vue3/src/views/Layout/index.vue +++ b/frontend/web-management-vue3/src/views/Layout/index.vue @@ -1,722 +1,145 @@ - - - - 补充采集任务列表 - - - - + + + 数据采集系统 + + + + + + - - {{ task.name }} - - - - - - - 补充采集执行 - - - - - - - - - 任务名称: - {{ currentTask?.name }} - - - 任务创建时间: - {{ currentTask?.createTime }} - - - - 任务描述: - {{ currentTask?.description }} - - - - - - - {{ editingIndex > -1 ? '编辑数据' : '数据填报' }} - 正在编辑第 {{ editingIndex + 1 }} 行 - - - - - - - - - - 请先选择任务以加载表单配置 - - - - 取消编辑 - - {{ editingIndex > -1 ? '保存修改' : '添加' }} - - - - - - - - 填报数据预览 - - 确认上报 - - - - - - - - - - - 编辑 - 删除 - - - - - - - - - - - - - - 任务名称: - {{ currentTask?.name }} - - - 任务创建时间: - {{ currentTask?.createTime }} - - - - 任务描述: - {{ currentTask?.description }} - - - - - - 上传文件: - - 点击上传文件 (Excel) - - - 请下载 标准模板 进行填写,否则可能导致解析失败。 - - - - - - - - - 上传数据预览区 - - 确认上报 - - - - - - - - - - - {{ scope.row[col.prop] }} - - - - - - - 保存 - 取消 - - - 编辑 - 删除 - - - - - - - - - - - - - - - - - - - - + + + + 任务制定 + + + + + 采集任务 + + + + + 质检结果库 + + + + + + + + + + - const jsonData = XLSX.utils.sheet_to_json(worksheet) - - if (jsonData.length === 0) { - ElMessage.warning('文件内容为空') - clearBatchData() - return - } + \ No newline at end of file diff --git a/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue b/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue index bbcdcc1..cdca67d 100644 --- a/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue +++ b/frontend/web-management-vue3/src/views/Quality/QualityCheckDetail.vue @@ -208,8 +208,8 @@ const setCellStyle = ({ row, column }: { row: CheckDataItem; column: any }) => { return { height: '48px', textAlign: 'center', - backgroundColor: '#fef0f0', - color: '#f56c6c', + backgroundColor: '#e95f5f', + color: '#fff', fontWeight: 500, border: '1px solid #fde2e2' }; diff --git a/frontend/web-management-vue3/src/views/Quality/index.vue b/frontend/web-management-vue3/src/views/Quality/index.vue index 0bec991..07ab53b 100644 --- a/frontend/web-management-vue3/src/views/Quality/index.vue +++ b/frontend/web-management-vue3/src/views/Quality/index.vue @@ -4,7 +4,7 @@ - + @@ -126,8 +126,8 @@ const originResultList = ref([ tableName: '数据表1', collectedColumns: ['ID', 'username', 'password'], checkRules: ['字段非空校验', '格式合规校验'], - updateTime: '2024/8/6 12:01:30', - publishTime: '2024/8/6 12:01:30' + updateTime: '2026/01/01 12:01:30', + publishTime: '2026/01/01 12:01:30' }, { id: 2, @@ -139,8 +139,8 @@ const originResultList = ref([ tableName: '数据表2', collectedColumns: ['orderId', 'amount'], checkRules: ['数值范围校验'], - updateTime: '2024/8/6 12:01:30', - publishTime: '2024/8/6 12:01:30' + updateTime: '2026/01/05 12:01:30', + publishTime: '2026/01/05 12:01:30' }, { id: 3, @@ -152,8 +152,8 @@ const originResultList = ref([ tableName: '数据表1', collectedColumns: ['goodsId', 'price'], checkRules: ['字段非空校验'], - updateTime: '2024/8/6 12:01:30', - publishTime: '2024/8/6 12:01:30' + updateTime: '2026/01/10 12:01:30', + publishTime: '2026/01/10 12:01:30' }, { id: 4, @@ -165,8 +165,8 @@ const originResultList = ref([ tableName: '数据表2', collectedColumns: ['logisticsId', 'status'], checkRules: ['状态枚举校验'], - updateTime: '2024/8/6 12:01:30', - publishTime: '2024/8/6 12:01:30' + updateTime: '2026/01/15 12:01:30', + publishTime: '2026/01/15 12:01:30' } ]) const resultList = ref([...originResultList.value]) // 筛选后的数据 diff --git a/frontend/web-management-vue3/src/views/Task/TaskAdd.vue b/frontend/web-management-vue3/src/views/Task/TaskAdd.vue index 40a6d87..1e5226d 100644 --- a/frontend/web-management-vue3/src/views/Task/TaskAdd.vue +++ b/frontend/web-management-vue3/src/views/Task/TaskAdd.vue @@ -792,6 +792,7 @@ const handleSubmit = async () => { await editTask(currentTaskId.value, submitData) ElMessage.success('编辑任务成功!') } else { + console.log("数据集合:",submitData) await addTask(submitData) ElMessage.success('新增任务成功!') } diff --git a/frontend/web-management-vue3/src/views/Task/index.vue b/frontend/web-management-vue3/src/views/Task/index.vue index 47e66eb..72c96e0 100644 --- a/frontend/web-management-vue3/src/views/Task/index.vue +++ b/frontend/web-management-vue3/src/views/Task/index.vue @@ -1,63 +1,40 @@ - - + 新增 删除 敏感词设置 - - - - - - - - - 查询 重置 - - - - - - - - - - - - - 编辑 @@ -67,27 +44,49 @@ - + - - - - + + + {{ detailTask?.taskName ?? '-' }} + + + {{ detailTask?.taskVersion ?? '-' }} + + + {{ detailTask?.taskDesc ?? '-' }} + + - - {{ detailTask?.sensitiveCheck ? '开启' : '关闭' }} + + {{ detailTask?.sensitiveCheck === 1 || detailTask?.sensitiveCheck === true ? '开启' : '关闭' }} - + + + + {{ detailTask.dataSource === 'db_connect_a' ? '数据库连接A' : + detailTask.dataSource === 'db_connect_b' ? '数据库连接B' : detailTask.dataSource }} + + - + + - {{ detailTask?.selectedTable === 'table1' ? '数据表1' : '数据表2' }} + + {{ detailTask.selectedTable === 'table1' ? '数据表1' : + detailTask.selectedTable === 'table2' ? '数据表2' : detailTask.selectedTable }} + + - + + + {{ detailTask?.publishTime ?? '-' }} + + + {{ detailTask?.updateTime ?? '-' }} - - - + - - + - + - 新增 敏感词检测后,将直接使用符号替换 @@ -163,78 +161,65 @@ import { ref, reactive, computed, onMounted, watch } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { useRouter, useRoute } from 'vue-router' -// 导入任务API import { getTaskList, deleteTask, Task } from '@/api/task' -// 敏感词:仅导入获取列表的方法(保存接口暂不启用,移除save相关导入) import { getSensitiveWordList, SensitiveWord ,saveSensitiveWordChange} from '@/api/sensitiveWord' -// 路由实例 const router = useRouter() const route = useRoute() -// 选中的行(批量操作) const selectedRows = ref([]) - -// 响应式数据 -const taskList = ref([]) // 任务列表(从API获取) -const originTaskList = ref([]) // 原始列表(用于筛选重置) -// 存储筛选条件 +const taskList = ref([]) +const originTaskList = ref([]) const filterForm = reactive({ timeType: 'publishTime', dateRange: [] as string[], taskName: '', }) -// 详情弹窗相关(类型同步更新) const isDetailDialogVisible = ref(false) -const detailTask = ref(null) // Task接口已扩展,包含所有字段 - -// ========== 关键修改1:声明敏感词弹窗的显示/隐藏变量 ========== +const detailTask = ref(null) const isSensitiveDialogVisible = ref(false) -// 查看详情:打开弹窗并赋值 +// 查看详情:关键修改1 - 深拷贝row数据,避免浅拷贝引用问题 const handleDetail = (row: Task) => { - detailTask.value = row + // 深拷贝row,断绝和表格数据的引用关联 + detailTask.value = JSON.parse(JSON.stringify(row)) + // 调试:打印detailTask的完整值,确认字段是否真的存在且有值 + console.log('详情弹窗数据:', detailTask.value) isDetailDialogVisible.value = true } -// 初始化:获取任务列表 +// 初始化任务列表 const initTaskList = async () => { const list = await getTaskList() taskList.value = list originTaskList.value = [...list] } -// 监听路由:从新增/编辑页返回时刷新列表 +// 监听路由刷新列表 watch( () => route.path, () => { - if (route.path === '/task-formulation') { // 假设列表页路由是/task-formulation + if (route.path === '/task-formulation') { initTaskList() } } ) -// 页面挂载时加载数据 onMounted(() => { initTaskList() }) -// 操作按钮事件 -// 新增任务 +// 新增/编辑/删除/筛选等方法:无修改 const handleAdd = () => { - router.push('/task-formulation/add') // 新增页路由(无ID) + router.push('/task-formulation/add') } - -// 编辑任务:传任务ID到新增页 const handleEdit = (row: Task) => { router.push({ path: '/task-formulation/add', - query: { taskId: row.id }, // 传ID作为查询参数 + query: { taskId: row.id }, }) } - -// 批量删除 const handleBatchDelete = async () => { if (selectedRows.value.length === 0) { ElMessage.warning('请选择要删除的任务') @@ -242,30 +227,24 @@ const handleBatchDelete = async () => { } const deleteIds = selectedRows.value.map(item => item.id) await deleteTask(deleteIds) - initTaskList() // 刷新列表 + initTaskList() } - -// 单条删除 const handleDelete = async (row: Task) => { try { await ElMessageBox.confirm('确定删除该任务吗?', '提示', { type: 'warning' }) await deleteTask([row.id]) - initTaskList() // 刷新列表 + initTaskList() } catch (e) { ElMessage.info('已取消删除') } } - -// 筛选栏事件 const handleQuery = () => { let filteredList = [...originTaskList.value] - // 筛选:任务名称 if (filterForm.taskName) { filteredList = filteredList.filter(item => item.taskName.includes(filterForm.taskName) ) } - // 筛选:日期范围 if (filterForm.dateRange.length === 2) { const [startDate, endDate] = filterForm.dateRange filteredList = filteredList.filter(item => { @@ -277,43 +256,34 @@ const handleQuery = () => { } taskList.value = filteredList } - const handleReset = () => { filterForm.timeType = 'publishTime' filterForm.dateRange = [] filterForm.taskName = '' taskList.value = [...originTaskList.value] } - -// 表格事件 const handleSelectionChange = (val: Task[]) => { selectedRows.value = val } -// 敏感词设置相关方法 -// 敏感词设置相关 -// 1. 保存原始数据(初始化获取的后端数据,用于对比修改) +// 敏感词相关方法:无修改 const originSensitiveWords = ref([]) -// 2. 记录变更数据(仅传这部分给后端) const changeData = reactive({ - add: [] as SensitiveWord[], // 新增的敏感词 - update: [] as SensitiveWord[], // 修改的敏感词 - delete: [] as number[] // 删除的敏感词ID + add: [] as SensitiveWord[], + update: [] as SensitiveWord[], + delete: [] as number[] }) const sensitiveWordList = reactive([]) const currentPage = ref(1) const pageSize = ref(10) const total = computed(() => sensitiveWordList.length) -// 打开敏感词弹窗时,调用接口获取数据 const handleSensitiveWord = async () => { isSensitiveDialogVisible.value = true try { const res = await getSensitiveWordList() sensitiveWordList.length = 0 sensitiveWordList.push(...res) - // 保存原始数据(深拷贝,避免后续修改影响对比) originSensitiveWords.value = JSON.parse(JSON.stringify(res)) - // 每次打开弹窗重置变更记录 changeData.add = [] changeData.update = [] changeData.delete = [] @@ -322,61 +292,44 @@ const handleSensitiveWord = async () => { ElMessage.error('获取敏感词失败,请稍后重试') } } - -// 新增敏感词(操作本地数组) const handleAddSensitiveWord = () => { const newWord: SensitiveWord = { - id: 0, // 前端临时ID + id: 0, wordContent: "", isEnabled: 1, } sensitiveWordList.push(newWord) - // 记录新增的敏感词 changeData.add.push(newWord) } - -// 删除敏感词(操作本地数组) const handleDeleteSensitiveWord = (id: number) => { const index = sensitiveWordList.findIndex(item => item.id === id) if (index > -1) { const delItem = sensitiveWordList[index] sensitiveWordList.splice(index, 1) - - // 区分:如果是新增的(临时ID),从add里移除即可;否则记录删除ID const isAddItem = changeData.add.some(item => item.id === id) if (isAddItem) { changeData.add = changeData.add.filter(item => item.id !== id) } else { changeData.delete.push(id) - // 同时从update里移除(避免已修改又删除的重复处理) changeData.update = changeData.update.filter(item => item.id !== id) } } } - -// ========== 关键修改2:调整保存逻辑(暂不调用接口) ========== const handleSensitiveConfirm = async () => { - // 无变更时直接关闭弹窗 if (changeData.add.length === 0 && changeData.update.length === 0 && changeData.delete.length === 0) { isSensitiveDialogVisible.value = false ElMessage.info('暂无敏感词变更,无需保存') return } console.log("修改后的数据:",changeData); - - try { - // 只传变更数据给后端 await saveSensitiveWordChange({ add: changeData.add, update: changeData.update, delete: changeData.delete }) - ElMessage.success("敏感词变更已同步至后端!") isSensitiveDialogVisible.value = false - - // 可选:重新拉取最新数据,更新本地列表 const latestData = await getSensitiveWordList() sensitiveWordList.length = 0 sensitiveWordList.push(...latestData) @@ -386,16 +339,10 @@ const handleSensitiveConfirm = async () => { } } const handleWordChange = (row: SensitiveWord) => { - // 跳过新增的(新增的已在add里,不用重复记录) if (changeData.add.some(item => item.id === row.id)) return - - // 找原始数据中的对应项 const originItem = originSensitiveWords.value.find(item => item.id === row.id) if (!originItem) return - - // 对比:内容或状态有变化才记录 if (originItem.wordContent !== row.wordContent || originItem.isEnabled !== row.isEnabled) { - // 先移除已有的(避免重复),再添加最新的 changeData.update = changeData.update.filter(item => item.id !== row.id) changeData.update.push({ ...row }) } @@ -408,7 +355,6 @@ const handleWordChange = (row: SensitiveWord) => { &__actions { margin-bottom: 15px; - button { margin-right: 10px; } @@ -419,17 +365,14 @@ const handleWordChange = (row: SensitiveWord) => { background-color: #fff; border-radius: 4px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); - .filter-buttons { text-align: right; - button { margin-left: 10px; } } } } -// 详情弹窗样式优化 :deep(.el-descriptions) { .el-descriptions-item__label { font-weight: 500; -- Gitee From 11de4c8cb04e5167b57b1eeab225ed5fb2a9f8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AE=87=E9=98=B3?= <16188704+hyytiamo@user.noreply.gitee.com> Date: Sat, 10 Jan 2026 11:22:15 +0800 Subject: [PATCH 15/44] =?UTF-8?q?=E5=BB=BA=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/TableOperateController.java | 51 +++++++ .../entity/DataTableConfigEntity.java | 40 ++++++ .../teaching/entity/FillDataColumnEntity.java | 30 ++++ .../mapper/DataTableConfigMapper.java | 10 ++ .../teaching/mapper/FillDataColumnMapper.java | 13 ++ .../teaching/mapper/TableOperateMapper.java | 25 ++++ .../mapper/xml/FillDataColumnMapper.xml | 7 + .../sevice/IDataTableConfigService.java | 12 ++ .../teaching/sevice/IFillDataService.java | 13 ++ .../teaching/sevice/ITableOperateService.java | 17 +++ .../impl/DataTableConfigServiceImpl.java | 54 +++++++ .../sevice/impl/FillDataServiceImpl.java | 62 ++++++++ .../sevice/impl/TableOperateServiceImpl.java | 136 ++++++++++++++++++ .../teaching/vo/DataTableConfigVO.java | 24 ++++ .../teaching/vo/FillDataColumnVO.java | 19 +++ .../teaching/vo/TableCreateVO.java | 20 +++ .../teaching/vo/TableFieldVO.java | 25 ++++ 17 files changed, 558 insertions(+) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java new file mode 100644 index 0000000..e029ac2 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java @@ -0,0 +1,51 @@ +package com.unionbigdata.teaching.controller; + +import com.unionbigdata.teaching.sevice.ITableOperateService; +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.vo.TableCreateVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/table/visual") +@Tag(name = "可视化建表模块", description = "用户自定义表名、字段的可视化建表接口") +public class TableOperateController { + + private final ITableOperateService tableOperateService; + + public TableOperateController(ITableOperateService tableOperateService) { + this.tableOperateService = tableOperateService; + } + + // 原有接口:建表+列表名 + @PostMapping("/create") + @Operation(summary = "可视化创建表", description = "用户输入表名、字段后,动态创建表并保存配置") + public Result createTable(@Valid @RequestBody TableCreateVO tableCreateVO) { + return tableOperateService.createTableByVisual(tableCreateVO); + } + + @GetMapping("/list-names") + @Operation(summary = "查询已创建的表名", description = "返回所有可视化创建的表名,用于下拉选择") + public Result> listAllTableNames() { + return tableOperateService.listAllTableNames(); + } + + // ========== 新增:查询表结构(点击表名时调用) ========== + @GetMapping("/columns") + @Operation(summary = "查询表结构", description = "返回指定表的字段信息(字段名、类型、长度)") + public Result>> getTableColumns(@RequestParam String tableName) { + return tableOperateService.getTableColumns(tableName); + } + + // ========== 新增:查询表数据(点击表名时调用) ========== + @GetMapping("/data") + @Operation(summary = "查询表数据", description = "返回指定表的前10条数据") + public Result>> getTableData(@RequestParam String tableName) { + return tableOperateService.getTableData(tableName); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java b/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java new file mode 100644 index 0000000..7ed175d --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java @@ -0,0 +1,40 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.Data; + +import java.time.LocalDateTime; + +@TableName("data_table_config") // 对应你的表名 +@Data +public class DataTableConfigEntity { + @TableId(value = "id", type = IdType.AUTO) // 自增主键 + @NotNull(message = "Id不能为空!") + private Long id; + + @NotNull(message = "字段数量不能为空") + @PositiveOrZero(message = "字段数量不能小于0") + private Integer fieldCount; // 对应数据库field_count(字段数量) + + @NotNull(message = "表名不能为空!") + private String tableName; // 对应table_name(用户创建的表名) + + @NotNull(message = "taskId不能为空!") + private Long taskId; // 对应task_id(关联任务ID) + + @NotNull(message = "fillerId不能为空!") + private Long fillerId; // 对应filler_id(关联用户ID) + + @NotNull(message = "isPrimaryKey不能为空!") + private Boolean isPrimaryKey; // 是否为主键 + + private Integer columnLength; // 精度 + + private LocalDateTime createTime; // 对应create_time + + private LocalDateTime updateTime; // 对应update_time +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java b/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java new file mode 100644 index 0000000..b622906 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java @@ -0,0 +1,30 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@TableName("fill_data_column") // 对应你的表名 +@Data +public class FillDataColumnEntity { + @TableId(value = "id", type = IdType.AUTO) + @NotNull(message = "Id不能为空!") + private Long id; + @NotNull(message = "fillDataId不能为空!") + private Long tableId; // 对应fill_data_id(关联fill_data的id) + + @NotNull(message = "字段名称不能为空!") + private String columnName; // 对应column_name(字段名) + + @NotNull(message = "字段类型不能为空!") + private String columnType; // 对应column_type(字段类型) + + private String columnValue; // 对应column_value(字段值) + private LocalDateTime createTime; + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java new file mode 100644 index 0000000..52b2601 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java @@ -0,0 +1,10 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.DataTableConfigEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DataTableConfigMapper extends BaseMapper { + // 继承BaseMapper,自带增删改查;如需自定义SQL,可在此添加 +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java new file mode 100644 index 0000000..6047824 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java @@ -0,0 +1,13 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.FillDataColumnEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface FillDataColumnMapper extends BaseMapper { + // 根据fill_data_id查询对应的所有字段 + List selectByFillDataId(Long fillDataId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java new file mode 100644 index 0000000..4137c37 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java @@ -0,0 +1,25 @@ +package com.unionbigdata.teaching.mapper; + +import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Param; +import java.util.List; +import java.util.Map; + +public interface TableOperateMapper { + // 原有方法:建表+列表名 + @Update("${createTableSql}") + void executeCreateTableSql(@Param("createTableSql") String createTableSql); + @Select("SELECT table_name FROM data_table_config") + List listAllTableNames(); + + // ========== 新增:查询表结构(字段信息) ========== + @Select("SELECT COLUMN_NAME AS columnName, DATA_TYPE AS columnType, CHARACTER_MAXIMUM_LENGTH AS columnLength " + + "FROM INFORMATION_SCHEMA.COLUMNS " + + "WHERE TABLE_SCHEMA = (SELECT DATABASE()) AND TABLE_NAME = #{tableName}") + List> getTableColumns(@Param("tableName") String tableName); + + // ========== 新增:查询表数据(前10条,可自定义数量) ========== + @Select("SELECT * FROM ${tableName} LIMIT 10") + List> getTableData(@Param("tableName") String tableName); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml new file mode 100644 index 0000000..d37c2fb --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml @@ -0,0 +1,7 @@ + + + + + SELECT * FROM fill_data_column WHERE fill_data_id = #{fillDataId} + + \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java new file mode 100644 index 0000000..830d3cc --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java @@ -0,0 +1,12 @@ +package com.unionbigdata.teaching.sevice; + +import com.unionbigdata.teaching.vo.DataTableConfigVO; + +import java.util.List; + +public interface IDataTableConfigService { + // 创建数据表配置(可视化建表) + Long createTableConfig(DataTableConfigVO configVO); + // 根据用户ID查询其创建的表配置 + List listByFillerId(Long fillerId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java new file mode 100644 index 0000000..9c83043 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java @@ -0,0 +1,13 @@ +package com.unionbigdata.teaching.sevice; + +import com.unionbigdata.teaching.vo.FillDataColumnVO; + +import java.util.List; + +public interface IFillDataService { + + // 批量保存填报数据列 + void saveFillDataColumns(List columnVOs); + // 根据填报记录ID查询对应的字段数据 + List listColumnsByFillDataId(Long fillDataId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java new file mode 100644 index 0000000..209799b --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java @@ -0,0 +1,17 @@ +package com.unionbigdata.teaching.sevice; + +import com.unionbigdata.teaching.vo.TableCreateVO; +import com.unionbigdata.teaching.common.Result; +import java.util.List; +import java.util.Map; + +public interface ITableOperateService { + // 原有方法:建表+列表名 + Result createTableByVisual(TableCreateVO tableCreateVO); + Result> listAllTableNames(); + + // ========== 新增:查询表结构+数据 ========== + Result>> getTableColumns(String tableName); + Result>> getTableData(String tableName); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java new file mode 100644 index 0000000..972eea2 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java @@ -0,0 +1,54 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.unionbigdata.teaching.entity.DataTableConfigEntity; +import com.unionbigdata.teaching.mapper.DataTableConfigMapper; +import com.unionbigdata.teaching.sevice.IDataTableConfigService; +import com.unionbigdata.teaching.vo.DataTableConfigVO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class DataTableConfigServiceImpl implements IDataTableConfigService { + @Resource + private DataTableConfigMapper tableConfigMapper; + + @Override + @Transactional + public Long createTableConfig(DataTableConfigVO configVO) { + DataTableConfigEntity entity = new DataTableConfigEntity(); + entity.setFieldCount(configVO.getFieldCount()); + entity.setTableName(configVO.getTableName()); + entity.setTaskId(configVO.getTaskId()); + entity.setFillerId(configVO.getFillerId()); + tableConfigMapper.insert(entity); + return entity.getId(); + } + + @Override + public List listByFillerId(Long fillerId) { + List entities = tableConfigMapper.selectList( + Wrappers.lambdaQuery(DataTableConfigEntity.class) + .eq(DataTableConfigEntity::getFillerId, fillerId) + ); + return entities.stream().map(this::convertVO).collect(Collectors.toList()); + } + + private DataTableConfigVO convertVO(DataTableConfigEntity entity) { + DataTableConfigVO vo = new DataTableConfigVO(); + if (!ObjectUtils.isEmpty(entity)) { + vo.setId(entity.getId()); + vo.setFieldCount(entity.getFieldCount()); + vo.setTableName(entity.getTableName()); + vo.setTaskId(entity.getTaskId()); + vo.setFillerId(entity.getFillerId()); + vo.setCreateTime(entity.getCreateTime()); + } + return vo; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java new file mode 100644 index 0000000..716b8c0 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java @@ -0,0 +1,62 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.unionbigdata.teaching.entity.FillDataColumnEntity; +import com.unionbigdata.teaching.mapper.FillDataColumnMapper; +import com.unionbigdata.teaching.sevice.IFillDataService; +import com.unionbigdata.teaching.vo.FillDataColumnVO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class FillDataServiceImpl implements IFillDataService { + + @Resource + private FillDataColumnMapper fillDataColumnMapper; + + + @Override + @Transactional + public void saveFillDataColumns(List columnVOs) { + // 空值判断:避免空列表插入报错 + if (ObjectUtils.isEmpty(columnVOs)) { + return; + } + // VO转Entity + List entities = columnVOs.stream().map(vo -> { + FillDataColumnEntity entity = new FillDataColumnEntity(); + entity.setTableId(vo.getFillDataId()); + entity.setColumnName(vo.getColumnName()); + entity.setColumnType(vo.getColumnType()); + entity.setColumnValue(vo.getColumnValue()); + return entity; + }).collect(Collectors.toList()); + + // 修复:循环插入(兼容所有版本,大学生项目足够用) + for (FillDataColumnEntity entity : entities) { + fillDataColumnMapper.insert(entity); + } + } + + @Override + public List listColumnsByFillDataId(Long tableId) { + List entities = fillDataColumnMapper.selectByFillDataId(tableId); + return entities.stream().map(this::convertVO).collect(Collectors.toList()); + } + + private FillDataColumnVO convertVO(FillDataColumnEntity entity) { + FillDataColumnVO vo = new FillDataColumnVO(); + if (!ObjectUtils.isEmpty(entity)) { + vo.setId(entity.getId()); + vo.setFillDataId(entity.getTableId()); + vo.setColumnName(entity.getColumnName()); + vo.setColumnType(entity.getColumnType()); + vo.setColumnValue(entity.getColumnValue()); + } + return vo; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java new file mode 100644 index 0000000..af1dcb4 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java @@ -0,0 +1,136 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.unionbigdata.teaching.entity.DataTableConfigEntity; +import com.unionbigdata.teaching.mapper.DataTableConfigMapper; +import com.unionbigdata.teaching.mapper.TableOperateMapper; +import com.unionbigdata.teaching.sevice.ITableOperateService; +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.vo.TableCreateVO; +import com.unionbigdata.teaching.vo.TableFieldVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Service +public class TableOperateServiceImpl implements ITableOperateService { + + private final TableOperateMapper tableOperateMapper; + private final DataTableConfigMapper dataTableConfigMapper; + + public TableOperateServiceImpl(TableOperateMapper tableOperateMapper, DataTableConfigMapper dataTableConfigMapper) { + this.tableOperateMapper = tableOperateMapper; + this.dataTableConfigMapper = dataTableConfigMapper; + } + + // 原有方法:建表+列表名 + @Override + @Transactional(rollbackFor = Exception.class) + public Result createTableByVisual(TableCreateVO tableCreateVO) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DataTableConfigEntity::getTableName, tableCreateVO.getTableName()); + if (dataTableConfigMapper.selectCount(wrapper) > 0) { + return Result.fail("表名[" + tableCreateVO.getTableName() + "]已存在,请更换表名"); + } + String createTableSql = buildCreateTableSql(tableCreateVO); + tableOperateMapper.executeCreateTableSql(createTableSql); + DataTableConfigEntity configEntity = new DataTableConfigEntity(); + configEntity.setTableName(tableCreateVO.getTableName()); + configEntity.setFieldCount(tableCreateVO.getFields().size()); + configEntity.setTaskId(tableCreateVO.getTaskId()); + configEntity.setFillerId(tableCreateVO.getFillerId()); + configEntity.setCreateTime(LocalDateTime.now()); + configEntity.setUpdateTime(LocalDateTime.now()); + dataTableConfigMapper.insert(configEntity); + return Result.okWithMsg("表[" + tableCreateVO.getTableName() + "]创建成功"); + } + + @Override + public Result> listAllTableNames() { + List tableNames = tableOperateMapper.listAllTableNames(); + return Result.ok(tableNames); + } + + // ========== 新增:查询表结构(字段信息) ========== + @Override + public Result>> getTableColumns(String tableName) { + // 先校验表是否存在 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DataTableConfigEntity::getTableName, tableName); + if (dataTableConfigMapper.selectCount(wrapper) == 0) { + return Result.fail("表[" + tableName + "]不存在"); + } + List> columns = tableOperateMapper.getTableColumns(tableName); + return Result.ok(columns); + } + + // ========== 新增:查询表数据 ========== + @Override + public Result>> getTableData(String tableName) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DataTableConfigEntity::getTableName, tableName); + if (dataTableConfigMapper.selectCount(wrapper) == 0) { + return Result.fail("表[" + tableName + "]不存在"); + } + List> data = tableOperateMapper.getTableData(tableName); + return Result.ok(data); + } + + // 原有方法:生成建表SQL + // 文件名:TableOperateServiceImpl.java(所在包:com.unionbigdata.teaching.service.impl) + /** + * 拼接建表SQL(适配新的字段配置:主键/精度/空值) + */ + private String buildCreateTableSql(TableCreateVO tableCreateVO) { + StringBuilder createSql = new StringBuilder(); + // 表名加反引号 防止中文/关键字报错 + createSql.append("CREATE TABLE IF NOT EXISTS `").append(tableCreateVO.getTableName()).append("` ("); + + List fields = tableCreateVO.getFields(); + int fieldSize = fields.size(); + for (int i = 0; i < fieldSize; i++) { + TableFieldVO field = fields.get(i); + // 1. 拼接字段名 + createSql.append("`").append(field.getColumnName()).append("` "); + + // 2. 拼接字段类型 + 长度 + 精度【核心】 + createSql.append(field.getColumnType()); + if (field.getColumnLength() != null && field.getColumnLength() > 0) { + createSql.append("(").append(field.getColumnLength()); + // 精度有值 则拼接小数位数 例如 DECIMAL(10,2) 就是长度10,2位小数 + if (field.getColumnPrecision() != null && !field.getColumnPrecision().trim().isEmpty()) { + createSql.append(",").append(field.getColumnPrecision().trim()); + } + createSql.append(")"); + } + + // 3. 拼接主键约束 ✅ 你的字段:isPrimaryKey + // true=是主键 → 加 PRIMARY KEY,false=否 → 不加 + if (Boolean.TRUE.equals(field.getIsPrimaryKey())) { + createSql.append(" PRIMARY KEY"); + } + + // 4. 拼接非空约束 ✅ 你的字段:isnullable (全小写) + // true = 允许为空 → 不加约束;false = 不允许为空 → 加 NOT NULL + if (!field.isIsnullable()) { + createSql.append(" NOT NULL"); + } + + // 5. 字段之间加逗号 最后一个字段不加 避免SQL语法错误 + if (i != fieldSize - 1) { + createSql.append(","); + } + } + + // 固定添加创建时间、更新时间字段 + createSql.append(", create_time DATETIME DEFAULT CURRENT_TIMESTAMP"); + createSql.append(", update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"); + + // 表引擎和字符集 固定配置 + createSql.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"); + + return createSql.toString(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java new file mode 100644 index 0000000..3acfde6 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java @@ -0,0 +1,24 @@ +package com.unionbigdata.teaching.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "数据表配置VO") +@Data +public class DataTableConfigVO { + @Schema(description = "表配置ID") + private Long id; + @Schema(description = "字段数量") + private Integer fieldCount; + @Schema(description = "表名") + private String tableName; + @Schema(description = "任务ID") + private Long taskId; + @Schema(description = "用户ID") + private Long fillerId; + private LocalDateTime createTime; // 对应create_time + + private LocalDateTime updateTime; // 对应update_time +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java new file mode 100644 index 0000000..575a345 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java @@ -0,0 +1,19 @@ +package com.unionbigdata.teaching.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "填报数据列VO") +@Data +public class FillDataColumnVO { + @Schema(description = "列ID") + private Long id; + @Schema(description = "关联填报记录ID") + private Long fillDataId; + @Schema(description = "字段名") + private String columnName; + @Schema(description = "字段类型") + private String columnType; + @Schema(description = "字段值") + private String columnValue; +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java new file mode 100644 index 0000000..a4572a4 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java @@ -0,0 +1,20 @@ +package com.unionbigdata.teaching.vo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.util.List; + +@Data +public class TableCreateVO { + @NotBlank(message = "表名不能为空") + private String tableName; // 用户自定义的表名 + + @NotEmpty(message = "至少需要1个字段") + private List fields; // 字段列表 + + private Long taskId; // 关联的任务ID(从前端任务选择传入) + private Long fillerId; // 关联的用户ID(从前端传入) + +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java new file mode 100644 index 0000000..f669378 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java @@ -0,0 +1,25 @@ +package com.unionbigdata.teaching.vo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class TableFieldVO { + @NotBlank(message = "字段名不能为空") + private String columnName; // 字段名(如username) + + @NotBlank(message = "字段类型不能为空") + private String columnType; // 字段类型(如VARCHAR/INT/DECIMAL) + + @NotNull(message = "字段长度不能为空") // 修复1:Integer类型不能用@NotBlank,必须用@NotNull + private Integer columnLength; // 字段长度(如20/10) + + @NotNull(message = "是否主键不能为空!") + private Boolean isPrimaryKey; // 是否为主键 ✅ 你的字段名:isPrimaryKey + + @NotNull(message = "字段是否可空不能为空") // 修复2:boolean基本类型不能用@NotBlank,必须用@NotNull + private boolean isnullable; // 是否允许为空 ✅ 你的字段名:isnullable 【注意:全小写】 + + private String columnPrecision; // 精度 ✅ 你的字段名:columnPrecision (如填2 就是2位小数) +} \ No newline at end of file -- Gitee From b493c4224807c297034a85b7f773925817c039db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AE=87=E9=98=B3?= <16188704+hyytiamo@user.noreply.gitee.com> Date: Sat, 10 Jan 2026 11:23:30 +0800 Subject: [PATCH 16/44] =?UTF-8?q?=E5=BB=BA=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pom.xml | 18 ++- .../unionbigdata/teaching/common/Result.java | 14 +- .../controller/TableOperateController.java | 51 +++++++ .../entity/DataTableConfigEntity.java | 40 ++++++ .../teaching/entity/FillDataColumnEntity.java | 30 ++++ .../mapper/DataTableConfigMapper.java | 10 ++ .../teaching/mapper/FillDataColumnMapper.java | 13 ++ .../teaching/mapper/TableOperateMapper.java | 25 ++++ .../mapper/xml/FillDataColumnMapper.xml | 7 + .../sevice/IDataTableConfigService.java | 12 ++ .../teaching/sevice/IFillDataService.java | 13 ++ .../teaching/sevice/ITableOperateService.java | 17 +++ .../impl/DataTableConfigServiceImpl.java | 54 +++++++ .../sevice/impl/FillDataServiceImpl.java | 62 ++++++++ .../sevice/impl/TableOperateServiceImpl.java | 136 ++++++++++++++++++ .../teaching/vo/DataTableConfigVO.java | 24 ++++ .../teaching/vo/FillDataColumnVO.java | 19 +++ .../teaching/vo/TableCreateVO.java | 20 +++ .../teaching/vo/TableFieldVO.java | 25 ++++ backend/src/main/resources/application.yml | 29 +++- 20 files changed, 608 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java diff --git a/backend/pom.xml b/backend/pom.xml index 34e1ce2..1775b3f 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -95,7 +95,23 @@ - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + **/com/unionbigdata/teaching/vo/DataColumnVO.java + **/com/unionbigdata/teaching/service/impl/DataColumnServiceImpl.java + **/com/unionbigdata/teaching/service/IDataColumnService.java + **/com/unionbigdata/teaching/mapper/DataColumnMapper.java + **/com/unionbigdata/teaching/entity/DataColumnEntity.java + + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/backend/src/main/java/com/unionbigdata/teaching/common/Result.java b/backend/src/main/java/com/unionbigdata/teaching/common/Result.java index 1363a5c..a67cb85 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/common/Result.java +++ b/backend/src/main/java/com/unionbigdata/teaching/common/Result.java @@ -11,20 +11,17 @@ public class Result implements Serializable { public static final long serialVersionUID = 42L; public static final String SUCCESS_CODE = "200"; public static final String FAIL_CODE = "500"; - public static final String SUCCESS_MSG = "success"; public static final String FAIL_MSG = "fail"; private String code; - private String msg; private T content; private String requestId; - /** - * 先保留原id,避免其他版本报错 - */ private String id; + + // (保留你原有的所有方法) public static Result ok() { Result r = new Result(Result.SUCCESS_CODE, Result.SUCCESS_MSG); return r; @@ -56,6 +53,13 @@ public class Result implements Serializable { return r; } + // ========== 新增这个方法:解决“找不到okWithMsg”的问题 ========== + public static Result okWithMsg(String msg) { + return new Result(SUCCESS_CODE, msg); + } + + + // (保留你原有的构造方法和success方法) public Result() { } diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java new file mode 100644 index 0000000..e029ac2 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java @@ -0,0 +1,51 @@ +package com.unionbigdata.teaching.controller; + +import com.unionbigdata.teaching.sevice.ITableOperateService; +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.vo.TableCreateVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/table/visual") +@Tag(name = "可视化建表模块", description = "用户自定义表名、字段的可视化建表接口") +public class TableOperateController { + + private final ITableOperateService tableOperateService; + + public TableOperateController(ITableOperateService tableOperateService) { + this.tableOperateService = tableOperateService; + } + + // 原有接口:建表+列表名 + @PostMapping("/create") + @Operation(summary = "可视化创建表", description = "用户输入表名、字段后,动态创建表并保存配置") + public Result createTable(@Valid @RequestBody TableCreateVO tableCreateVO) { + return tableOperateService.createTableByVisual(tableCreateVO); + } + + @GetMapping("/list-names") + @Operation(summary = "查询已创建的表名", description = "返回所有可视化创建的表名,用于下拉选择") + public Result> listAllTableNames() { + return tableOperateService.listAllTableNames(); + } + + // ========== 新增:查询表结构(点击表名时调用) ========== + @GetMapping("/columns") + @Operation(summary = "查询表结构", description = "返回指定表的字段信息(字段名、类型、长度)") + public Result>> getTableColumns(@RequestParam String tableName) { + return tableOperateService.getTableColumns(tableName); + } + + // ========== 新增:查询表数据(点击表名时调用) ========== + @GetMapping("/data") + @Operation(summary = "查询表数据", description = "返回指定表的前10条数据") + public Result>> getTableData(@RequestParam String tableName) { + return tableOperateService.getTableData(tableName); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java b/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java new file mode 100644 index 0000000..7ed175d --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java @@ -0,0 +1,40 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.Data; + +import java.time.LocalDateTime; + +@TableName("data_table_config") // 对应你的表名 +@Data +public class DataTableConfigEntity { + @TableId(value = "id", type = IdType.AUTO) // 自增主键 + @NotNull(message = "Id不能为空!") + private Long id; + + @NotNull(message = "字段数量不能为空") + @PositiveOrZero(message = "字段数量不能小于0") + private Integer fieldCount; // 对应数据库field_count(字段数量) + + @NotNull(message = "表名不能为空!") + private String tableName; // 对应table_name(用户创建的表名) + + @NotNull(message = "taskId不能为空!") + private Long taskId; // 对应task_id(关联任务ID) + + @NotNull(message = "fillerId不能为空!") + private Long fillerId; // 对应filler_id(关联用户ID) + + @NotNull(message = "isPrimaryKey不能为空!") + private Boolean isPrimaryKey; // 是否为主键 + + private Integer columnLength; // 精度 + + private LocalDateTime createTime; // 对应create_time + + private LocalDateTime updateTime; // 对应update_time +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java b/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java new file mode 100644 index 0000000..b622906 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java @@ -0,0 +1,30 @@ +package com.unionbigdata.teaching.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@TableName("fill_data_column") // 对应你的表名 +@Data +public class FillDataColumnEntity { + @TableId(value = "id", type = IdType.AUTO) + @NotNull(message = "Id不能为空!") + private Long id; + @NotNull(message = "fillDataId不能为空!") + private Long tableId; // 对应fill_data_id(关联fill_data的id) + + @NotNull(message = "字段名称不能为空!") + private String columnName; // 对应column_name(字段名) + + @NotNull(message = "字段类型不能为空!") + private String columnType; // 对应column_type(字段类型) + + private String columnValue; // 对应column_value(字段值) + private LocalDateTime createTime; + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java new file mode 100644 index 0000000..52b2601 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/DataTableConfigMapper.java @@ -0,0 +1,10 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.DataTableConfigEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DataTableConfigMapper extends BaseMapper { + // 继承BaseMapper,自带增删改查;如需自定义SQL,可在此添加 +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java new file mode 100644 index 0000000..6047824 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java @@ -0,0 +1,13 @@ +package com.unionbigdata.teaching.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.entity.FillDataColumnEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface FillDataColumnMapper extends BaseMapper { + // 根据fill_data_id查询对应的所有字段 + List selectByFillDataId(Long fillDataId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java new file mode 100644 index 0000000..4137c37 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java @@ -0,0 +1,25 @@ +package com.unionbigdata.teaching.mapper; + +import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Param; +import java.util.List; +import java.util.Map; + +public interface TableOperateMapper { + // 原有方法:建表+列表名 + @Update("${createTableSql}") + void executeCreateTableSql(@Param("createTableSql") String createTableSql); + @Select("SELECT table_name FROM data_table_config") + List listAllTableNames(); + + // ========== 新增:查询表结构(字段信息) ========== + @Select("SELECT COLUMN_NAME AS columnName, DATA_TYPE AS columnType, CHARACTER_MAXIMUM_LENGTH AS columnLength " + + "FROM INFORMATION_SCHEMA.COLUMNS " + + "WHERE TABLE_SCHEMA = (SELECT DATABASE()) AND TABLE_NAME = #{tableName}") + List> getTableColumns(@Param("tableName") String tableName); + + // ========== 新增:查询表数据(前10条,可自定义数量) ========== + @Select("SELECT * FROM ${tableName} LIMIT 10") + List> getTableData(@Param("tableName") String tableName); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml new file mode 100644 index 0000000..d37c2fb --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/xml/FillDataColumnMapper.xml @@ -0,0 +1,7 @@ + + + + + SELECT * FROM fill_data_column WHERE fill_data_id = #{fillDataId} + + \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java new file mode 100644 index 0000000..830d3cc --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/IDataTableConfigService.java @@ -0,0 +1,12 @@ +package com.unionbigdata.teaching.sevice; + +import com.unionbigdata.teaching.vo.DataTableConfigVO; + +import java.util.List; + +public interface IDataTableConfigService { + // 创建数据表配置(可视化建表) + Long createTableConfig(DataTableConfigVO configVO); + // 根据用户ID查询其创建的表配置 + List listByFillerId(Long fillerId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java new file mode 100644 index 0000000..9c83043 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/IFillDataService.java @@ -0,0 +1,13 @@ +package com.unionbigdata.teaching.sevice; + +import com.unionbigdata.teaching.vo.FillDataColumnVO; + +import java.util.List; + +public interface IFillDataService { + + // 批量保存填报数据列 + void saveFillDataColumns(List columnVOs); + // 根据填报记录ID查询对应的字段数据 + List listColumnsByFillDataId(Long fillDataId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java new file mode 100644 index 0000000..209799b --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java @@ -0,0 +1,17 @@ +package com.unionbigdata.teaching.sevice; + +import com.unionbigdata.teaching.vo.TableCreateVO; +import com.unionbigdata.teaching.common.Result; +import java.util.List; +import java.util.Map; + +public interface ITableOperateService { + // 原有方法:建表+列表名 + Result createTableByVisual(TableCreateVO tableCreateVO); + Result> listAllTableNames(); + + // ========== 新增:查询表结构+数据 ========== + Result>> getTableColumns(String tableName); + Result>> getTableData(String tableName); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java new file mode 100644 index 0000000..972eea2 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/DataTableConfigServiceImpl.java @@ -0,0 +1,54 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.unionbigdata.teaching.entity.DataTableConfigEntity; +import com.unionbigdata.teaching.mapper.DataTableConfigMapper; +import com.unionbigdata.teaching.sevice.IDataTableConfigService; +import com.unionbigdata.teaching.vo.DataTableConfigVO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class DataTableConfigServiceImpl implements IDataTableConfigService { + @Resource + private DataTableConfigMapper tableConfigMapper; + + @Override + @Transactional + public Long createTableConfig(DataTableConfigVO configVO) { + DataTableConfigEntity entity = new DataTableConfigEntity(); + entity.setFieldCount(configVO.getFieldCount()); + entity.setTableName(configVO.getTableName()); + entity.setTaskId(configVO.getTaskId()); + entity.setFillerId(configVO.getFillerId()); + tableConfigMapper.insert(entity); + return entity.getId(); + } + + @Override + public List listByFillerId(Long fillerId) { + List entities = tableConfigMapper.selectList( + Wrappers.lambdaQuery(DataTableConfigEntity.class) + .eq(DataTableConfigEntity::getFillerId, fillerId) + ); + return entities.stream().map(this::convertVO).collect(Collectors.toList()); + } + + private DataTableConfigVO convertVO(DataTableConfigEntity entity) { + DataTableConfigVO vo = new DataTableConfigVO(); + if (!ObjectUtils.isEmpty(entity)) { + vo.setId(entity.getId()); + vo.setFieldCount(entity.getFieldCount()); + vo.setTableName(entity.getTableName()); + vo.setTaskId(entity.getTaskId()); + vo.setFillerId(entity.getFillerId()); + vo.setCreateTime(entity.getCreateTime()); + } + return vo; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java new file mode 100644 index 0000000..716b8c0 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java @@ -0,0 +1,62 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.unionbigdata.teaching.entity.FillDataColumnEntity; +import com.unionbigdata.teaching.mapper.FillDataColumnMapper; +import com.unionbigdata.teaching.sevice.IFillDataService; +import com.unionbigdata.teaching.vo.FillDataColumnVO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class FillDataServiceImpl implements IFillDataService { + + @Resource + private FillDataColumnMapper fillDataColumnMapper; + + + @Override + @Transactional + public void saveFillDataColumns(List columnVOs) { + // 空值判断:避免空列表插入报错 + if (ObjectUtils.isEmpty(columnVOs)) { + return; + } + // VO转Entity + List entities = columnVOs.stream().map(vo -> { + FillDataColumnEntity entity = new FillDataColumnEntity(); + entity.setTableId(vo.getFillDataId()); + entity.setColumnName(vo.getColumnName()); + entity.setColumnType(vo.getColumnType()); + entity.setColumnValue(vo.getColumnValue()); + return entity; + }).collect(Collectors.toList()); + + // 修复:循环插入(兼容所有版本,大学生项目足够用) + for (FillDataColumnEntity entity : entities) { + fillDataColumnMapper.insert(entity); + } + } + + @Override + public List listColumnsByFillDataId(Long tableId) { + List entities = fillDataColumnMapper.selectByFillDataId(tableId); + return entities.stream().map(this::convertVO).collect(Collectors.toList()); + } + + private FillDataColumnVO convertVO(FillDataColumnEntity entity) { + FillDataColumnVO vo = new FillDataColumnVO(); + if (!ObjectUtils.isEmpty(entity)) { + vo.setId(entity.getId()); + vo.setFillDataId(entity.getTableId()); + vo.setColumnName(entity.getColumnName()); + vo.setColumnType(entity.getColumnType()); + vo.setColumnValue(entity.getColumnValue()); + } + return vo; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java new file mode 100644 index 0000000..af1dcb4 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java @@ -0,0 +1,136 @@ +package com.unionbigdata.teaching.sevice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.unionbigdata.teaching.entity.DataTableConfigEntity; +import com.unionbigdata.teaching.mapper.DataTableConfigMapper; +import com.unionbigdata.teaching.mapper.TableOperateMapper; +import com.unionbigdata.teaching.sevice.ITableOperateService; +import com.unionbigdata.teaching.common.Result; +import com.unionbigdata.teaching.vo.TableCreateVO; +import com.unionbigdata.teaching.vo.TableFieldVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Service +public class TableOperateServiceImpl implements ITableOperateService { + + private final TableOperateMapper tableOperateMapper; + private final DataTableConfigMapper dataTableConfigMapper; + + public TableOperateServiceImpl(TableOperateMapper tableOperateMapper, DataTableConfigMapper dataTableConfigMapper) { + this.tableOperateMapper = tableOperateMapper; + this.dataTableConfigMapper = dataTableConfigMapper; + } + + // 原有方法:建表+列表名 + @Override + @Transactional(rollbackFor = Exception.class) + public Result createTableByVisual(TableCreateVO tableCreateVO) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DataTableConfigEntity::getTableName, tableCreateVO.getTableName()); + if (dataTableConfigMapper.selectCount(wrapper) > 0) { + return Result.fail("表名[" + tableCreateVO.getTableName() + "]已存在,请更换表名"); + } + String createTableSql = buildCreateTableSql(tableCreateVO); + tableOperateMapper.executeCreateTableSql(createTableSql); + DataTableConfigEntity configEntity = new DataTableConfigEntity(); + configEntity.setTableName(tableCreateVO.getTableName()); + configEntity.setFieldCount(tableCreateVO.getFields().size()); + configEntity.setTaskId(tableCreateVO.getTaskId()); + configEntity.setFillerId(tableCreateVO.getFillerId()); + configEntity.setCreateTime(LocalDateTime.now()); + configEntity.setUpdateTime(LocalDateTime.now()); + dataTableConfigMapper.insert(configEntity); + return Result.okWithMsg("表[" + tableCreateVO.getTableName() + "]创建成功"); + } + + @Override + public Result> listAllTableNames() { + List tableNames = tableOperateMapper.listAllTableNames(); + return Result.ok(tableNames); + } + + // ========== 新增:查询表结构(字段信息) ========== + @Override + public Result>> getTableColumns(String tableName) { + // 先校验表是否存在 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DataTableConfigEntity::getTableName, tableName); + if (dataTableConfigMapper.selectCount(wrapper) == 0) { + return Result.fail("表[" + tableName + "]不存在"); + } + List> columns = tableOperateMapper.getTableColumns(tableName); + return Result.ok(columns); + } + + // ========== 新增:查询表数据 ========== + @Override + public Result>> getTableData(String tableName) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DataTableConfigEntity::getTableName, tableName); + if (dataTableConfigMapper.selectCount(wrapper) == 0) { + return Result.fail("表[" + tableName + "]不存在"); + } + List> data = tableOperateMapper.getTableData(tableName); + return Result.ok(data); + } + + // 原有方法:生成建表SQL + // 文件名:TableOperateServiceImpl.java(所在包:com.unionbigdata.teaching.service.impl) + /** + * 拼接建表SQL(适配新的字段配置:主键/精度/空值) + */ + private String buildCreateTableSql(TableCreateVO tableCreateVO) { + StringBuilder createSql = new StringBuilder(); + // 表名加反引号 防止中文/关键字报错 + createSql.append("CREATE TABLE IF NOT EXISTS `").append(tableCreateVO.getTableName()).append("` ("); + + List fields = tableCreateVO.getFields(); + int fieldSize = fields.size(); + for (int i = 0; i < fieldSize; i++) { + TableFieldVO field = fields.get(i); + // 1. 拼接字段名 + createSql.append("`").append(field.getColumnName()).append("` "); + + // 2. 拼接字段类型 + 长度 + 精度【核心】 + createSql.append(field.getColumnType()); + if (field.getColumnLength() != null && field.getColumnLength() > 0) { + createSql.append("(").append(field.getColumnLength()); + // 精度有值 则拼接小数位数 例如 DECIMAL(10,2) 就是长度10,2位小数 + if (field.getColumnPrecision() != null && !field.getColumnPrecision().trim().isEmpty()) { + createSql.append(",").append(field.getColumnPrecision().trim()); + } + createSql.append(")"); + } + + // 3. 拼接主键约束 ✅ 你的字段:isPrimaryKey + // true=是主键 → 加 PRIMARY KEY,false=否 → 不加 + if (Boolean.TRUE.equals(field.getIsPrimaryKey())) { + createSql.append(" PRIMARY KEY"); + } + + // 4. 拼接非空约束 ✅ 你的字段:isnullable (全小写) + // true = 允许为空 → 不加约束;false = 不允许为空 → 加 NOT NULL + if (!field.isIsnullable()) { + createSql.append(" NOT NULL"); + } + + // 5. 字段之间加逗号 最后一个字段不加 避免SQL语法错误 + if (i != fieldSize - 1) { + createSql.append(","); + } + } + + // 固定添加创建时间、更新时间字段 + createSql.append(", create_time DATETIME DEFAULT CURRENT_TIMESTAMP"); + createSql.append(", update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"); + + // 表引擎和字符集 固定配置 + createSql.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"); + + return createSql.toString(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java new file mode 100644 index 0000000..3acfde6 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/DataTableConfigVO.java @@ -0,0 +1,24 @@ +package com.unionbigdata.teaching.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "数据表配置VO") +@Data +public class DataTableConfigVO { + @Schema(description = "表配置ID") + private Long id; + @Schema(description = "字段数量") + private Integer fieldCount; + @Schema(description = "表名") + private String tableName; + @Schema(description = "任务ID") + private Long taskId; + @Schema(description = "用户ID") + private Long fillerId; + private LocalDateTime createTime; // 对应create_time + + private LocalDateTime updateTime; // 对应update_time +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java new file mode 100644 index 0000000..575a345 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/FillDataColumnVO.java @@ -0,0 +1,19 @@ +package com.unionbigdata.teaching.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "填报数据列VO") +@Data +public class FillDataColumnVO { + @Schema(description = "列ID") + private Long id; + @Schema(description = "关联填报记录ID") + private Long fillDataId; + @Schema(description = "字段名") + private String columnName; + @Schema(description = "字段类型") + private String columnType; + @Schema(description = "字段值") + private String columnValue; +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java new file mode 100644 index 0000000..a4572a4 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java @@ -0,0 +1,20 @@ +package com.unionbigdata.teaching.vo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.util.List; + +@Data +public class TableCreateVO { + @NotBlank(message = "表名不能为空") + private String tableName; // 用户自定义的表名 + + @NotEmpty(message = "至少需要1个字段") + private List fields; // 字段列表 + + private Long taskId; // 关联的任务ID(从前端任务选择传入) + private Long fillerId; // 关联的用户ID(从前端传入) + +} \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java new file mode 100644 index 0000000..f669378 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/TableFieldVO.java @@ -0,0 +1,25 @@ +package com.unionbigdata.teaching.vo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class TableFieldVO { + @NotBlank(message = "字段名不能为空") + private String columnName; // 字段名(如username) + + @NotBlank(message = "字段类型不能为空") + private String columnType; // 字段类型(如VARCHAR/INT/DECIMAL) + + @NotNull(message = "字段长度不能为空") // 修复1:Integer类型不能用@NotBlank,必须用@NotNull + private Integer columnLength; // 字段长度(如20/10) + + @NotNull(message = "是否主键不能为空!") + private Boolean isPrimaryKey; // 是否为主键 ✅ 你的字段名:isPrimaryKey + + @NotNull(message = "字段是否可空不能为空") // 修复2:boolean基本类型不能用@NotBlank,必须用@NotNull + private boolean isnullable; // 是否允许为空 ✅ 你的字段名:isnullable 【注意:全小写】 + + private String columnPrecision; // 精度 ✅ 你的字段名:columnPrecision (如填2 就是2位小数) +} \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 8f7cf05..62f758f 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -4,34 +4,53 @@ server: spring: application: name: data-acqusition-system + + # 您的数据库配置 datasource: - url: jdbc:mysql://localhost:3306/data-acqusition-system?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai + url: jdbc:mysql://localhost:3306/data_acqusition_system?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root - password: 123456 + password: hyy4088.. driver-class-name: com.mysql.cj.jdbc.Driver + + # 建议添加连接池配置(提高性能) + hikari: + connection-timeout: 30000 + maximum-pool-size: 20 + minimum-idle: 5 + sql: init: - mode: never + mode: never # 您已手动导入数据,所以用never + mybatis-plus: + # 您的mapper文件路径 mapper-locations: classpath*:com/unionbigdata/teaching/mapper/xml/*.xml + + # 添加实体类包扫描 + type-aliases-package: com.unionbigdata.teaching.entity + global-config: db-config: id-type: auto + configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + map-underscore-to-camel-case: true # 自动下划线转驼峰 springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha + api-docs: path: /v3/api-docs + group-configs: - group: 'default' paths-to-match: '/**' - packages-to-scan: com.unionbigdata.teaching -# knife4j的增强配置,不需要增强可以不配 + packages-to-scan: com.unionbigdata.teaching.controller # 建议精确到controller包 + knife4j: enable: true setting: -- Gitee From aa7c4b0f547dc7b15f0a294da858766b7eff20f6 Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Sat, 10 Jan 2026 11:27:11 +0800 Subject: [PATCH 17/44] =?UTF-8?q?=E5=AF=B9=E4=BB=BB=E5=8A=A1=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=8A=9F=E8=83=BD=E8=BF=9B=E4=B8=80=E6=AD=A5=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/controller/TaskController.java | 22 ++++++++----------- .../unionbigdata/teaching/entity/Task.java | 3 --- .../teaching/sevice/ITaskService.java | 16 +++++++++----- .../teaching/sevice/impl/TaskServiceImpl.java | 22 +++++++++++++------ 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java index 05c572b..ec2435b 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java @@ -1,5 +1,6 @@ package com.unionbigdata.teaching.controller; +import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; import com.unionbigdata.teaching.common.Result; import com.unionbigdata.teaching.sevice.ITaskService; import com.unionbigdata.teaching.vo.TaskVO; @@ -18,17 +19,7 @@ public class TaskController { @Autowired private ITaskService taskService; -/** - * 获取任务列表的方法 - * 该方法用于从服务层获取所有的任务信息,并将其转换为视图对象(TaskVO)返回 - * - * @return List 返回任务视图对象的列表,包含了所有任务的信息 - */ - @GetMapping - public Result> getTaskList(){ - // 调用taskService的getAllTask方法获取所有任务数据 - return Result.ok(taskService.getAllTask()); - } + /** * 用@RequestParam接收查询参数 @@ -53,8 +44,8 @@ public class TaskController { * @param id 任务ID,通过路径变量传递 * @return 返回一个Result对象,包含任务信息的Map集合 */ - @GetMapping("/{id}") - public Result> getTaskById(@PathVariable Integer id){ + @GetMapping("/addOrEdit/{id}") + public Result> addOrEditTaskById(@PathVariable Integer id){ // 调用taskService的getTaskById方法获取任务信息,并封装到Result对象中返回 return Result.ok(taskService.getTaskById(id)); } @@ -63,4 +54,9 @@ public class TaskController { public Result deleteBatch(@RequestBody List ids) { return Result.ok(taskService.removeBatchByIds(ids)); } + + @PostMapping("/datacollect")//数据采集 + public Result dataCollect(@RequestBody DynamicTableRequestDTO dynamicDTO) { + return Result.ok(taskService.dataCollect(dynamicDTO)); + } } diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java index 9dd1f26..9a1a831 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java @@ -34,9 +34,6 @@ public class Task { //处理人id private Long handlerId; - //theme_id - private Integer themeId; - //任务描述 private String taskDescription; diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java index 95a7ba1..a7bc792 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java @@ -1,6 +1,7 @@ package com.unionbigdata.teaching.sevice; import com.baomidou.mybatisplus.extension.service.IService; +import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; import com.unionbigdata.teaching.entity.Task; import com.unionbigdata.teaching.vo.TaskVO; @@ -9,12 +10,6 @@ import java.util.List; import java.util.Map; public interface ITaskService extends IService { -/** - * 获取所有任务的方法 - * - * @return 返回一个TaskVO类型的列表,包含所有任务的信息 - */ - List getAllTask(); Map getTaskById(Integer id); @@ -27,4 +22,13 @@ public interface ITaskService extends IService { * @return 返回任务列表,包含符合条件的TaskVO对象集合 */ List queryTaskList(String timeType, LocalDate startDate, LocalDate endDate, String taskName); + +/** + * 数据收集方法 + * 用于根据动态表格请求DTO对象收集并返回相关数据 + * + * @param dynamicDTO 动态表格请求DTO对象,包含收集数据所需的参数和条件 + * @return 返回收集到的数据,类型为Object,具体类型取决于实现 + */ + Object dataCollect(DynamicTableRequestDTO dynamicDTO); } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java index ee773f0..5ea2cd6 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java @@ -2,14 +2,17 @@ package com.unionbigdata.teaching.sevice.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; import com.unionbigdata.teaching.entity.DataSource; import com.unionbigdata.teaching.entity.Task; import com.unionbigdata.teaching.mapper.DataSourceMapper; import com.unionbigdata.teaching.mapper.TaskMapper; +import com.unionbigdata.teaching.sevice.ISensitiveWordService; import com.unionbigdata.teaching.sevice.ITaskService; import com.unionbigdata.teaching.vo.DataSourceVO; import com.unionbigdata.teaching.vo.TaskVO; import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; @@ -28,13 +31,6 @@ public class TaskServiceImpl extends ServiceImpl implements IT @Resource private DataSourceMapper dataSourceMapper; - @Override - public List getAllTask() { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.orderByDesc("create_time"); - List taskList = taskMapper.selectList(queryWrapper); - return taskList.stream().map(this::convertTaskVO).toList(); - } @Override public Map getTaskById(Integer id) { @@ -53,6 +49,7 @@ public class TaskServiceImpl extends ServiceImpl implements IT dynamicJson.put("version",task.getVersion());//任务版本 dynamicJson.put("taskDescription",task.getTaskDescription()); dynamicJson.put("isSensitiveDetection",task.getIsSensitiveDetection()); + dynamicJson.put("createTime",task.getCreateTime());//任务创建时间 dynamicJson.put("dataSourceList",dataSourceVOList);//任务的数据源 return dynamicJson; } @@ -87,6 +84,17 @@ public class TaskServiceImpl extends ServiceImpl implements IT .toList(); // Java16+简洁写法 } + @Override + public Object dataCollect(DynamicTableRequestDTO dynamicDTO) { + Integer taskId = dynamicDTO.getTaskId(); + //根据任务id查询到对应要填充的表的名称(1任务对1表,1表对n任务) + + //对数据进行清理(敏感词过滤、质检) + + //插入数据 + return null; + } + private TaskVO convertTaskVO(Task task) { TaskVO taskVO = new TaskVO(); if (!ObjectUtils.isEmpty(task)) { -- Gitee From 66143019f03e7c4f8ceb943a9d945651357f14de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AE=87=E9=98=B3?= <16188704+hyytiamo@user.noreply.gitee.com> Date: Sat, 10 Jan 2026 14:58:57 +0800 Subject: [PATCH 18/44] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E5=AF=B9?= =?UTF-8?q?=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/controller/TableOperateController.java | 6 +++--- .../teaching/entity/DataTableConfigEntity.java | 2 ++ .../unionbigdata/teaching/mapper/TableOperateMapper.java | 4 ++-- .../teaching/sevice/ITableOperateService.java | 2 +- .../teaching/sevice/impl/TableOperateServiceImpl.java | 9 ++++++--- .../java/com/unionbigdata/teaching/vo/TableCreateVO.java | 3 +++ 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java index e029ac2..6573d5e 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TableOperateController.java @@ -29,10 +29,10 @@ public class TableOperateController { return tableOperateService.createTableByVisual(tableCreateVO); } - @GetMapping("/list-names") + @GetMapping("-{id}") @Operation(summary = "查询已创建的表名", description = "返回所有可视化创建的表名,用于下拉选择") - public Result> listAllTableNames() { - return tableOperateService.listAllTableNames(); + public Result> listAllTableNames(@PathVariable Long id) { + return tableOperateService.listAllTableNames(id); } // ========== 新增:查询表结构(点击表名时调用) ========== diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java b/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java index 7ed175d..327bd06 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/DataTableConfigEntity.java @@ -34,6 +34,8 @@ public class DataTableConfigEntity { private Integer columnLength; // 精度 + private Integer dataSourceId; // 对应datasource_id(关联数据源ID) + private LocalDateTime createTime; // 对应create_time private LocalDateTime updateTime; // 对应update_time diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java index 4137c37..28e1efc 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java @@ -10,8 +10,8 @@ public interface TableOperateMapper { // 原有方法:建表+列表名 @Update("${createTableSql}") void executeCreateTableSql(@Param("createTableSql") String createTableSql); - @Select("SELECT table_name FROM data_table_config") - List listAllTableNames(); + @Select("SELECT table_name FROM data_table_config WHERE datasource_id = #{id}") + List listAllTableNames(@Param("id") Long id); // ========== 新增:查询表结构(字段信息) ========== @Select("SELECT COLUMN_NAME AS columnName, DATA_TYPE AS columnType, CHARACTER_MAXIMUM_LENGTH AS columnLength " + diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java index 209799b..c10a993 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITableOperateService.java @@ -8,7 +8,7 @@ import java.util.Map; public interface ITableOperateService { // 原有方法:建表+列表名 Result createTableByVisual(TableCreateVO tableCreateVO); - Result> listAllTableNames(); + Result> listAllTableNames(Long id); // ========== 新增:查询表结构+数据 ========== Result>> getTableColumns(String tableName); diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java index af1dcb4..ee5eafe 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TableOperateServiceImpl.java @@ -36,6 +36,7 @@ public class TableOperateServiceImpl implements ITableOperateService { } String createTableSql = buildCreateTableSql(tableCreateVO); tableOperateMapper.executeCreateTableSql(createTableSql); + DataTableConfigEntity configEntity = new DataTableConfigEntity(); configEntity.setTableName(tableCreateVO.getTableName()); configEntity.setFieldCount(tableCreateVO.getFields().size()); @@ -43,13 +44,14 @@ public class TableOperateServiceImpl implements ITableOperateService { configEntity.setFillerId(tableCreateVO.getFillerId()); configEntity.setCreateTime(LocalDateTime.now()); configEntity.setUpdateTime(LocalDateTime.now()); + configEntity.setDataSourceId(tableCreateVO.getDataSourceId()); dataTableConfigMapper.insert(configEntity); return Result.okWithMsg("表[" + tableCreateVO.getTableName() + "]创建成功"); } @Override - public Result> listAllTableNames() { - List tableNames = tableOperateMapper.listAllTableNames(); + public Result> listAllTableNames(Long id) { + List tableNames = tableOperateMapper.listAllTableNames(id); return Result.ok(tableNames); } @@ -87,6 +89,8 @@ public class TableOperateServiceImpl implements ITableOperateService { StringBuilder createSql = new StringBuilder(); // 表名加反引号 防止中文/关键字报错 createSql.append("CREATE TABLE IF NOT EXISTS `").append(tableCreateVO.getTableName()).append("` ("); + //自增主键 + createSql.append("`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,"); List fields = tableCreateVO.getFields(); int fieldSize = fields.size(); @@ -117,7 +121,6 @@ public class TableOperateServiceImpl implements ITableOperateService { if (!field.isIsnullable()) { createSql.append(" NOT NULL"); } - // 5. 字段之间加逗号 最后一个字段不加 避免SQL语法错误 if (i != fieldSize - 1) { createSql.append(","); diff --git a/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java b/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java index a4572a4..d8ad082 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java +++ b/backend/src/main/java/com/unionbigdata/teaching/vo/TableCreateVO.java @@ -8,6 +8,9 @@ import java.util.List; @Data public class TableCreateVO { + @NotBlank(message = "数据源id,不为空") + private Integer dataSourceId; + @NotBlank(message = "表名不能为空") private String tableName; // 用户自定义的表名 -- Gitee From 3ec0191072e13859a42a0a632db01ee3c6c9335a Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Sun, 11 Jan 2026 13:34:23 +0800 Subject: [PATCH 19/44] =?UTF-8?q?=E5=BC=80=E5=8F=91=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=81=E7=BC=96=E8=BE=91=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teaching/DTO/CreateTableDTO.java | 16 ++++ .../teaching/DTO/SelectColumnDTO.java | 19 ++++ .../unionbigdata/teaching/DTO/TaskAddDTO.java | 46 ++++++++++ .../teaching/controller/TaskController.java | 13 +++ .../teaching/entity/FillDataColumnEntity.java | 10 ++- .../unionbigdata/teaching/entity/Task.java | 7 +- .../teaching/mapper/FillDataColumnMapper.java | 68 ++++++++++++++- .../teaching/mapper/TableOperateMapper.java | 2 +- .../teaching/mapper/TaskMapper.java | 8 ++ .../teaching/sevice/ITaskService.java | 16 ++++ .../sevice/impl/FillDataServiceImpl.java | 2 - .../sevice/impl/SensitiveWordServiceImpl.java | 86 +++++++++++++++++-- .../teaching/sevice/impl/TaskServiceImpl.java | 61 ++++++++++++- 13 files changed, 334 insertions(+), 20 deletions(-) create mode 100644 backend/src/main/java/com/unionbigdata/teaching/DTO/CreateTableDTO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/DTO/SelectColumnDTO.java create mode 100644 backend/src/main/java/com/unionbigdata/teaching/DTO/TaskAddDTO.java diff --git a/backend/src/main/java/com/unionbigdata/teaching/DTO/CreateTableDTO.java b/backend/src/main/java/com/unionbigdata/teaching/DTO/CreateTableDTO.java new file mode 100644 index 0000000..50d6c92 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/DTO/CreateTableDTO.java @@ -0,0 +1,16 @@ +package com.unionbigdata.teaching.DTO; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class CreateTableDTO { + + // 表名 + private String tableName; + + // 动态表格行数据:每一行是“字段名→值”的键值对。一个Map可以装很多,一个Map存一行;如<字段名,姓名> + private List> tableRows; +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/DTO/SelectColumnDTO.java b/backend/src/main/java/com/unionbigdata/teaching/DTO/SelectColumnDTO.java new file mode 100644 index 0000000..a731a05 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/DTO/SelectColumnDTO.java @@ -0,0 +1,19 @@ +package com.unionbigdata.teaching.DTO; + +import lombok.Data; + +import java.util.List; + +@Data +public class SelectColumnDTO { + //列名 + String columnName; + //注释或备注 + private String columnComment; + // 对应column_type(字段类型) + private String columnType; + //是否采集 + private Integer isCollect; + //数据长度 + private Integer length; +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/DTO/TaskAddDTO.java b/backend/src/main/java/com/unionbigdata/teaching/DTO/TaskAddDTO.java new file mode 100644 index 0000000..ee2c292 --- /dev/null +++ b/backend/src/main/java/com/unionbigdata/teaching/DTO/TaskAddDTO.java @@ -0,0 +1,46 @@ +package com.unionbigdata.teaching.DTO; + +import lombok.Data; + +import java.util.List; + +@Data +public class TaskAddDTO { + //第一步所用数据 + //任务名称 + private String taskName; + //版本号 + private String version; + //任务描述 + private String taskDescription; + //是否开启敏感词检测 + private Integer isSensitiveDetection; + //数据源id,新建任务后,根据数据源id可以找到对应的数据库,进而找到对应的表 + private Integer dataSourceId; + + + + + + + + + //数据表id,这个是创建的新表的id(根据table_id判断是新增表 or 选择已有表,若table_id存在则是选择已有表,否则是新增表) + private Integer tableId; + //选择已有表时,存储表字段 + private List selectColumnDTO; + + //存储动态建立数据表所用的数据 + private DynamicTableRequestDTO dynamicTableRequestDTO; + + + + + + + + + //编辑任务时,所用属性 + private Integer taskId; + +} diff --git a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java index ec2435b..02fafbc 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java +++ b/backend/src/main/java/com/unionbigdata/teaching/controller/TaskController.java @@ -1,11 +1,13 @@ package com.unionbigdata.teaching.controller; import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; +import com.unionbigdata.teaching.DTO.TaskAddDTO; import com.unionbigdata.teaching.common.Result; import com.unionbigdata.teaching.sevice.ITaskService; import com.unionbigdata.teaching.vo.TaskVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; import java.time.LocalDate; @@ -59,4 +61,15 @@ public class TaskController { public Result dataCollect(@RequestBody DynamicTableRequestDTO dynamicDTO) { return Result.ok(taskService.dataCollect(dynamicDTO)); } + + @PostMapping("/addTask")//新增任务 + public Result taskAdd(@RequestBody TaskAddDTO taskAddDTO) { + if(ObjectUtils.isEmpty(taskAddDTO.getTableId())){//无table_id则要新建表 + return Result.ok(taskService.createTable(taskAddDTO)); + }else {//有table_id则选择已有表 + return Result.ok(taskService.addOrUpdateTaskTableColumnsRelations(taskAddDTO)); + } + } + + //编辑任务(可能会换表,需要删除此任务之前配置的表和关联的columns) } diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java b/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java index b622906..fcd3b64 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/FillDataColumnEntity.java @@ -23,8 +23,16 @@ public class FillDataColumnEntity { @NotNull(message = "字段类型不能为空!") private String columnType; // 对应column_type(字段类型) - private String columnValue; // 对应column_value(字段值) private LocalDateTime createTime; private LocalDateTime updateTime; + // 是否被收藏 + private Integer isCollect; + + //注释或备注 + private String columnComment; + + //数据长度 + private Integer length; + } \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java index 9a1a831..1122fe0 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java +++ b/backend/src/main/java/com/unionbigdata/teaching/entity/Task.java @@ -1,8 +1,6 @@ package com.unionbigdata.teaching.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; @@ -26,7 +24,8 @@ public class Task { private LocalDateTime updateTime; //状态 - private String status; + @TableField(fill = FieldFill.INSERT)//FieldFill.INSERT表示在执行insert语句时才会有默认值“未发布” + private String status = "未发布"; //创建人id private Long creatorId; diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java index 6047824..493273d 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/FillDataColumnMapper.java @@ -1,8 +1,9 @@ package com.unionbigdata.teaching.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.unionbigdata.teaching.DTO.SelectColumnDTO; import com.unionbigdata.teaching.entity.FillDataColumnEntity; -import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.*; import java.util.List; @@ -10,4 +11,69 @@ import java.util.List; public interface FillDataColumnMapper extends BaseMapper { // 根据fill_data_id查询对应的所有字段 List selectByFillDataId(Long fillDataId); + + /** + * 批量插入任务与列的关联关系 + * 使用MyBatis的@Insert注解执行批量插入操作 + * 通过动态SQL构建插入语句,支持一次插入多条记录 + * + * @param taskId 任务ID,用于标识具体的任务 + * @param columnNames 列名列表,包含与任务关联的所有列ID + */ +// 批量插入fill_data_column表(适配List) + @Insert("") + int batchInsertTaskColumnRelation( + @Param("taskId") Integer taskId, + @Param("columnNames") List columnNames + ); + + /** + * 批量更新:仅当isCollect值与数据库不一致时更新(纯UPDATE,不新增) + */ + @Update("") + int batchUpdateTaskColumnRelation( + @Param("taskId") Integer taskId, + @Param("columnNames") List columnNames + ); + + /** + * 根据taskId删除fill_data_column表中对应的所有记录 + * @param taskId 任务ID(不可为null,否则会触发空值防护,不执行删除) + * @return 被删除的记录行数(便于业务层判断删除效果) + */ + @Delete("") + int deleteBatchByTaskId(@Param("taskId") Integer taskId); } \ No newline at end of file diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java index 28e1efc..2ba9b5e 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TableOperateMapper.java @@ -10,7 +10,7 @@ public interface TableOperateMapper { // 原有方法:建表+列表名 @Update("${createTableSql}") void executeCreateTableSql(@Param("createTableSql") String createTableSql); - @Select("SELECT table_name FROM data_table_config WHERE datasource_id = #{id}") + @Select("SELECT table_name FROM data_table_config WHERE data_source_id = #{id}") List listAllTableNames(@Param("id") Long id); // ========== 新增:查询表结构(字段信息) ========== diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java index 7ace959..622ee1e 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java @@ -2,6 +2,14 @@ package com.unionbigdata.teaching.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.unionbigdata.teaching.entity.Task; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Options; public interface TaskMapper extends BaseMapper { + // 入参为Task实体类,和BaseMapper的泛型一致,更规范 + @Insert("insert into task (task_name, version, task_description, is_sensitive_detection, data_source_id, create_time, table_id) " + + "values (#{taskName}, #{version}, #{taskDescription}, #{isSensitiveDetection}, #{dataSourceId}, NOW(), #{tableId}})") + // 回写自增id到Task对象的id字段 + @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") + int insertTask(Task task); } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java index a7bc792..bc6d8b1 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/ITaskService.java @@ -2,6 +2,7 @@ package com.unionbigdata.teaching.sevice; import com.baomidou.mybatisplus.extension.service.IService; import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; +import com.unionbigdata.teaching.DTO.TaskAddDTO; import com.unionbigdata.teaching.entity.Task; import com.unionbigdata.teaching.vo.TaskVO; @@ -31,4 +32,19 @@ public interface ITaskService extends IService { * @return 返回收集到的数据,类型为Object,具体类型取决于实现 */ Object dataCollect(DynamicTableRequestDTO dynamicDTO); + +/** + * 创建数据表的方法 + * @param taskAddDTO 包含任务添加或更新信息的DTO对象 + * @return 返回Boolean类型结果,表示创建操作是否成功 + */ + Boolean createTable(TaskAddDTO taskAddDTO); + +/** + * 更新任务表列关系的方法 + * + * @param taskAddDTO 任务添加数据传输对象,包含任务相关的信息 + * @return 更新操作是否成功,返回Boolean类型表示操作结果 + */ + Boolean addOrUpdateTaskTableColumnsRelations(TaskAddDTO taskAddDTO); } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java index 716b8c0..96a9e98 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/FillDataServiceImpl.java @@ -32,7 +32,6 @@ public class FillDataServiceImpl implements IFillDataService { entity.setTableId(vo.getFillDataId()); entity.setColumnName(vo.getColumnName()); entity.setColumnType(vo.getColumnType()); - entity.setColumnValue(vo.getColumnValue()); return entity; }).collect(Collectors.toList()); @@ -55,7 +54,6 @@ public class FillDataServiceImpl implements IFillDataService { vo.setFillDataId(entity.getTableId()); vo.setColumnName(entity.getColumnName()); vo.setColumnType(entity.getColumnType()); - vo.setColumnValue(entity.getColumnValue()); } return vo; } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java index ed23567..7502c4d 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/SensitiveWordServiceImpl.java @@ -125,21 +125,89 @@ public class SensitiveWordServiceImpl extends ServiceImpl row : tableRows) { +// // 遍历该行的每个字段 +// // 新增:打印当前处理的行号 + 处理前的原始数据(方便对比) +// System.out.println("========== 开始处理第 " + rowNum + " 行数据 =========="); +// System.out.println("处理前的原始数据:" + row); +// // 对每个字段进行处理 +// for (String name : filedName) { +// // 获取字段值(注意类型转换,前端传的是String) +// String fieldValue = (row.get(name) == null) ? "" : row.get(name).toString(); +// // 敏感词替换 +// String replacedValue = sensitiveWordManager.replaceSensitiveWord(fieldValue); +// // 替换后写回Map +// row.put(name, replacedValue); +// } +// // 新增:打印处理后的行数据(对比原始数据,确认敏感词是否替换成功) +// System.out.println("处理后的行数据:" + row); +// System.out.println("========== 第 " + rowNum + " 行数据处理完成 ==========\n"); +// rowNum++; +// } for (Map row : tableRows) { - // 遍历该行的每个字段 - // 新增:打印当前处理的行号 + 处理前的原始数据(方便对比) + // 打印行号和原始数据 System.out.println("========== 开始处理第 " + rowNum + " 行数据 =========="); System.out.println("处理前的原始数据:" + row); - // 对每个字段进行处理 + + // 遍历该行的每个字段 for (String name : filedName) { - // 获取字段值(注意类型转换,前端传的是String) - String fieldValue = (row.get(name) == null) ? "" : row.get(name).toString(); - // 敏感词替换 + Object originalValue = row.get(name); // 先获取原始值(不直接转String) + String fieldValue = ""; + String valueType = ""; // 记录字段值的类型 + + // ========== 核心:判断字段值的具体类型 ========== + if (originalValue == null) { + valueType = "null"; + fieldValue = ""; // null 转空字符串 + } else if (originalValue instanceof String) { + valueType = "String(字符串)"; + fieldValue = (String) originalValue; // 直接强转,避免多余的 toString() + } else if (originalValue instanceof Integer) { + valueType = "Integer(整数)"; + fieldValue = originalValue.toString(); // 数字转字符串(敏感词替换需要字符串) + } else if (originalValue instanceof Double) { + valueType = "Double(浮点数)"; + fieldValue = originalValue.toString(); + } else if (originalValue instanceof Boolean) { + valueType = "Boolean(布尔值)"; + fieldValue = originalValue.toString(); + } else { + // 其他类型(如Long、Float、日期等),统一转String + valueType = originalValue.getClass().getSimpleName() + "(其他类型)"; + fieldValue = originalValue.toString(); + } + + // 打印字段名、类型、原始值(方便调试) + System.out.println("字段名:" + name + " | 类型:" + valueType + " | 原始值:" + originalValue); + + // 敏感词替换(仅针对字符串有效,非字符串类型替换后还是原格式) String replacedValue = sensitiveWordManager.replaceSensitiveWord(fieldValue); - // 替换后写回Map - row.put(name, replacedValue); + + // ========== 可选:将替换后的值转回原类型(如果需要) ========== + Object finalValue = replacedValue; + if (originalValue instanceof Integer) { + try { + finalValue = Integer.parseInt(replacedValue); // 字符串转回整数 + } catch (NumberFormatException e) { + finalValue = originalValue; // 转换失败则保留原值 + System.out.println("字段 " + name + " 替换后无法转回Integer,保留原值:" + originalValue); + } + } else if (originalValue instanceof Double) { + try { + finalValue = Double.parseDouble(replacedValue); + } catch (NumberFormatException e) { + finalValue = originalValue; + System.out.println("字段 " + name + " 替换后无法转回Double,保留原值:" + originalValue); + } + } else if (originalValue instanceof Boolean) { + finalValue = Boolean.parseBoolean(replacedValue); + } + + // 替换后写回Map(保留原类型,更精准) + row.put(name, finalValue); } - // 新增:打印处理后的行数据(对比原始数据,确认敏感词是否替换成功) + + // 打印处理后的行数据 System.out.println("处理后的行数据:" + row); System.out.println("========== 第 " + rowNum + " 行数据处理完成 ==========\n"); rowNum++; diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java index 5ea2cd6..0f19be1 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java @@ -3,16 +3,18 @@ package com.unionbigdata.teaching.sevice.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.unionbigdata.teaching.DTO.DynamicTableRequestDTO; +import com.unionbigdata.teaching.DTO.SelectColumnDTO; +import com.unionbigdata.teaching.DTO.TaskAddDTO; import com.unionbigdata.teaching.entity.DataSource; import com.unionbigdata.teaching.entity.Task; import com.unionbigdata.teaching.mapper.DataSourceMapper; +import com.unionbigdata.teaching.mapper.FillDataColumnMapper; import com.unionbigdata.teaching.mapper.TaskMapper; -import com.unionbigdata.teaching.sevice.ISensitiveWordService; import com.unionbigdata.teaching.sevice.ITaskService; import com.unionbigdata.teaching.vo.DataSourceVO; import com.unionbigdata.teaching.vo.TaskVO; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; @@ -31,6 +33,9 @@ public class TaskServiceImpl extends ServiceImpl implements IT @Resource private DataSourceMapper dataSourceMapper; + @Resource + private FillDataColumnMapper fillDataColumnMapper; + @Override public Map getTaskById(Integer id) { @@ -95,6 +100,58 @@ public class TaskServiceImpl extends ServiceImpl implements IT return null; } + @Override + public Boolean createTable(TaskAddDTO taskAddDTO) { + return null; + } + + @Override + public Boolean addOrUpdateTaskTableColumnsRelations(TaskAddDTO taskAddDTO) { + //获取任务id + Integer taskId = taskAddDTO.getTaskId(); + if(ObjectUtils.isEmpty(taskId)){//新增任务 + //获取需要绑定的表 + //Integer tableId = taskAddDTO.getTableId(); + //获取需要绑定的字段名 + List columnName = taskAddDTO.getSelectColumnDTO(); + + //更新字段名表,将任务与字段名进行绑定 + //先创建任务获取task_id + Task task = new Task(); + BeanUtils.copyProperties(taskAddDTO,task); + int affectRows = taskMapper.insert(task); + if(affectRows > 0){//任务新增成功 + //获取新增任务的task_id + Integer newTaskId = task.getId(); + //再创建字段名表,将字段名与task_id进行绑定 + fillDataColumnMapper.batchInsertTaskColumnRelation(newTaskId,columnName); + return Boolean.TRUE; + } + return Boolean.FALSE; + } + else {//更新任务 + Task existTask = taskMapper.selectById(taskId); + if (ObjectUtils.isEmpty(existTask)) { + throw new RuntimeException("任务不存在,ID:" + taskId); + } + + //删除原有 任务、表、列关系 + Integer lastTableId = taskMapper.selectById(taskAddDTO.getTaskId()).getTableId(); + if(lastTableId == taskAddDTO.getTableId()){//如果表没变,则直接更新字段的采集情况 + //更新字段名表,将任务与字段名进行绑定 + fillDataColumnMapper.batchUpdateTaskColumnRelation(taskId,taskAddDTO.getSelectColumnDTO()); + return Boolean.TRUE; + } + else {//如果表变了,则删除原有任务、表、列关系,再重新创建 + //删除原有任务、表、列关系 + fillDataColumnMapper.deleteBatchByTaskId(taskId); + //创建新任务、表、列关系 + fillDataColumnMapper.batchInsertTaskColumnRelation(taskId,taskAddDTO.getSelectColumnDTO()); + return Boolean.TRUE; + } + } + } + private TaskVO convertTaskVO(Task task) { TaskVO taskVO = new TaskVO(); if (!ObjectUtils.isEmpty(task)) { -- Gitee From 05ce791f70262fb4d6c6c4a1379f05a835d2600c Mon Sep 17 00:00:00 2001 From: HuangJiahui <3236488932@qq.com> Date: Sun, 11 Jan 2026 13:47:28 +0800 Subject: [PATCH 20/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=81=E7=BC=96=E8=BE=91=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/unionbigdata/teaching/mapper/TaskMapper.java | 6 ++++++ .../unionbigdata/teaching/sevice/impl/TaskServiceImpl.java | 2 ++ 2 files changed, 8 insertions(+) diff --git a/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java b/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java index 622ee1e..18088b8 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java +++ b/backend/src/main/java/com/unionbigdata/teaching/mapper/TaskMapper.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.unionbigdata.teaching.entity.Task; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.Update; public interface TaskMapper extends BaseMapper { // 入参为Task实体类,和BaseMapper的泛型一致,更规范 @@ -12,4 +13,9 @@ public interface TaskMapper extends BaseMapper { // 回写自增id到Task对象的id字段 @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") int insertTask(Task task); + + @Update("update task " + + "set table_id = #{tableId} " + + "where id = #{taskId}") + int updateTableIdByTaskId(Integer taskId, Integer tableId); } diff --git a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java index 0f19be1..695a2f1 100644 --- a/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java +++ b/backend/src/main/java/com/unionbigdata/teaching/sevice/impl/TaskServiceImpl.java @@ -145,6 +145,8 @@ public class TaskServiceImpl extends ServiceImpl implements IT else {//如果表变了,则删除原有任务、表、列关系,再重新创建 //删除原有任务、表、列关系 fillDataColumnMapper.deleteBatchByTaskId(taskId); + //修改task表中的表id + taskMapper.updateTableIdByTaskId(taskId,taskAddDTO.getTableId()); //创建新任务、表、列关系 fillDataColumnMapper.batchInsertTaskColumnRelation(taskId,taskAddDTO.getSelectColumnDTO()); return Boolean.TRUE; -- Gitee From 9dcec3264c226b48a849a89ba5b01001b86c086a Mon Sep 17 00:00:00 2001 From: f10s <2010310561@qq.com> Date: Sun, 11 Jan 2026 16:01:20 +0800 Subject: [PATCH 21/44] =?UTF-8?q?fix:=E4=BF=AE=E6=94=B9bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/web-management-react/.gitignore | 23 - frontend/web-management-react/README.md | 57 - frontend/web-management-react/config/env.js | 104 - .../config/getHttpsConfig.js | 66 - .../config/jest/babelTransform.js | 29 - .../config/jest/cssTransform.js | 14 - .../config/jest/fileTransform.js | 40 - .../web-management-react/config/modules.js | 134 - frontend/web-management-react/config/paths.js | 77 - .../config/webpack.config.js | 793 - .../persistentCache/createEnvironmentHash.js | 9 - .../config/webpackDevServer.config.js | 127 - .../web-management-react/package-lock.json | 14185 ---------------- frontend/web-management-react/package.json | 148 - .../web-management-react/public/favicon.ico | Bin 3870 -> 0 bytes .../web-management-react/public/index.html | 43 - .../web-management-react/public/logo192.png | Bin 5347 -> 0 bytes .../web-management-react/public/logo512.png | Bin 9664 -> 0 bytes .../web-management-react/public/manifest.json | 25 - .../web-management-react/public/robots.txt | 3 - .../web-management-react/scripts/build.js | 217 - .../web-management-react/scripts/start.js | 154 - frontend/web-management-react/scripts/test.js | 52 - frontend/web-management-react/src/App.css | 17 - frontend/web-management-react/src/App.js | 49 - frontend/web-management-react/src/App.test.js | 8 - frontend/web-management-react/src/index.css | 13 - frontend/web-management-react/src/index.js | 18 - frontend/web-management-react/src/logo.svg | 1 - .../src/reportWebVitals.js | 13 - .../web-management-react/src/router/data.js | 16 - .../web-management-react/src/router/index.jsx | 26 - .../web-management-react/src/service/index.js | 226 - .../web-management-react/src/service/test.js | 25 - .../web-management-react/src/setupProxy.js | 14 - .../web-management-react/src/setupTests.js | 5 - .../web-management-react/src/utils/index.js | 18 - .../src/views/test/index.jsx | 69 - .../src/views/test/index.scss | 12 - .../src/views/test1/index.css | 0 .../src/views/test1/index.jsx | 9 - frontend/web-management-vue2/.eslintrc.js | 17 - frontend/web-management-vue2/.gitignore | 21 - frontend/web-management-vue2/README.md | 39 - frontend/web-management-vue2/babel.config.js | 5 - .../web-management-vue2/package-lock.json | 13509 --------------- frontend/web-management-vue2/package.json | 55 - frontend/web-management-vue2/pnpm-lock.yaml | 10106 ----------- .../web-management-vue2/public/favicon.ico | Bin 4286 -> 0 bytes .../web-management-vue2/public/index.html | 17 - frontend/web-management-vue2/src/App.vue | 26 - .../web-management-vue2/src/assets/logo.png | Bin 6849 -> 0 bytes .../src/components/HelloWorld.vue | 31 - frontend/web-management-vue2/src/main.js | 24 - .../web-management-vue2/src/router/index.js | 28 - .../web-management-vue2/src/service/index.js | 50 - .../src/views/main/index.vue | 86 - .../src/views/test/index.vue | 24 - frontend/web-management-vue2/vue.config.js | 5 - .../src/views/Data/index.vue | 255 +- 60 files changed, 204 insertions(+), 40933 deletions(-) delete mode 100644 frontend/web-management-react/.gitignore delete mode 100644 frontend/web-management-react/README.md delete mode 100644 frontend/web-management-react/config/env.js delete mode 100644 frontend/web-management-react/config/getHttpsConfig.js delete mode 100644 frontend/web-management-react/config/jest/babelTransform.js delete mode 100644 frontend/web-management-react/config/jest/cssTransform.js delete mode 100644 frontend/web-management-react/config/jest/fileTransform.js delete mode 100644 frontend/web-management-react/config/modules.js delete mode 100644 frontend/web-management-react/config/paths.js delete mode 100644 frontend/web-management-react/config/webpack.config.js delete mode 100644 frontend/web-management-react/config/webpack/persistentCache/createEnvironmentHash.js delete mode 100644 frontend/web-management-react/config/webpackDevServer.config.js delete mode 100644 frontend/web-management-react/package-lock.json delete mode 100644 frontend/web-management-react/package.json delete mode 100644 frontend/web-management-react/public/favicon.ico delete mode 100644 frontend/web-management-react/public/index.html delete mode 100644 frontend/web-management-react/public/logo192.png delete mode 100644 frontend/web-management-react/public/logo512.png delete mode 100644 frontend/web-management-react/public/manifest.json delete mode 100644 frontend/web-management-react/public/robots.txt delete mode 100644 frontend/web-management-react/scripts/build.js delete mode 100644 frontend/web-management-react/scripts/start.js delete mode 100644 frontend/web-management-react/scripts/test.js delete mode 100644 frontend/web-management-react/src/App.css delete mode 100644 frontend/web-management-react/src/App.js delete mode 100644 frontend/web-management-react/src/App.test.js delete mode 100644 frontend/web-management-react/src/index.css delete mode 100644 frontend/web-management-react/src/index.js delete mode 100644 frontend/web-management-react/src/logo.svg delete mode 100644 frontend/web-management-react/src/reportWebVitals.js delete mode 100644 frontend/web-management-react/src/router/data.js delete mode 100644 frontend/web-management-react/src/router/index.jsx delete mode 100644 frontend/web-management-react/src/service/index.js delete mode 100644 frontend/web-management-react/src/service/test.js delete mode 100644 frontend/web-management-react/src/setupProxy.js delete mode 100644 frontend/web-management-react/src/setupTests.js delete mode 100644 frontend/web-management-react/src/utils/index.js delete mode 100644 frontend/web-management-react/src/views/test/index.jsx delete mode 100644 frontend/web-management-react/src/views/test/index.scss delete mode 100644 frontend/web-management-react/src/views/test1/index.css delete mode 100644 frontend/web-management-react/src/views/test1/index.jsx delete mode 100644 frontend/web-management-vue2/.eslintrc.js delete mode 100644 frontend/web-management-vue2/.gitignore delete mode 100644 frontend/web-management-vue2/README.md delete mode 100644 frontend/web-management-vue2/babel.config.js delete mode 100644 frontend/web-management-vue2/package-lock.json delete mode 100644 frontend/web-management-vue2/package.json delete mode 100644 frontend/web-management-vue2/pnpm-lock.yaml delete mode 100644 frontend/web-management-vue2/public/favicon.ico delete mode 100644 frontend/web-management-vue2/public/index.html delete mode 100644 frontend/web-management-vue2/src/App.vue delete mode 100644 frontend/web-management-vue2/src/assets/logo.png delete mode 100644 frontend/web-management-vue2/src/components/HelloWorld.vue delete mode 100644 frontend/web-management-vue2/src/main.js delete mode 100644 frontend/web-management-vue2/src/router/index.js delete mode 100644 frontend/web-management-vue2/src/service/index.js delete mode 100644 frontend/web-management-vue2/src/views/main/index.vue delete mode 100644 frontend/web-management-vue2/src/views/test/index.vue delete mode 100644 frontend/web-management-vue2/vue.config.js diff --git a/frontend/web-management-react/.gitignore b/frontend/web-management-react/.gitignore deleted file mode 100644 index 4d29575..0000000 --- a/frontend/web-management-react/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/frontend/web-management-react/README.md b/frontend/web-management-react/README.md deleted file mode 100644 index 7aae9f3..0000000 --- a/frontend/web-management-react/README.md +++ /dev/null @@ -1,57 +0,0 @@ -react前端框架 - -前端编译工具:vscode -node 版本建议 v14.18.1 -npm 版本建议 6.14.15 - - -### 1.技术栈 -react 18 + hook + router6 + antd5 + axios - -react v18 -react-router v6 (路由) -antd v4 (ui组件库) -axios (http请求) - -### 2.项目启动 - -npm i 安装依赖 -npm start 启动项目 - -npm config set registry https://registry.npmmirror.com/ 如果执行npm i 太慢可以设置淘宝镜像 - - -### 3.项目结构 - -src - | - router 页面路由 - | - service 接口请求 - | - view 页面 - | setupProxy.js 代理服务处理跨域 - -### 4.hook使用 -useState 声明状态变量 -useEffect 组件渲染时执行 / 依赖值变化时执行 - -使用案例 -` -const [state, setState] = useState(initialState); -state: 声明变量值 -setState: 更新变量方法 -setState: 设置初始值,默认null - -案例:const [num, setNum] = useState(1); -` -` - useEffect(()=>{ - // 首次渲染时执行 - },[]) - - useEffect(()=>{ - // 依赖值data 变化时执行 - },[data]) -` -### 5.网址 - -react 简单学习网站:https://react.docschina.org/learn/writing-markup-with-jsx -antd 网站地址:https://ant-design.antgroup.com/docs/react/introduce-cn \ No newline at end of file diff --git a/frontend/web-management-react/config/env.js b/frontend/web-management-react/config/env.js deleted file mode 100644 index ffa7e49..0000000 --- a/frontend/web-management-react/config/env.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const paths = require('./paths'); - -// Make sure that including paths.js after env.js will read .env variables. -delete require.cache[require.resolve('./paths')]; - -const NODE_ENV = process.env.NODE_ENV; -if (!NODE_ENV) { - throw new Error( - 'The NODE_ENV environment variable is required but was not specified.' - ); -} - -// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use -const dotenvFiles = [ - `${paths.dotenv}.${NODE_ENV}.local`, - // Don't include `.env.local` for `test` environment - // since normally you expect tests to produce the same - // results for everyone - NODE_ENV !== 'test' && `${paths.dotenv}.local`, - `${paths.dotenv}.${NODE_ENV}`, - paths.dotenv, -].filter(Boolean); - -// Load environment variables from .env* files. Suppress warnings using silent -// if this file is missing. dotenv will never modify any environment variables -// that have already been set. Variable expansion is supported in .env files. -// https://github.com/motdotla/dotenv -// https://github.com/motdotla/dotenv-expand -dotenvFiles.forEach(dotenvFile => { - if (fs.existsSync(dotenvFile)) { - require('dotenv-expand')( - require('dotenv').config({ - path: dotenvFile, - }) - ); - } -}); - -// We support resolving modules according to `NODE_PATH`. -// This lets you use absolute paths in imports inside large monorepos: -// https://github.com/facebook/create-react-app/issues/253. -// It works similar to `NODE_PATH` in Node itself: -// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders -// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. -// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims. -// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 -// We also resolve them to make sure all tools using them work consistently. -const appDirectory = fs.realpathSync(process.cwd()); -process.env.NODE_PATH = (process.env.NODE_PATH || '') - .split(path.delimiter) - .filter(folder => folder && !path.isAbsolute(folder)) - .map(folder => path.resolve(appDirectory, folder)) - .join(path.delimiter); - -// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be -// injected into the application via DefinePlugin in webpack configuration. -const REACT_APP = /^REACT_APP_/i; - -function getClientEnvironment(publicUrl) { - const raw = Object.keys(process.env) - .filter(key => REACT_APP.test(key)) - .reduce( - (env, key) => { - env[key] = process.env[key]; - return env; - }, - { - // Useful for determining whether we’re running in production mode. - // Most importantly, it switches React into the correct mode. - NODE_ENV: process.env.NODE_ENV || 'development', - // Useful for resolving the correct path to static assets in `public`. - // For example, . - // This should only be used as an escape hatch. Normally you would put - // images into the `src` and `import` them in code to get their paths. - PUBLIC_URL: publicUrl, - // We support configuring the sockjs pathname during development. - // These settings let a developer run multiple simultaneous projects. - // They are used as the connection `hostname`, `pathname` and `port` - // in webpackHotDevClient. They are used as the `sockHost`, `sockPath` - // and `sockPort` options in webpack-dev-server. - WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST, - WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH, - WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT, - // Whether or not react-refresh is enabled. - // It is defined here so it is available in the webpackHotDevClient. - FAST_REFRESH: process.env.FAST_REFRESH !== 'false', - } - ); - // Stringify all values so we can feed into webpack DefinePlugin - const stringified = { - 'process.env': Object.keys(raw).reduce((env, key) => { - env[key] = JSON.stringify(raw[key]); - return env; - }, {}), - }; - - return { raw, stringified }; -} - -module.exports = getClientEnvironment; diff --git a/frontend/web-management-react/config/getHttpsConfig.js b/frontend/web-management-react/config/getHttpsConfig.js deleted file mode 100644 index 013d493..0000000 --- a/frontend/web-management-react/config/getHttpsConfig.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const crypto = require('crypto'); -const chalk = require('react-dev-utils/chalk'); -const paths = require('./paths'); - -// Ensure the certificate and key provided are valid and if not -// throw an easy to debug error -function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { - let encrypted; - try { - // publicEncrypt will throw an error with an invalid cert - encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); - } catch (err) { - throw new Error( - `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}` - ); - } - - try { - // privateDecrypt will throw an error with an invalid key - crypto.privateDecrypt(key, encrypted); - } catch (err) { - throw new Error( - `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${ - err.message - }` - ); - } -} - -// Read file and throw an error if it doesn't exist -function readEnvFile(file, type) { - if (!fs.existsSync(file)) { - throw new Error( - `You specified ${chalk.cyan( - type - )} in your env, but the file "${chalk.yellow(file)}" can't be found.` - ); - } - return fs.readFileSync(file); -} - -// Get the https config -// Return cert files if provided in env, otherwise just true or false -function getHttpsConfig() { - const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; - const isHttps = HTTPS === 'true'; - - if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { - const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE); - const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE); - const config = { - cert: readEnvFile(crtFile, 'SSL_CRT_FILE'), - key: readEnvFile(keyFile, 'SSL_KEY_FILE'), - }; - - validateKeyAndCerts({ ...config, keyFile, crtFile }); - return config; - } - return isHttps; -} - -module.exports = getHttpsConfig; diff --git a/frontend/web-management-react/config/jest/babelTransform.js b/frontend/web-management-react/config/jest/babelTransform.js deleted file mode 100644 index 5b391e4..0000000 --- a/frontend/web-management-react/config/jest/babelTransform.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -const babelJest = require('babel-jest').default; - -const hasJsxRuntime = (() => { - if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { - return false; - } - - try { - require.resolve('react/jsx-runtime'); - return true; - } catch (e) { - return false; - } -})(); - -module.exports = babelJest.createTransformer({ - presets: [ - [ - require.resolve('babel-preset-react-app'), - { - runtime: hasJsxRuntime ? 'automatic' : 'classic', - }, - ], - ], - babelrc: false, - configFile: false, -}); diff --git a/frontend/web-management-react/config/jest/cssTransform.js b/frontend/web-management-react/config/jest/cssTransform.js deleted file mode 100644 index 8f65114..0000000 --- a/frontend/web-management-react/config/jest/cssTransform.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -// This is a custom Jest transformer turning style imports into empty objects. -// http://facebook.github.io/jest/docs/en/webpack.html - -module.exports = { - process() { - return 'module.exports = {};'; - }, - getCacheKey() { - // The output is always the same. - return 'cssTransform'; - }, -}; diff --git a/frontend/web-management-react/config/jest/fileTransform.js b/frontend/web-management-react/config/jest/fileTransform.js deleted file mode 100644 index aab6761..0000000 --- a/frontend/web-management-react/config/jest/fileTransform.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -const path = require('path'); -const camelcase = require('camelcase'); - -// This is a custom Jest transformer turning file imports into filenames. -// http://facebook.github.io/jest/docs/en/webpack.html - -module.exports = { - process(src, filename) { - const assetFilename = JSON.stringify(path.basename(filename)); - - if (filename.match(/\.svg$/)) { - // Based on how SVGR generates a component name: - // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 - const pascalCaseFilename = camelcase(path.parse(filename).name, { - pascalCase: true, - }); - const componentName = `Svg${pascalCaseFilename}`; - return `const React = require('react'); - module.exports = { - __esModule: true, - default: ${assetFilename}, - ReactComponent: React.forwardRef(function ${componentName}(props, ref) { - return { - $$typeof: Symbol.for('react.element'), - type: 'svg', - ref: ref, - key: null, - props: Object.assign({}, props, { - children: ${assetFilename} - }) - }; - }), - };`; - } - - return `module.exports = ${assetFilename};`; - }, -}; diff --git a/frontend/web-management-react/config/modules.js b/frontend/web-management-react/config/modules.js deleted file mode 100644 index d63e41d..0000000 --- a/frontend/web-management-react/config/modules.js +++ /dev/null @@ -1,134 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const paths = require('./paths'); -const chalk = require('react-dev-utils/chalk'); -const resolve = require('resolve'); - -/** - * Get additional module paths based on the baseUrl of a compilerOptions object. - * - * @param {Object} options - */ -function getAdditionalModulePaths(options = {}) { - const baseUrl = options.baseUrl; - - if (!baseUrl) { - return ''; - } - - const baseUrlResolved = path.resolve(paths.appPath, baseUrl); - - // We don't need to do anything if `baseUrl` is set to `node_modules`. This is - // the default behavior. - if (path.relative(paths.appNodeModules, baseUrlResolved) === '') { - return null; - } - - // Allow the user set the `baseUrl` to `appSrc`. - if (path.relative(paths.appSrc, baseUrlResolved) === '') { - return [paths.appSrc]; - } - - // If the path is equal to the root directory we ignore it here. - // We don't want to allow importing from the root directly as source files are - // not transpiled outside of `src`. We do allow importing them with the - // absolute path (e.g. `src/Components/Button.js`) but we set that up with - // an alias. - if (path.relative(paths.appPath, baseUrlResolved) === '') { - return null; - } - - // Otherwise, throw an error. - throw new Error( - chalk.red.bold( - "Your project's `baseUrl` can only be set to `src` or `node_modules`." + - ' Create React App does not support other values at this time.' - ) - ); -} - -/** - * Get webpack aliases based on the baseUrl of a compilerOptions object. - * - * @param {*} options - */ -function getWebpackAliases(options = {}) { - const baseUrl = options.baseUrl; - - if (!baseUrl) { - return {}; - } - - const baseUrlResolved = path.resolve(paths.appPath, baseUrl); - - if (path.relative(paths.appPath, baseUrlResolved) === '') { - return { - src: paths.appSrc, - }; - } -} - -/** - * Get jest aliases based on the baseUrl of a compilerOptions object. - * - * @param {*} options - */ -function getJestAliases(options = {}) { - const baseUrl = options.baseUrl; - - if (!baseUrl) { - return {}; - } - - const baseUrlResolved = path.resolve(paths.appPath, baseUrl); - - if (path.relative(paths.appPath, baseUrlResolved) === '') { - return { - '^src/(.*)$': '/src/$1', - }; - } -} - -function getModules() { - // Check if TypeScript is setup - const hasTsConfig = fs.existsSync(paths.appTsConfig); - const hasJsConfig = fs.existsSync(paths.appJsConfig); - - if (hasTsConfig && hasJsConfig) { - throw new Error( - 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.' - ); - } - - let config; - - // If there's a tsconfig.json we assume it's a - // TypeScript project and set up the config - // based on tsconfig.json - if (hasTsConfig) { - const ts = require(resolve.sync('typescript', { - basedir: paths.appNodeModules, - })); - config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config; - // Otherwise we'll check if there is jsconfig.json - // for non TS projects. - } else if (hasJsConfig) { - config = require(paths.appJsConfig); - } - - config = config || {}; - const options = config.compilerOptions || {}; - - const additionalModulePaths = getAdditionalModulePaths(options); - - return { - additionalModulePaths: additionalModulePaths, - webpackAliases: getWebpackAliases(options), - jestAliases: getJestAliases(options), - hasTsConfig, - }; -} - -module.exports = getModules(); diff --git a/frontend/web-management-react/config/paths.js b/frontend/web-management-react/config/paths.js deleted file mode 100644 index f0a6cd9..0000000 --- a/frontend/web-management-react/config/paths.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath'); - -// Make sure any symlinks in the project folder are resolved: -// https://github.com/facebook/create-react-app/issues/637 -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = relativePath => path.resolve(appDirectory, relativePath); - -// We use `PUBLIC_URL` environment variable or "homepage" field to infer -// "public path" at which the app is served. -// webpack needs to know it to put the right - - diff --git a/frontend/web-management-vue2/src/assets/logo.png b/frontend/web-management-vue2/src/assets/logo.png deleted file mode 100644 index f3d2503fc2a44b5053b0837ebea6e87a2d339a43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*V
这里是采集任务的核心功能区,可查看任务列表、执行状态、手动触发采集等。
这里是质检结果库的核心功能区,可查看质检记录、统计分析、导出报告等。
这里是任务制定的核心功能区,可添加任务配置、规则设置等内容。
Rz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*V