From 1393dfcf5b8b67180a776ab8591ca90996054da5 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Mon, 04 Aug 2025 15:46:49 +0800 Subject: [PATCH] feat(product): 添加 AI 题目配置功能 --- src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java | 4 src/main/java/cc/mrbird/febs/ai/service/AiProductService.java | 2 src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLinkService.java | 4 src/main/java/cc/mrbird/febs/ai/controller/product/ViewController.java | 45 +++++++++ src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java | 10 + src/main/resources/templates/febs/views/modules/ai/product/productQuestionSet.html | 128 +++++++++++++++++++++++++ src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLinkServiceImpl.java | 11 ++ src/main/java/cc/mrbird/febs/ai/service/impl/AiProductServiceImpl.java | 31 +++++ src/main/resources/templates/febs/views/modules/ai/product/list.html | 19 +++ src/main/java/cc/mrbird/febs/ai/controller/product/AiProductController.java | 8 + 10 files changed, 254 insertions(+), 8 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/controller/product/AiProductController.java b/src/main/java/cc/mrbird/febs/ai/controller/product/AiProductController.java index da982f3..816ca69 100644 --- a/src/main/java/cc/mrbird/febs/ai/controller/product/AiProductController.java +++ b/src/main/java/cc/mrbird/febs/ai/controller/product/AiProductController.java @@ -84,4 +84,12 @@ return aiProductService.productRoleSet(dto); } + + + @PostMapping("productQuestionSet") + @ControllerEndpoint(operation = "AI题目配置", exceptionMessage = "操作失败") + public FebsResponse productQuestionSet(@RequestBody @Valid AdminMoveChooseInfoDto dto) { + + return aiProductService.productQuestionSet(dto); + } } diff --git a/src/main/java/cc/mrbird/febs/ai/controller/product/ViewController.java b/src/main/java/cc/mrbird/febs/ai/controller/product/ViewController.java index 6a43ac0..7f874d9 100644 --- a/src/main/java/cc/mrbird/febs/ai/controller/product/ViewController.java +++ b/src/main/java/cc/mrbird/febs/ai/controller/product/ViewController.java @@ -37,6 +37,8 @@ private final AiProductPointLinkService aiProductPointLinkService; private final AiProductPointService aiProductPointService; private final AiProductRoleLinkService aiProductRoleLinkService; + private final AiProductQuestionLinkService aiProductQuestionLinkService; + private final AiProductQuestionService aiProductQuestionService; private final AiProductRoleService aiProductRoleService; @GetMapping("list") @@ -140,4 +142,47 @@ model.addAttribute("chooseId", id); return FebsUtil.view("modules/ai/product/productRoleSet"); } + + + + @GetMapping("productQuestionSet/{id}") + @RequiresPermissions("productList:productQuestionSet") + public String productQuestionSet(@PathVariable String id, Model model) { + List<AdminMoveChooseInfoVo> vos = new ArrayList<>(); + Set<String> productIds = new HashSet<>(); + + AiProduct entity = aiProductService.getById(id); + if(ObjectUtil.isNotNull(entity)){ + //右侧数据 + LambdaQueryWrapper<AiProductQuestionLink> query = Wrappers.lambdaQuery(AiProductQuestionLink.class); + if(StrUtil.isNotEmpty(id)){ + query.eq(AiProductQuestionLink::getProductId, id); + } + List<AiProductQuestionLink> selectedList = aiProductQuestionLinkService.selectListByQuery(query); + if(CollUtil.isNotEmpty(selectedList)){ + //stream流操作happyMemberLabelRecords,获取memberId的set集合 + productIds = selectedList.stream().map(AiProductQuestionLink::getProductQuestionId).collect(Collectors.toSet()); + } + + //左侧数据 + LambdaQueryWrapper<AiProductQuestion> aiProductQuestionLambdaQueryWrapper = Wrappers.lambdaQuery(AiProductQuestion.class); + aiProductQuestionLambdaQueryWrapper.eq(AiProductQuestion::getProductCategoryId, entity.getProductCategoryId()); + aiProductQuestionLambdaQueryWrapper.eq(AiProductQuestion::getState, 1); + List<AiProductQuestion> allList = aiProductQuestionService.productQuestionTree(aiProductQuestionLambdaQueryWrapper); + if(CollUtil.isNotEmpty(allList)){ + //stream流操作mallMembers,生成一个新的List<MallMemberVo> + vos = allList.stream().map(AiProductQuestion -> { + AdminMoveChooseInfoVo vo = new AdminMoveChooseInfoVo(); + vo.setId(AiProductQuestion.getId()); + vo.setName(AiProductQuestion.getTitle()); + return vo; + }).collect(Collectors.toList()); + } + } + + model.addAttribute("productQuestionAll", vos); + model.addAttribute("productQuestionSelected", productIds); + model.addAttribute("chooseId", id); + return FebsUtil.view("modules/ai/product/productQuestionSet"); + } } diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLinkService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLinkService.java index 8a7ea6d..0193a77 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLinkService.java +++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLinkService.java @@ -1,6 +1,7 @@ package cc.mrbird.febs.ai.service; import cc.mrbird.febs.ai.entity.AiProductQuestionLink; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -20,4 +21,7 @@ AiProductQuestionLink getById(String id); + List<AiProductQuestionLink> selectListByQuery(LambdaQueryWrapper<AiProductQuestionLink> query); + + void deleteByQuery(LambdaQueryWrapper<AiProductQuestionLink> eq); } diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java index f9b6212..203750c 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java +++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java @@ -1,8 +1,10 @@ package cc.mrbird.febs.ai.service; import cc.mrbird.febs.ai.entity.AiProductQuestion; +import cc.mrbird.febs.ai.entity.AiProductRole; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -33,4 +35,6 @@ FebsResponse delete(String id); List<AiProductQuestion> questionTree(); + + List<AiProductQuestion> productQuestionTree(LambdaQueryWrapper<AiProductQuestion> aiProductQuestionLambdaQueryWrapper); } diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductService.java index 0622299..06321a9 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/AiProductService.java +++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductService.java @@ -39,4 +39,6 @@ FebsResponse productSet(AdminMoveChooseInfoDto dto); FebsResponse productRoleSet(AdminMoveChooseInfoDto dto); + + FebsResponse productQuestionSet(AdminMoveChooseInfoDto dto); } diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLinkServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLinkServiceImpl.java index 1bc9905..4db310b 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLinkServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLinkServiceImpl.java @@ -30,4 +30,15 @@ return aiProductQuestionLinkMapper.selectById(id); } + @Override + public List<AiProductQuestionLink> selectListByQuery(LambdaQueryWrapper<AiProductQuestionLink> query) { + + return aiProductQuestionLinkMapper.selectList(query); + } + + @Override + public void deleteByQuery(LambdaQueryWrapper<AiProductQuestionLink> eq) { + aiProductQuestionLinkMapper.delete( eq); + } + } diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java index cdea318..e8009fa 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java @@ -1,9 +1,6 @@ package cc.mrbird.febs.ai.service.impl; -import cc.mrbird.febs.ai.entity.AiMemberRole; -import cc.mrbird.febs.ai.entity.AiProductPoint; -import cc.mrbird.febs.ai.entity.AiProductQuestion; -import cc.mrbird.febs.ai.entity.AiProductQuestionItem; +import cc.mrbird.febs.ai.entity.*; import cc.mrbird.febs.ai.mapper.AiProductQuestionMapper; import cc.mrbird.febs.ai.service.AiProductQuestionItemService; import cc.mrbird.febs.ai.service.AiProductQuestionService; @@ -160,4 +157,9 @@ return aiProductQuestionMapper.selectList(null); } + @Override + public List<AiProductQuestion> productQuestionTree(LambdaQueryWrapper<AiProductQuestion> aiProductQuestionLambdaQueryWrapper) { + return aiProductQuestionMapper.selectList(aiProductQuestionLambdaQueryWrapper); + } + } diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductServiceImpl.java index 9ac7ab2..5ab494e 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductServiceImpl.java @@ -3,10 +3,7 @@ import cc.mrbird.febs.ai.entity.*; import cc.mrbird.febs.ai.mapper.AiProductMapper; import cc.mrbird.febs.ai.req.AdminMoveChooseInfoDto; -import cc.mrbird.febs.ai.service.AiProductCategoryService; -import cc.mrbird.febs.ai.service.AiProductPointLinkService; -import cc.mrbird.febs.ai.service.AiProductRoleLinkService; -import cc.mrbird.febs.ai.service.AiProductService; +import cc.mrbird.febs.ai.service.*; import cc.mrbird.febs.ai.util.UUID; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; @@ -43,6 +40,7 @@ private final AiProductCategoryService aiProductCategoryService; private final AiProductPointLinkService aiProductPointLinkService; private final AiProductRoleLinkService aiProductRoleLinkService; + private final AiProductQuestionLinkService aiProductQuestionLinkService; @Override public AiProduct getById(String id) { @@ -218,4 +216,29 @@ } return new FebsResponse().success().message("操作成功"); } + + @Override + public FebsResponse productQuestionSet(AdminMoveChooseInfoDto dto) { + String chooseId = dto.getChooseId(); + List<String> chooseIds = dto.getChooseIds(); + AiProduct aiProduct = this.getById(chooseId); + if (ObjectUtil.isNotNull(aiProduct)) { + aiProductQuestionLinkService.deleteByQuery( + Wrappers.lambdaQuery(AiProductQuestionLink.class) + .eq(AiProductQuestionLink::getProductId,chooseId) + ); + if(CollUtil.isNotEmpty(chooseIds)){ + Date createdTime = new Date(); + for (String item : chooseIds){ + AiProductQuestionLink entity = new AiProductQuestionLink(); + entity.setId(UUID.getSimpleUUIDString()); + entity.setProductId(chooseId); + entity.setProductQuestionId(item); + entity.setCreatedTime(createdTime); + aiProductQuestionLinkService.getBaseMapper().insert(entity); + } + } + } + return new FebsResponse().success().message("操作成功"); + } } diff --git a/src/main/resources/templates/febs/views/modules/ai/product/list.html b/src/main/resources/templates/febs/views/modules/ai/product/list.html index ebd5512..a41f5f6 100644 --- a/src/main/resources/templates/febs/views/modules/ai/product/list.html +++ b/src/main/resources/templates/febs/views/modules/ai/product/list.html @@ -54,6 +54,7 @@ <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productList:add" lay-event="productAdd">新增</button> <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productList:pointSet" lay-event="pointSet">知识点配置</button> <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productList:productRoleSet" lay-event="productRoleSet">AI陪练配置</button> + <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productList:productQuestionSet" lay-event="productQuestionSet">AI题目配置</button> </div> </script> @@ -282,6 +283,24 @@ } }); } + + if (layEvent === 'productQuestionSet') { + var checkData = table.checkStatus('productTable').data; + if (checkData.length > 1 || checkData.length === 0) { + febs.alert.warn('每次操作只能操作一行数据'); + return; + } + febs.modal.open('AI题目配置', 'modules/ai/product/productQuestionSet/' + checkData[0].id, { + btn: ['提交', '取消'], + area:['100%','100%'], + yes: function (index, layero) { + $('#productQuestion-set').find('#submit').trigger('click'); + }, + btn2: function () { + layer.closeAll(); + } + }); + } }); function initproductTable() { diff --git a/src/main/resources/templates/febs/views/modules/ai/product/productQuestionSet.html b/src/main/resources/templates/febs/views/modules/ai/product/productQuestionSet.html new file mode 100644 index 0000000..918d9cd --- /dev/null +++ b/src/main/resources/templates/febs/views/modules/ai/product/productQuestionSet.html @@ -0,0 +1,128 @@ +<div class="layui-fluid layui-anim febs-anim" id="productQuestion-set" lay-title="AI题目配置"> + <div class="layui-row febs-container"> + <div class="layui-col-md12"> + <div class="layui-fluid" id="productQuestion-type-set"> + <form class="layui-form" action="" lay-filter="productQuestion-type-set-form"> + <div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief"> + <ul class="layui-tab-title"> + <li class="layui-this">题目配置</li> + </ul> + <div class="layui-tab-content"> + <input type="text" name="chooseId" + placeholder="" autoComplete="off" class="layui-input febs-hide"> + <div class="layui-tab-item layui-show"> + <div class="layui-form-item"> + <div id="productQuestionSetMove"></div> + </div> + </div> + </div> + </div> + <div class="layui-form-item febs-hide"> + <button class="layui-btn" lay-submit="" lay-filter="productQuestion-type-set-form-submit" id="submit">保存</button> + </div> + </form> + </div> + </div> + </div> +</div> + +<script data-th-inline="javascript"> + layui.use(['febs','form', 'transfer'], function () { + var $ = layui.jquery, + febs = layui.febs, + layer = layui.layer, + form = layui.form, + transfer = layui.transfer, + productQuestionTypeAll = [[${productQuestionAll}]], + productQuestionTypeChoose = [[${productQuestionSelected}]], + chooseId = [[${chooseId}]], + $view = $('#productQuestion-set'), + + $productQuestionSetMoveQuery = $view.find('#productQuestionSetMoveQuery') + ; + + // 查询按钮 + $productQuestionSetMoveQuery.on('click', function () { + console.log(transfer.getData('productQuestionSetMove-set')) + + let data1 = transfer.getData('productQuestionSetMove-set'); + //获取data1中的value,返回一个数组 + let productQuestionIdList = data1.map(function(item){ + return item.value; + }); + + console.log(productQuestionIdList) + }); + + + form.render(); + + initproductQuestionTypeSet(); + + function initproductQuestionTypeSet() { + console.log("productQuestionTypeAll:", productQuestionTypeAll); // 调试信息 + console.log("productQuestionTypeChoose:", productQuestionTypeChoose); // 调试信息 + console.log("chooseId:", chooseId); // 调试信息 + form.val("productQuestion-type-set-form", { + "chooseId": chooseId, + }); + // 转换数据格式(假设接口返回的数据结构需要处理) + var dataLeft = productQuestionTypeAll.map(function(item){ + return { + value: item.id, // 值字段 + title: item.name // 显示文本 + } + }); + var dataRight = productQuestionTypeChoose.map(function(item){ + return { + value: item, // 值字段 + } + }); + + // 渲染穿梭框 + transfer.render({ + elem: '#productQuestionSetMove', + data: dataLeft, + id: 'productQuestionSetMove-set', // 唯一标识 + title: ['待选择列表', '已选择列表'], + width: 300, + height: 400, + showSearch: true, + value: productQuestionTypeChoose, + }); + } + + form.on('submit(productQuestion-type-set-form-submit)', function (data) { + let data1 = transfer.getData('productQuestionSetMove-set'); + //获取data1中的value,返回一个数组 + let productQuestionIdList = data1.map(function(item){ + return item.value; + }); + data.field.chooseIds = productQuestionIdList; + data.field.chooseId = chooseId; + $.ajax({ + 'url':ctx + 'admin/product/productQuestionSet', + 'type':'post', + 'dataType':'json', + 'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式 + 'traditional': true,//ajax传递数组必须添加属性 + 'data':JSON.stringify(data.field), + 'success':function (data) { + if(data.code==200){ + layer.closeAll(); + febs.alert.success(data.message); + $('#febs-type').find('#query').click(); + }else{ + febs.alert.warn(data.message); + } + }, + 'error':function () { + febs.alert.warn('服务器繁忙'); + } + }) + return false; + }); + + + }); +</script> \ No newline at end of file -- Gitblit v1.9.1