feat(ai): 添加产品问答标签功能
- 在AiProductQuestionController中新增updateLabel接口用于更新标签
- 在AiProductQuestionLabelController中新增listAll接口获取所有标签
- 实现AiProductQuestionLabelService的listAllByCompanyId方法
- 实现AiProductQuestionService的updateLabel方法支持批量标签更新
- 创建新的labelSet.html页面实现标签设置界面
- 在产品问答列表页面添加打标签按钮和相关功能
- 修改视图控制器在名称显示中加入标签信息
- 更新数据库查询逻辑支持按公司ID过滤标签列表
9 files modified
1 files added
| | |
| | | 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()); |
| | | } |
| | |
| | | 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()); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | 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"); |
| | | } |
| | | } |
| | |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.validation.Valid; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | |
| | | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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> { |
| | | |
| | |
| | | FebsResponse add(AiProductQuestionLabel dto); |
| | | |
| | | FebsResponse update(AiProductQuestionLabel dto); |
| | | |
| | | List<AiProductQuestionLabel> listAllByCompanyId(String companyId); |
| | | } |
| | |
| | | void exportProductQuestion(AiProductQuestion dto, HttpServletResponse response); |
| | | |
| | | FebsResponse importDeliver(MultipartFile file); |
| | | |
| | | FebsResponse updateLabel(String ids, String label); |
| | | } |
| | |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | @Slf4j |
| | | @Service |
| | |
| | | } |
| | | 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); |
| | | } |
| | | } |
| | |
| | | |
| | | } |
| | | |
| | | @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("操作成功"); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | }); |
| | | 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({ |
| | |
| | | {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'}, |
| | | ]] |