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