From 29674c95a7c1f57233c4182a72d01917a0be9689 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Thu, 05 Feb 2026 10:36:54 +0800
Subject: [PATCH] feat(ai): 添加产品问答标签功能

---
 src/main/java/cc/mrbird/febs/ai/controller/productQuestionLabel/AiProductQuestionLabelController.java |    9 ++
 src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java                                 |    2 
 src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java                        |   13 +++
 src/main/java/cc/mrbird/febs/ai/controller/product/ViewController.java                                |    8 +
 src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java                        |   14 +++
 src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java           |    7 +
 src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLabelService.java                            |    3 
 src/main/resources/templates/febs/views/modules/ai/productQuestion/list.html                          |   24 ++++++
 src/main/resources/templates/febs/views/modules/ai/productQuestion/labelSet.html                      |  105 ++++++++++++++++++++++++++
 src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLabelServiceImpl.java                   |   11 ++
 10 files changed, 195 insertions(+), 1 deletions(-)

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 d56592e..7655652 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
@@ -182,8 +182,14 @@
                 vos = allList.stream().map(AiProductQuestion -> {
                     AdminMoveChooseInfoVo vo = new AdminMoveChooseInfoVo();
                     vo.setId(AiProductQuestion.getId());
+                    String name = AiProductQuestion.getTitle();
                     String difficulty = AiProductQuestion.getDifficulty() == 1 ? "简单" : AiProductQuestion.getDifficulty() == 2 ? "中等" : "困难";
-                    vo.setName(difficulty+"-"+AiProductQuestion.getTitle());
+                    name = difficulty+"-"+name;
+                    String label = AiProductQuestion.getLabel();
+                    if (StrUtil.isNotEmpty(label)){
+                        name = label+"-"+name;
+                    }
+                    vo.setName(name);
                     return vo;
                 }).collect(Collectors.toList());
             }
diff --git a/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java b/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java
index 075ec0a..e94209a 100644
--- a/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java
+++ b/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java
@@ -146,4 +146,11 @@
     public FebsResponse importDeliver(@RequestBody MultipartFile file){
         return aiProductQuestionService.importDeliver(file);
     }
+
+    @PostMapping("updateLabel")
+    @ControllerEndpoint(operation = "更新标签", exceptionMessage = "操作失败")
+    public FebsResponse updateLabel(@RequestBody @Valid AiProductQuestion dto) {
+
+        return aiProductQuestionService.updateLabel(dto.getIds(), dto.getLabel());
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java b/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java
index 06ce0ad..564a4d4 100644
--- a/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java
+++ b/src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java
@@ -7,6 +7,7 @@
 import cc.mrbird.febs.ai.service.AiProductQuestionService;
 import cc.mrbird.febs.common.entity.FebsConstant;
 import cc.mrbird.febs.common.utils.FebsUtil;
+import cc.mrbird.febs.mall.entity.MallMember;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
@@ -17,7 +18,9 @@
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author Administrator
@@ -72,4 +75,14 @@
         model.addAttribute("aiProductQuestion", entity);
         return FebsUtil.view("modules/ai/productQuestion/info");
     }
+
+
+    @GetMapping("labelSet/{strIds}")
+    @RequiresPermissions("productQuestionList:labelSet")
+    public String vipLevelSetting(@PathVariable(value = "strIds") String strIds, Model model) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("ids", strIds);
+        model.addAttribute("labelSet", data);
+        return FebsUtil.view("modules/ai/productQuestion/labelSet");
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/controller/productQuestionLabel/AiProductQuestionLabelController.java b/src/main/java/cc/mrbird/febs/ai/controller/productQuestionLabel/AiProductQuestionLabelController.java
index de10253..0d6a72d 100644
--- a/src/main/java/cc/mrbird/febs/ai/controller/productQuestionLabel/AiProductQuestionLabelController.java
+++ b/src/main/java/cc/mrbird/febs/ai/controller/productQuestionLabel/AiProductQuestionLabelController.java
@@ -14,6 +14,7 @@
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -51,4 +52,12 @@
 
         return aiProductQuestionLabelService.update(dto);
     }
+
+    @GetMapping("listAll")
+    @ControllerEndpoint(operation = "获取所有标签", exceptionMessage = "获取标签失败")
+    public FebsResponse listAll() {
+        String companyId = getCurrentUserCompanyId();
+        List<AiProductQuestionLabel> labels = aiProductQuestionLabelService.listAllByCompanyId(companyId);
+        return new FebsResponse().success().data(labels);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLabelService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLabelService.java
index 79594e5..8c5663b 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLabelService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionLabelService.java
@@ -6,6 +6,7 @@
 import cc.mrbird.febs.common.entity.QueryRequest;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.List;
 
 public interface AiProductQuestionLabelService extends IService<AiProductQuestionLabel> {
 
@@ -16,4 +17,6 @@
     FebsResponse add(AiProductQuestionLabel dto);
 
     FebsResponse update(AiProductQuestionLabel dto);
+
+    List<AiProductQuestionLabel> listAllByCompanyId(String companyId);
 }
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 7da398f..70c3ceb 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java
@@ -58,4 +58,6 @@
     void exportProductQuestion(AiProductQuestion dto, HttpServletResponse response);
 
     FebsResponse importDeliver(MultipartFile file);
+
+    FebsResponse updateLabel(String ids, String label);
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLabelServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLabelServiceImpl.java
index 0d0755c..526b489 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLabelServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionLabelServiceImpl.java
@@ -19,6 +19,7 @@
 import org.springframework.stereotype.Service;
 
 import java.util.Date;
+import java.util.List;
 
 @Slf4j
 @Service
@@ -72,4 +73,14 @@
         }
         return new FebsResponse().success().message("操作成功");
     }
+
+    @Override
+    public List<AiProductQuestionLabel> listAllByCompanyId(String companyId) {
+        LambdaQueryWrapper<AiProductQuestionLabel> query = Wrappers.lambdaQuery(AiProductQuestionLabel.class);
+        if (StrUtil.isNotEmpty(companyId)){
+            query.eq(AiProductQuestionLabel::getCompanyId, companyId);
+        }
+        query.orderByDesc(AiProductQuestionLabel::getCreatedTime);
+        return aiProductQuestionLabelMapper.selectList(query);
+    }
 }
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 7c7d764..ad48fa6 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
@@ -640,4 +640,18 @@
 
     }
 
+    @Override
+    public FebsResponse updateLabel(String ids, String label) {
+        if (StrUtil.isEmpty(ids)) {
+            throw new FebsException("参数错误");
+        }
+        List<String> idList = StrUtil.split(ids, ',');
+        this.update(null,
+                Wrappers.lambdaUpdate(AiProductQuestion.class)
+                        .set(AiProductQuestion::getLabel, label)
+                        .set(AiProductQuestion::getUpdatedTime, new Date())
+                        .in(AiProductQuestion::getId, idList));
+        return new FebsResponse().success().message("操作成功");
+    }
+
 }
diff --git a/src/main/resources/templates/febs/views/modules/ai/productQuestion/labelSet.html b/src/main/resources/templates/febs/views/modules/ai/productQuestion/labelSet.html
new file mode 100644
index 0000000..15c9114
--- /dev/null
+++ b/src/main/resources/templates/febs/views/modules/ai/productQuestion/labelSet.html
@@ -0,0 +1,105 @@
+<style>
+    #labelSet {
+        padding: 20px 25px 25px 0;
+    }
+
+    #labelSet .layui-treeSelect .ztree li a, .ztree li span {
+        margin: 0 0 2px 3px !important;
+    }
+    #labelSet #data-permission-tree-block {
+        border: 1px solid #eee;
+        border-radius: 2px;
+        padding: 3px 0;
+    }
+    #labelSet .layui-treeSelect .ztree li span.button.switch {
+        top: 1px;
+        left: 3px;
+    }
+
+</style>
+<div class="layui-fluid" id="labelSet">
+    <form class="layui-form" action="" lay-filter="labelSet-form">
+        <div class="layui-form-item febs-hide">
+            <label class="layui-form-label febs-form-item-require">id:</label>
+            <div class="layui-input-block">
+                <input type="text" name="ids">
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <div class="layui-inline">
+                <label class="layui-form-label">标签:</label>
+                <div class="layui-input-inline">
+                    <select lay-verify="required" name="label" class="labelSet-level" id="labelNameSet">
+                        <option value="">请选择</option>
+                    </select>
+                </div>
+            </div>
+        </div>
+        <div class="layui-form-item febs-hide">
+            <button class="layui-btn" lay-submit="" lay-filter="labelSet-form-submit" id="submit"></button>
+        </div>
+    </form>
+</div>
+
+<script data-th-inline="javascript">
+    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree'], function () {
+        var $ = layui.jquery,
+            febs = layui.febs,
+            layer = layui.layer,
+            formSelects = layui.formSelects,
+            treeSelect = layui.treeSelect,
+            form = layui.form,
+            eleTree = layui.eleTree,
+            labelSet = [[${labelSet}]],
+            $view = $('#labelSet'),
+            validate = layui.validate,
+            _deptTree;
+
+        form.render();
+
+        initLabelSetLevel();
+
+        function initLabelSetLevel() {
+            form.val("labelSet-form", {
+                "ids": labelSet.ids
+            });
+        }
+
+        //(下拉框)
+        $.get(ctx + 'admin/aiProductQuestionLabel/listAll', function (res) {
+            var data = res.data;
+            for (var k in data)
+            {
+                $(".labelSet-level").append("<option value='" + data[k].name + "'>" + data[k].name + "</option>");
+            }
+            layui.use('form', function () {
+                var form = layui.form;
+                form.render();
+            });
+        });
+
+        form.on('submit(labelSet-form-submit)', function (data) {
+            $.ajax({
+                'url':ctx + 'admin/productQuestion/updateLabel',
+                '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);
+                    }else{
+                        febs.alert.warn(data.message);
+                    }
+                },
+                'error':function () {
+                    febs.alert.warn('服务器繁忙');
+                }
+            })
+            return false;
+        });
+
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/febs/views/modules/ai/productQuestion/list.html b/src/main/resources/templates/febs/views/modules/ai/productQuestion/list.html
index ed4f8dc..f468053 100644
--- a/src/main/resources/templates/febs/views/modules/ai/productQuestion/list.html
+++ b/src/main/resources/templates/febs/views/modules/ai/productQuestion/list.html
@@ -56,6 +56,7 @@
         <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productQuestionList:aiAdd" lay-event="productQuestionStateOpen">启用</button>
         <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productQuestionList:aiAdd" lay-event="productQuestionStateClose">禁用</button>
         <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productQuestionList:aiAdd" lay-event="productQuestionDelete">删除</button>
+        <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain" shiro:hasPermission="productQuestionList:aiAdd" lay-event="productQuestionAddLabel">打标签</button>
         <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain" shiro:hasPermission="productQuestionList:aiAdd"  lay-event="exportProductQuestion">导出</button>
         <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain" shiro:hasPermission="productQuestionList:aiAdd" id="importProductQuestion"  lay-event="importProductQuestion">导入</button>
     </div>
@@ -267,6 +268,28 @@
                 });
                 window.location.href = ctx + "admin/productQuestion/exportProductQuestion?ids="+ids;
             }
+            if (layEvent === 'productQuestionAddLabel') {
+                var checkData = table.checkStatus('productQuestionTable').data;
+                if (checkData.length <= 0) {
+                    febs.alert.warn('请选择');
+                    return;
+                }
+                var ids = [];
+                layui.each(checkData, function (key, item) {
+                    ids.push(item.id)
+                });
+                let strIds = ids.join(',');
+                febs.modal.open('打标签', 'modules/ai/productQuestion/labelSet/' + strIds, {
+                    btn: ['确定', '取消'],
+                    area:['100%','100%'],
+                    yes: function (index, layero) {
+                        $('#labelSet').find('#submit').trigger('click');
+                    },
+                    btn2: function () {
+                        layer.closeAll();
+                    }
+                });
+            }
         });
 
         upload.render({
@@ -310,6 +333,7 @@
                     {field: 'state', title: '状态', templet: '#productQuestionStateSwitch', minWidth: 130,align:'center'},
                     {field: 'productCategoryName', title: '分类', minWidth: 100,align:'center'},
                     {field: 'title', title: '题目', minWidth: 100,align:'center'},
+                    {field: 'label', title: '标签', minWidth: 100,align:'center'},
                     {templet:"#difficultyFormat",  title: '难度', minWidth: 140,align:'center'},
                     {field: 'companyId', title: '公司编码', minWidth: 150,align:'center'},
                 ]]

--
Gitblit v1.9.1