feat(ai): add three-level FAQ category management

- add FAQ category table/sql migration and initialize ddl updates

- add category service/controller with validation, default category rules, and sorting

- support faq item category binding and category-based filtering (include descendants)

- redesign FAQ page with category tree actions and UI polish
This commit is contained in:
2026-02-25 16:53:31 +08:00
parent 3b6ed8a49a
commit 9600d0855e
19 changed files with 2224 additions and 99 deletions

View File

@@ -285,6 +285,31 @@ CREATE TABLE `tb_document_collection_category`
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for tb_faq_category
-- ----------------------------
DROP TABLE IF EXISTS `tb_faq_category`;
CREATE TABLE `tb_faq_category`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`collection_id` bigint UNSIGNED NOT NULL COMMENT '知识库ID',
`parent_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '父分类ID0表示根',
`ancestors` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0' COMMENT '祖先路径(逗号分隔)',
`level_no` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT '层级(1-3)',
`category_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名称',
`sort_no` int NOT NULL DEFAULT 0 COMMENT '排序',
`is_default` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认分类',
`status` int NOT NULL DEFAULT 0 COMMENT '数据状态',
`created` datetime NULL DEFAULT NULL COMMENT '创建时间',
`created_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '创建人',
`modified` datetime NULL DEFAULT NULL COMMENT '更新时间',
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_faq_category_collection_parent_sort`(`collection_id`, `parent_id`, `sort_no`) USING BTREE,
INDEX `idx_faq_category_collection_level`(`collection_id`, `level_no`) USING BTREE,
INDEX `idx_faq_category_collection_status`(`collection_id`, `status`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'FAQ分类' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for tb_faq_item
-- ----------------------------
@@ -293,6 +318,7 @@ CREATE TABLE `tb_faq_item`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`collection_id` bigint UNSIGNED NOT NULL COMMENT '知识库ID',
`category_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT 'FAQ分类ID',
`question` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '问题',
`answer_html` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '答案HTML',
`answer_text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '答案纯文本',
@@ -304,7 +330,8 @@ CREATE TABLE `tb_faq_item`
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_faq_collection_id`(`collection_id`) USING BTREE,
INDEX `idx_faq_collection_order`(`collection_id`, `order_no`) USING BTREE
INDEX `idx_faq_collection_order`(`collection_id`, `order_no`) USING BTREE,
INDEX `idx_faq_collection_category_order`(`collection_id`, `category_id`, `order_no`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'FAQ条目' ROW_FORMAT = Dynamic;
-- ----------------------------

View File

@@ -0,0 +1,62 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- P3: FAQ分类树增强最多三级
CREATE TABLE IF NOT EXISTS tb_faq_category
(
id bigint UNSIGNED NOT NULL COMMENT '主键',
collection_id bigint UNSIGNED NOT NULL COMMENT '知识库ID',
parent_id bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '父分类ID0表示根',
ancestors varchar(512) NOT NULL DEFAULT '0' COMMENT '祖先路径(逗号分隔)',
level_no tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT '层级(1-3)',
category_name varchar(64) NOT NULL COMMENT '分类名称',
sort_no int NOT NULL DEFAULT 0 COMMENT '排序',
is_default tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认分类',
status int NOT NULL DEFAULT 0 COMMENT '数据状态',
created datetime NULL COMMENT '创建时间',
created_by bigint UNSIGNED NULL COMMENT '创建人',
modified datetime NULL COMMENT '更新时间',
modified_by bigint UNSIGNED NULL COMMENT '更新人',
PRIMARY KEY (id),
INDEX idx_faq_category_collection_parent_sort (collection_id, parent_id, sort_no),
INDEX idx_faq_category_collection_level (collection_id, level_no),
INDEX idx_faq_category_collection_status (collection_id, status)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT ='FAQ分类';
-- 兼容低版本 MySQL不使用 ADD COLUMN / ADD INDEX IF NOT EXISTS
SET @faq_item_category_col_exists := (
SELECT COUNT(1)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'tb_faq_item'
AND COLUMN_NAME = 'category_id'
);
SET @faq_item_add_category_col_sql := IF(
@faq_item_category_col_exists = 0,
'ALTER TABLE tb_faq_item ADD COLUMN category_id bigint UNSIGNED NULL DEFAULT NULL COMMENT ''FAQ分类ID'' AFTER collection_id',
'DO 0'
);
PREPARE stmt_add_faq_item_category_col FROM @faq_item_add_category_col_sql;
EXECUTE stmt_add_faq_item_category_col;
DEALLOCATE PREPARE stmt_add_faq_item_category_col;
SET @faq_item_category_idx_exists := (
SELECT COUNT(1)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'tb_faq_item'
AND INDEX_NAME = 'idx_faq_collection_category_order'
);
SET @faq_item_add_category_idx_sql := IF(
@faq_item_category_idx_exists = 0,
'ALTER TABLE tb_faq_item ADD INDEX idx_faq_collection_category_order (collection_id, category_id, order_no)',
'DO 0'
);
PREPARE stmt_add_faq_item_category_idx FROM @faq_item_add_category_idx_sql;
EXECUTE stmt_add_faq_item_category_idx;
DEALLOCATE PREPARE stmt_add_faq_item_category_idx;
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -285,6 +285,31 @@ CREATE TABLE `tb_document_collection_category`
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for tb_faq_category
-- ----------------------------
DROP TABLE IF EXISTS `tb_faq_category`;
CREATE TABLE `tb_faq_category`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`collection_id` bigint UNSIGNED NOT NULL COMMENT '知识库ID',
`parent_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '父分类ID0表示根',
`ancestors` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0' COMMENT '祖先路径(逗号分隔)',
`level_no` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT '层级(1-3)',
`category_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名称',
`sort_no` int NOT NULL DEFAULT 0 COMMENT '排序',
`is_default` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认分类',
`status` int NOT NULL DEFAULT 0 COMMENT '数据状态',
`created` datetime NULL DEFAULT NULL COMMENT '创建时间',
`created_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '创建人',
`modified` datetime NULL DEFAULT NULL COMMENT '更新时间',
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_faq_category_collection_parent_sort`(`collection_id`, `parent_id`, `sort_no`) USING BTREE,
INDEX `idx_faq_category_collection_level`(`collection_id`, `level_no`) USING BTREE,
INDEX `idx_faq_category_collection_status`(`collection_id`, `status`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'FAQ分类' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for tb_faq_item
-- ----------------------------
@@ -293,6 +318,7 @@ CREATE TABLE `tb_faq_item`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`collection_id` bigint UNSIGNED NOT NULL COMMENT '知识库ID',
`category_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT 'FAQ分类ID',
`question` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '问题',
`answer_html` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '答案HTML',
`answer_text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '答案纯文本',
@@ -304,7 +330,8 @@ CREATE TABLE `tb_faq_item`
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_faq_collection_id`(`collection_id`) USING BTREE,
INDEX `idx_faq_collection_order`(`collection_id`, `order_no`) USING BTREE
INDEX `idx_faq_collection_order`(`collection_id`, `order_no`) USING BTREE,
INDEX `idx_faq_collection_category_order`(`collection_id`, `category_id`, `order_no`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'FAQ条目' ROW_FORMAT = Dynamic;
-- ----------------------------