| src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/cc/mrbird/febs/ai/entity/AiProductQuestionJob.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/cc/mrbird/febs/ai/mapper/AiProductQuestionJobMapper.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java | ●●●●● patch | view | raw | blame | history | |
| src/main/resources/templates/febs/views/modules/ai/productQuestion/jobList.html | ●●●●● patch | view | raw | blame | history |
src/main/java/cc/mrbird/febs/ai/controller/productQuestion/AiProductQuestionController.java
@@ -1,6 +1,7 @@ package cc.mrbird.febs.ai.controller.productQuestion; import cc.mrbird.febs.ai.entity.AiProductQuestion; import cc.mrbird.febs.ai.entity.AiProductQuestionJob; import cc.mrbird.febs.ai.req.AiProductQuestionAiDto; import cc.mrbird.febs.ai.service.AiProductQuestionService; import cc.mrbird.febs.common.annotation.ControllerEndpoint; @@ -37,6 +38,15 @@ return new FebsResponse().success().data(data); } @GetMapping("jobList") public FebsResponse jobList(AiProductQuestionJob dto, QueryRequest request) { String companyId = getCurrentUserCompanyId(); dto.setCompanyId(companyId); Map<String, Object> data = getDataTable(aiProductQuestionService.listJobInPage(dto, request)); return new FebsResponse().success().data(data); } @GetMapping("changeState/{id}/{state}") @ControllerEndpoint(operation = "状态操作", exceptionMessage = "操作失败") public FebsResponse changeState( @@ -60,9 +70,12 @@ @ControllerEndpoint(operation = "AI生成题目", exceptionMessage = "操作失败") public FebsResponse aiAdd(@RequestBody @Valid AiProductQuestionAiDto dto) { // String companyId = getCurrentUserCompanyId(); // dto.setCompanyId(companyId); // return aiProductQuestionService.aiAdd(dto); String companyId = getCurrentUserCompanyId(); dto.setCompanyId(companyId); return aiProductQuestionService.aiAdd(dto); return aiProductQuestionService.aiAddV2(dto); } @PostMapping("update") src/main/java/cc/mrbird/febs/ai/controller/productQuestion/ViewController.java
@@ -38,6 +38,13 @@ return FebsUtil.view("modules/ai/productQuestion/list"); } @GetMapping("jobList") @RequiresPermissions("productQuestionJobList:view") public String jobList() { return FebsUtil.view("modules/ai/productQuestion/jobList"); } @GetMapping(value = "/add") @RequiresPermissions("productQuestionList:add") public String artAdd() { src/main/java/cc/mrbird/febs/ai/entity/AiProductQuestionJob.java
New file @@ -0,0 +1,55 @@ package cc.mrbird.febs.ai.entity; import cc.mrbird.febs.common.entity.AiBaseEntity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.util.List; /** * ai题目生成任务 * * @author yourname * @date 2025-07-29 */ @Data @TableName("ai_product_question_job") public class AiProductQuestionJob extends AiBaseEntity { /** * 公司ID (UUID) */ private String companyId; /** * AI产品类别ID (UUID) */ private String productCategoryId; /** * 要求 */ private String title; /** * 难度:1-简单,2-中等,3-困难 */ private Integer difficulty; /** * 状态 0-为启动 1-进行中 2-已完成 */ private Integer state; /** * 题目数量 */ private Integer questionCnt; /** * 已完成数量 */ private Integer questionDoneCnt; } src/main/java/cc/mrbird/febs/ai/mapper/AiProductQuestionJobMapper.java
New file @@ -0,0 +1,14 @@ package cc.mrbird.febs.ai.mapper; import cc.mrbird.febs.ai.entity.AiProductQuestionJob; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * AI产品题目 Mapper接口 * * @author yourname * @date 2025-07-29 */ public interface AiProductQuestionJobMapper extends BaseMapper<AiProductQuestionJob> { } src/main/java/cc/mrbird/febs/ai/service/AiProductQuestionService.java
@@ -1,6 +1,7 @@ package cc.mrbird.febs.ai.service; import cc.mrbird.febs.ai.entity.AiProductQuestion; import cc.mrbird.febs.ai.entity.AiProductQuestionJob; import cc.mrbird.febs.ai.entity.AiProductRole; import cc.mrbird.febs.ai.req.AiProductQuestionAiDto; import cc.mrbird.febs.common.entity.FebsResponse; @@ -27,6 +28,8 @@ IPage<AiProductQuestion> listInPage(AiProductQuestion dto, QueryRequest request); IPage<AiProductQuestionJob> listJobInPage(AiProductQuestionJob dto, QueryRequest request); FebsResponse changeState(String id, Integer state); FebsResponse add(AiProductQuestion dto); @@ -42,4 +45,5 @@ List<AiProductQuestion> productQuestionTree(LambdaQueryWrapper<AiProductQuestion> aiProductQuestionLambdaQueryWrapper); FebsResponse aiAdd(AiProductQuestionAiDto dto); FebsResponse aiAddV2(AiProductQuestionAiDto dto); } src/main/java/cc/mrbird/febs/ai/service/impl/AiProductQuestionServiceImpl.java
@@ -1,6 +1,7 @@ package cc.mrbird.febs.ai.service.impl; import cc.mrbird.febs.ai.entity.*; import cc.mrbird.febs.ai.mapper.AiProductQuestionJobMapper; import cc.mrbird.febs.ai.mapper.AiProductQuestionMapper; import cc.mrbird.febs.ai.req.AiProductQuestionAiDto; import cc.mrbird.febs.ai.service.AiProductQuestionItemService; @@ -46,6 +47,7 @@ public class AiProductQuestionServiceImpl extends ServiceImpl<AiProductQuestionMapper, AiProductQuestion> implements AiProductQuestionService { private final AiProductQuestionMapper aiProductQuestionMapper; private final AiProductQuestionJobMapper aiProductQuestionJobMapper; private final AiProductQuestionItemService aiProductQuestionItemService; private final AiService aiService; @@ -68,6 +70,21 @@ query.ne(AiProductQuestion::getState, 2); query.orderByDesc(AiProductQuestion::getCreatedTime); Page<AiProductQuestion> pages = aiProductQuestionMapper.selectPage(page, query); return pages; } @Override public IPage<AiProductQuestionJob> listJobInPage(AiProductQuestionJob dto, QueryRequest request) { Page<AiProductQuestionJob> page = new Page<>(request.getPageNum(), request.getPageSize()); LambdaQueryWrapper<AiProductQuestionJob> query = Wrappers.lambdaQuery(AiProductQuestionJob.class); if (StrUtil.isNotEmpty(dto.getCompanyId())){ query.eq(AiProductQuestionJob::getCompanyId, dto.getCompanyId()); } if (StrUtil.isNotEmpty(dto.getProductCategoryId())){ query.eq(AiProductQuestionJob::getProductCategoryId, dto.getProductCategoryId()); } query.orderByDesc(AiProductQuestionJob::getCreatedTime); Page<AiProductQuestionJob> pages = aiProductQuestionJobMapper.selectPage(page, query); return pages; } @@ -248,6 +265,26 @@ return new FebsResponse().success().message("操作成功"); } @Override public FebsResponse aiAddV2(AiProductQuestionAiDto dto) { String companyId = dto.getCompanyId(); String productCategoryId = dto.getProductCategoryId(); Integer questionCnt = dto.getQuestionCnt(); String query = dto.getQuery(); Integer difficulty = dto.getDifficulty(); Date createdTime = new Date(); AiProductQuestionJob aiProductQuestionJob = new AiProductQuestionJob(); aiProductQuestionJob.setId(UUID.getSimpleUUIDString()); aiProductQuestionJob.setCompanyId(companyId); aiProductQuestionJob.setProductCategoryId(productCategoryId); aiProductQuestionJob.setTitle(query); aiProductQuestionJob.setQuestionCnt(questionCnt); aiProductQuestionJob.setDifficulty(difficulty); aiProductQuestionJob.setCreatedTime(createdTime); aiProductQuestionJobMapper.insert(aiProductQuestionJob); return new FebsResponse().success().message("操作成功"); } /** * 解析AI返回的包含问题和答案的JSON字符串 * @param aiResponse AI返回的原始响应字符串 src/main/resources/templates/febs/views/modules/ai/productQuestion/jobList.html
New file @@ -0,0 +1,160 @@ <div class="layui-fluid layui-anim febs-anim" id="febs-productQuestion-job" lay-title="产品题库"> <div class="layui-row febs-container"> <div class="layui-col-md12"> <div class="layui-card"> <div class="layui-card-body febs-table-full"> <form class="layui-form layui-table-form" lay-filter="productQuestion-table-job-form"> <div class="layui-row"> <div class="layui-col-md10"> <div class="layui-row layui-col-space6 layui-form-item"> <div class="layui-col-lg3"> <label class="layui-form-label">产品分类:</label> <div class="layui-input-block"> <div id="product-qutestion-job-category-query"></div> </div> </div> </div> </div> <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area"> <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query"> <i class="layui-icon"></i> </div> <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset"> <i class="layui-icon"></i> </div> </div> </div> </form> <table lay-filter="productQuestionJobTable" lay-data="{id: 'productQuestionJobTable'}"></table> <style type="text/css"> .layui-table-cell{ text-align:center; height: auto; white-space: nowrap; /*文本不会换行,在同一行显示*/ overflow: hidden; /*超出隐藏*/ text-overflow: ellipsis; /*省略号显示*/ } .layui-table img{ max-width:100px } ::-webkit-scrollbar { height: 20px !important; background-color: #f4f4f4; } </style> </div> </div> </div> </div> </div> <script type="text/html" id="difficultyFormat"> {{# if(d.difficulty == 1) { }} <span>简单</span> {{# }else if(d.difficulty == 2) { }} <span>中等</span> {{# }else if(d.difficulty == 3) { }} <span>困难</span> {{# } else { }} <span>-</span> {{# } }} </script> <style> .layui-form-onswitch { background-color: #5FB878 !important; } </style> <!-- 表格操作栏 end --> <script data-th-inline="none" type="text/javascript"> // 引入组件并初始化 layui.use([ 'jquery', 'form', 'table', 'febs', 'xmSelect'], function () { var $ = layui.jquery, febs = layui.febs, form = layui.form, table = layui.table, $view = $('#febs-productQuestion-job'), $query = $view.find('#query'), $reset = $view.find('#reset'), $searchForm = $view.find('form'), sortObject = {field: 'orderNum', type: null}, tableIns; form.render(); var categoryQuestion = xmSelect.render({ el: '#product-qutestion-job-category-query', language: 'zn', prop : { value : 'id', children : 'child' }, iconfont: { parent: 'hidden', }, tips: '请选择', filterable: true, radio: true, clickClose: true, tree: { show: true, //非严格模式 strict: false, }, data: [] }) febs.get(ctx + 'admin/productCategory/categoryTree', null, function(res) { categoryQuestion.update({ data : res.data, autoRow: true, }); }) // 表格初始化 initproductQuestionJobTable(); function initproductQuestionJobTable() { tableIns = febs.table.init({ elem: $view.find('table'), id: 'productQuestionJobTable', url: ctx + 'admin/productQuestion/jobList', toolbar:"#productQuestionJobToolbar", defaultToolbar:[], cols: [[ {type: 'checkbox'}, {type: 'numbers', title: '', width: 80}, {field: 'title', title: '要求', minWidth: 100,align:'center'}, {field: 'questionCnt', title: '生成总数', minWidth: 100,align:'center'}, {field: 'questionDoneCnt', title: '已完成', minWidth: 100,align:'center'}, {templet:"#difficultyFormat", title: '难度', minWidth: 140,align:'center'}, {field: 'companyId', title: '公司编码', minWidth: 150,align:'center'}, ]] }); } // 查询按钮 $query.on('click', function () { var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type}); tableIns.reload({where: params, page: {curr: 1}}); }); // 刷新按钮 $reset.on('click', function () { var categoryList = []; categoryQuestion.setValue(categoryList); $searchForm[0].reset(); sortObject.type = 'null'; tableIns.reload({where: null, page: {curr: 1}, initSort: sortObject}); }); // 获取查询参数 function getQueryParams() { return { productCategoryId: categoryQuestion.getValue('valueStr'), }; } }) </script>