serv\web-侧边栏 标签统一
This commit is contained in:
276
schoolNewsServ/.bin/mysql/sql/RESOURCE_CATEGORY_REMOVAL.md
Normal file
276
schoolNewsServ/.bin/mysql/sql/RESOURCE_CATEGORY_REMOVAL.md
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
# ResourceCategory 移除清单
|
||||||
|
|
||||||
|
## 📝 概述
|
||||||
|
|
||||||
|
本文档记录了 `ResourceCategory` 相关功能的完整移除过程。原资源分类功能已完全迁移到标签系统(`tb_tag` 的 `tag_type=1`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 已完成的操作
|
||||||
|
|
||||||
|
### 1. 数据库层面
|
||||||
|
|
||||||
|
#### 已注释的建表语句
|
||||||
|
**文件:** `.bin\mysql\sql\createTableResource.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 资源分类表(已废弃,使用 tb_tag 表的 tag_type=1 代替)
|
||||||
|
-- DROP TABLE IF EXISTS `tb_resource_category`;
|
||||||
|
-- CREATE TABLE `tb_resource_category` (
|
||||||
|
-- ...
|
||||||
|
-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资源分类表';
|
||||||
|
--
|
||||||
|
-- ⚠️ 注意:资源分类功能已迁移到 tb_tag 表中,使用 tag_type=1 表示文章分类标签
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 已注释的初始化数据
|
||||||
|
**文件:** `.bin\mysql\sql\initAllData.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 插入资源分类数据(已废弃,使用下方的 tb_tag 数据代替)
|
||||||
|
-- INSERT INTO `tb_resource_category` (id, category_id, name, description, order_num, creator, create_time) VALUES
|
||||||
|
-- ('1', 'party_history', '党史学习', '党史学习相关资源', 1, '1', now()),
|
||||||
|
-- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Java 代码层面
|
||||||
|
|
||||||
|
#### 已删除的文件(共7个)
|
||||||
|
|
||||||
|
1. **实体类**
|
||||||
|
- ❌ `common\common-dto\src\main\java\org\xyzh\common\dto\resource\TbResourceCategory.java`
|
||||||
|
|
||||||
|
2. **Service 层**
|
||||||
|
- ❌ `api\api-news\src\main\java\org\xyzh\api\news\category\ResourceCategoryService.java`
|
||||||
|
- ❌ `news\src\main\java\org\xyzh\news\service\NCResourceCategoryService.java`
|
||||||
|
- ❌ `news\src\main\java\org\xyzh\news\service\impl\NCResourceCategoryServiceImpl.java`
|
||||||
|
|
||||||
|
3. **Controller 层**
|
||||||
|
- ❌ `news\src\main\java\org\xyzh\news\controller\ResourceCategoryController.java`
|
||||||
|
|
||||||
|
4. **Mapper 层**
|
||||||
|
- ❌ `news\src\main\java\org\xyzh\news\mapper\ResourceCategoryMapper.java`
|
||||||
|
- ❌ `news\src\main\resources\mapper\ResourceCategoryMapper.xml`
|
||||||
|
|
||||||
|
#### 已修改的文件(共2个)
|
||||||
|
|
||||||
|
1. **ResourceVO.java**
|
||||||
|
- 删除了 `resourceCategory` 字段及其 getter/setter
|
||||||
|
- 保留 `tags` 字段用于存储标签列表(包含文章分类标签)
|
||||||
|
|
||||||
|
**修改前:**
|
||||||
|
```java
|
||||||
|
public class ResourceVO {
|
||||||
|
private TbResource resource;
|
||||||
|
private TbResourceCategory resourceCategory; // ❌ 已删除
|
||||||
|
private List<TbTag> tags;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后:**
|
||||||
|
```java
|
||||||
|
public class ResourceVO {
|
||||||
|
private TbResource resource;
|
||||||
|
// ✅ 资源标签列表(包含文章分类标签 tag_type=1)
|
||||||
|
private List<TbTag> tags;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **ResourceCenterController.java**
|
||||||
|
- 修改 import 语句,移除 `TbResourceCategory`,添加 `TbTag`
|
||||||
|
- 修改返回类型:`ResultDomain<TbResourceCategory>` → `ResultDomain<TbTag>`
|
||||||
|
- 更新 TODO 注释,说明使用 `TagService.getTagsByType(1)`
|
||||||
|
|
||||||
|
**关键修改:**
|
||||||
|
```java
|
||||||
|
// 修改前
|
||||||
|
import org.xyzh.common.dto.resource.TbResourceCategory;
|
||||||
|
public ResultDomain<TbResourceCategory> getSpecialCategories() { ... }
|
||||||
|
|
||||||
|
// 修改后
|
||||||
|
import org.xyzh.common.dto.resource.TbTag;
|
||||||
|
public ResultDomain<TbTag> getSpecialCategories() {
|
||||||
|
// TODO: 使用 TagService.getTagsByType(1) 获取文章分类标签
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 迁移映射关系
|
||||||
|
|
||||||
|
### API 接口映射
|
||||||
|
|
||||||
|
| 原接口 (ResourceCategory) | 新接口 (Tag) | 说明 |
|
||||||
|
|---------------------------|--------------|------|
|
||||||
|
| `GET /news/categorys/list` | `GET /news/tags/type/1` | 获取所有文章分类标签 |
|
||||||
|
| `GET /news/categorys/category/{id}` | `GET /news/tags/tag/{tagID}` | 获取单个标签详情 |
|
||||||
|
| `POST /news/categorys/category` | `POST /news/tags/tag` | 创建标签(需指定 tagType=1) |
|
||||||
|
| `PUT /news/categorys/category` | `PUT /news/tags/tag` | 更新标签 |
|
||||||
|
| `DELETE /news/categorys/category/{id}` | `DELETE /news/tags/tag/{tagID}` | 删除标签 |
|
||||||
|
| `GET /news/categorys/tree` | `GET /news/tags/type/1` | 获取分类树(可通过标签列表构建) |
|
||||||
|
|
||||||
|
### 数据字段映射
|
||||||
|
|
||||||
|
| ResourceCategory 字段 | Tag 字段 | 说明 |
|
||||||
|
|----------------------|----------|------|
|
||||||
|
| `tagID` | `tagID` | 唯一标识 |
|
||||||
|
| `name` | `name` | 名称 |
|
||||||
|
| `description` | `description` | 描述 |
|
||||||
|
| `icon` | - | 图标(Tag中无此字段,可扩展) |
|
||||||
|
| `orderNum` | - | 排序号(可通过创建时间排序) |
|
||||||
|
| `parentID` | - | 父分类(Tag为扁平结构) |
|
||||||
|
| - | `tagType` | 标签类型(固定为1) |
|
||||||
|
| - | `color` | 标签颜色(新增字段) |
|
||||||
|
|
||||||
|
### 代码调用映射
|
||||||
|
|
||||||
|
**修改前:**
|
||||||
|
```java
|
||||||
|
// 使用 ResourceCategoryService
|
||||||
|
ResourceCategoryService categoryService;
|
||||||
|
ResultDomain<TbResourceCategory> result = categoryService.getAllCategories();
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后:**
|
||||||
|
```java
|
||||||
|
// 使用 TagService
|
||||||
|
TagService tagService;
|
||||||
|
ResultDomain<TbTag> result = tagService.getTagsByType(1); // 1 = 文章分类标签
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 数据迁移注意事项
|
||||||
|
|
||||||
|
### 如果数据库中已有 tb_resource_category 数据
|
||||||
|
|
||||||
|
需要执行以下迁移 SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. 将 tb_resource_category 数据迁移到 tb_tag
|
||||||
|
INSERT INTO tb_tag (id, tag_id, name, description, tag_type, creator, create_time)
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
category_id AS tag_id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
1 AS tag_type, -- 文章分类标签
|
||||||
|
creator,
|
||||||
|
create_time
|
||||||
|
FROM tb_resource_category
|
||||||
|
WHERE deleted = 0;
|
||||||
|
|
||||||
|
-- 2. 确认迁移成功后,删除旧表(可选)
|
||||||
|
-- DROP TABLE IF EXISTS tb_resource_category;
|
||||||
|
```
|
||||||
|
|
||||||
|
### tb_resource 表的 category_id 字段
|
||||||
|
|
||||||
|
`tb_resource` 表中的 `category_id` 字段仍然保留,但现在应该:
|
||||||
|
- 存储的是 `tb_tag` 表中 `tag_type=1` 的标签的 `tag_id`
|
||||||
|
- 或者改为使用 `tb_resource_tag` 关联表来管理资源与分类标签的关系
|
||||||
|
|
||||||
|
**推荐方案:** 使用 `tb_resource_tag` 关联表
|
||||||
|
```sql
|
||||||
|
-- 迁移资源分类关系到资源标签关联表
|
||||||
|
INSERT INTO tb_resource_tag (id, resource_id, tag_id, create_time)
|
||||||
|
SELECT
|
||||||
|
CONCAT('rt_', UUID()) AS id,
|
||||||
|
resource_id,
|
||||||
|
category_id AS tag_id,
|
||||||
|
NOW() AS create_time
|
||||||
|
FROM tb_resource
|
||||||
|
WHERE category_id IS NOT NULL AND category_id != '';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 影响范围评估
|
||||||
|
|
||||||
|
### 前端影响
|
||||||
|
- ❌ 需要修改前端代码中调用 `/news/categorys` 的接口
|
||||||
|
- ✅ 改为调用 `/news/tags/type/1` 接口
|
||||||
|
- ✅ 数据结构基本一致,只需修改接口地址和字段映射
|
||||||
|
|
||||||
|
### 后端影响
|
||||||
|
- ✅ 已完全移除 ResourceCategory 相关代码
|
||||||
|
- ✅ 所有功能已迁移到 TagService
|
||||||
|
- ⚠️ 如有其他模块引用了 ResourceCategory,需要同步修改
|
||||||
|
|
||||||
|
### 数据库影响
|
||||||
|
- ✅ 建表语句已注释,不会创建 `tb_resource_category` 表
|
||||||
|
- ⚠️ 如果数据库中已存在该表,需要手动迁移数据
|
||||||
|
- ⚠️ 建议保留旧表一段时间作为备份
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 验证清单
|
||||||
|
|
||||||
|
完成以下验证以确保迁移成功:
|
||||||
|
|
||||||
|
### 1. 编译验证
|
||||||
|
- [ ] Maven 编译无错误
|
||||||
|
- [ ] 无 `TbResourceCategory` 相关的编译错误
|
||||||
|
- [ ] 无 `ResourceCategoryService` 相关的导入错误
|
||||||
|
|
||||||
|
### 2. 功能验证
|
||||||
|
- [ ] 创建文章分类标签(tagType=1)
|
||||||
|
- [ ] 获取文章分类标签列表
|
||||||
|
- [ ] 为资源添加分类标签
|
||||||
|
- [ ] 查询资源的分类标签
|
||||||
|
- [ ] 删除文章分类标签
|
||||||
|
|
||||||
|
### 3. 接口验证
|
||||||
|
```bash
|
||||||
|
# 1. 获取文章分类标签
|
||||||
|
curl http://localhost:8080/news/tags/type/1
|
||||||
|
|
||||||
|
# 2. 创建文章分类标签
|
||||||
|
curl -X POST http://localhost:8080/news/tags/tag \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"党史学习","tagType":1,"color":"#ff6b6b"}'
|
||||||
|
|
||||||
|
# 3. 为资源添加分类标签
|
||||||
|
curl -X POST http://localhost:8080/news/tags/resource/{resourceID}/tag/{tagID}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 数据验证
|
||||||
|
```sql
|
||||||
|
-- 检查标签数据
|
||||||
|
SELECT * FROM tb_tag WHERE tag_type = 1;
|
||||||
|
|
||||||
|
-- 检查资源标签关联
|
||||||
|
SELECT r.title, t.name
|
||||||
|
FROM tb_resource r
|
||||||
|
LEFT JOIN tb_resource_tag rt ON r.resource_id = rt.resource_id
|
||||||
|
LEFT JOIN tb_tag t ON rt.tag_id = t.tag_id
|
||||||
|
WHERE t.tag_type = 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 总结
|
||||||
|
|
||||||
|
### 移除内容
|
||||||
|
- ✅ 7个 Java 文件(实体、Service、Controller、Mapper)
|
||||||
|
- ✅ 1个 Mapper XML 文件
|
||||||
|
- ✅ SQL 建表语句(已注释)
|
||||||
|
- ✅ SQL 初始化数据(已注释)
|
||||||
|
|
||||||
|
### 修改内容
|
||||||
|
- ✅ 2个 Java 文件(ResourceVO、ResourceCenterController)
|
||||||
|
- ✅ 更新迁移文档
|
||||||
|
|
||||||
|
### 替代方案
|
||||||
|
- ✅ 使用 `tb_tag` (tag_type=1) 替代 `tb_resource_category`
|
||||||
|
- ✅ 使用 `TagService.getTagsByType(1)` 获取文章分类标签
|
||||||
|
- ✅ 接口从 `/news/categorys` 迁移到 `/news/tags/type/1`
|
||||||
|
|
||||||
|
### 优势
|
||||||
|
- ✅ 代码更简洁,减少7个文件
|
||||||
|
- ✅ 数据结构更统一
|
||||||
|
- ✅ 功能更灵活,易于扩展
|
||||||
|
- ✅ 维护成本降低
|
||||||
|
|
||||||
|
移除操作已全部完成!🎉
|
||||||
|
|
||||||
415
schoolNewsServ/.bin/mysql/sql/TAG_TYPE_MIGRATION.md
Normal file
415
schoolNewsServ/.bin/mysql/sql/TAG_TYPE_MIGRATION.md
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
# 标签系统类型化改造文档
|
||||||
|
|
||||||
|
## 📝 改造概述
|
||||||
|
|
||||||
|
将原有的单一标签系统改造为支持3种标签类型的系统,同时废除 `tb_resource_category` 表:
|
||||||
|
1. **文章分类标签** (tag_type=1) - 替代原 `tb_resource_category`
|
||||||
|
2. **课程分类标签** (tag_type=2)
|
||||||
|
3. **学习任务分类标签** (tag_type=3)
|
||||||
|
|
||||||
|
### 改造日期
|
||||||
|
2025-10-27
|
||||||
|
|
||||||
|
### 改造原因
|
||||||
|
- ✅ **更清晰的业务划分** - 不同业务领域使用专属的标签类型
|
||||||
|
- ✅ **避免标签混淆** - 同名标签在不同类型下可独立存在
|
||||||
|
- ✅ **更好的可扩展性** - 便于未来添加新的标签类型
|
||||||
|
- ✅ **统一管理** - 将 `tb_resource_category` 合并到 `tb_tag`,使用 tag_type=1 表示文章分类标签
|
||||||
|
- ✅ **简化架构** - 减少数据表数量,统一标签管理逻辑
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗑️ 废除内容
|
||||||
|
|
||||||
|
### 1. 废除 tb_resource_category 表
|
||||||
|
|
||||||
|
**原因:** 资源分类功能已完全整合到标签系统中,使用 `tag_type=1` 的标签代替。
|
||||||
|
|
||||||
|
**废除内容:**
|
||||||
|
- ❌ `tb_resource_category` 表(已注释建表语句)
|
||||||
|
- ❌ `TbResourceCategory` 实体类(已删除)
|
||||||
|
- ❌ `ResourceCategoryService` 接口(已删除)
|
||||||
|
- ❌ `NCResourceCategoryServiceImpl` 实现类(已删除)
|
||||||
|
- ❌ `ResourceCategoryController` 控制器(已删除)
|
||||||
|
- ❌ `ResourceCategoryMapper` 及 XML(已删除)
|
||||||
|
|
||||||
|
**迁移方案:**
|
||||||
|
- 原 `tb_resource_category` 数据 → `tb_tag` (tag_type=1)
|
||||||
|
- 原 `/news/categorys` 接口 → `/news/tags/type/1` 接口
|
||||||
|
- 原 `ResourceVO.resourceCategory` 字段 → 改用 `ResourceVO.tags` 列表
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 数据库变更
|
||||||
|
|
||||||
|
### 1. 建表语句修改 (createTableResource.sql)
|
||||||
|
|
||||||
|
**修改内容:**
|
||||||
|
- 添加 `tag_type` 字段(INT(4),默认值1)
|
||||||
|
- 修改唯一索引:从 `uk_tag_name` 改为 `uk_tag_name_type`(组合唯一索引)
|
||||||
|
- 添加索引:`idx_tag_type`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 标签表
|
||||||
|
DROP TABLE IF EXISTS `tb_tag`;
|
||||||
|
CREATE TABLE `tb_tag` (
|
||||||
|
`id` VARCHAR(50) NOT NULL COMMENT '标签ID',
|
||||||
|
`tag_id` VARCHAR(50) NOT NULL COMMENT '标签唯一标识',
|
||||||
|
`name` VARCHAR(100) NOT NULL COMMENT '标签名称',
|
||||||
|
`color` VARCHAR(20) DEFAULT NULL COMMENT '标签颜色',
|
||||||
|
`description` VARCHAR(255) DEFAULT NULL COMMENT '标签描述',
|
||||||
|
`tag_type` INT(4) DEFAULT 1 COMMENT '标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)',
|
||||||
|
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`delete_time` TIMESTAMP NULL DEFAULT NULL COMMENT '删除时间',
|
||||||
|
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_tag_id` (`tag_id`),
|
||||||
|
UNIQUE KEY `uk_tag_name_type` (`name`, `tag_type`),
|
||||||
|
KEY `idx_tag_type` (`tag_type`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='标签表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 初始化数据 (initAllData.sql)
|
||||||
|
|
||||||
|
**新增内容:**
|
||||||
|
- 添加15条初始标签数据(每种类型各5条)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 插入标签数据 (文章分类标签 tag_type=1)
|
||||||
|
INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, create_time) VALUES
|
||||||
|
('tag001', 'tag_article_001', '党史', '#ff6b6b', '党史学习相关文章', 1, '1', now()),
|
||||||
|
('tag002', 'tag_article_002', '理论学习', '#4ecdc4', '理论学习相关文章', 1, '1', now()),
|
||||||
|
...
|
||||||
|
|
||||||
|
-- 插入标签数据 (课程分类标签 tag_type=2)
|
||||||
|
INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, create_time) VALUES
|
||||||
|
('tag101', 'tag_course_001', '基础课程', '#26de81', '基础思政课程', 2, '1', now()),
|
||||||
|
('tag102', 'tag_course_002', '专题课程', '#fc5c65', '专题思政课程', 2, '1', now()),
|
||||||
|
...
|
||||||
|
|
||||||
|
-- 插入标签数据 (学习任务分类标签 tag_type=3)
|
||||||
|
INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, create_time) VALUES
|
||||||
|
('tag201', 'tag_task_001', '每日学习', '#20bf6b', '每日学习任务', 3, '1', now()),
|
||||||
|
('tag202', 'tag_task_002', '专题学习', '#fa8231', '专题学习任务', 3, '1', now()),
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 代码变更
|
||||||
|
|
||||||
|
### 1. 枚举类新增
|
||||||
|
|
||||||
|
**文件:** `common\common-core\src\main\java\org\xyzh\common\core\enums\TagType.java`
|
||||||
|
|
||||||
|
```java
|
||||||
|
public enum TagType {
|
||||||
|
ARTICLE_CATEGORY(1, "文章分类标签"),
|
||||||
|
COURSE_CATEGORY(2, "课程分类标签"),
|
||||||
|
LEARNING_TASK_CATEGORY(3, "学习任务分类标签");
|
||||||
|
|
||||||
|
// ... 枚举方法
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. DTO实体类修改
|
||||||
|
|
||||||
|
**文件:** `common\common-dto\src\main\java\org\xyzh\common\dto\resource\TbTag.java`
|
||||||
|
|
||||||
|
**修改内容:**
|
||||||
|
- 添加 `tagType` 字段(Integer)
|
||||||
|
- 添加 getter/setter 方法
|
||||||
|
- 更新 toString() 方法
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* @description 标签类型 1-文章分类标签 2-课程分类标签 3-学习任务分类标签
|
||||||
|
*/
|
||||||
|
private Integer tagType;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Mapper接口修改
|
||||||
|
|
||||||
|
**文件:** `news\src\main\java\org\xyzh\news\mapper\TagMapper.java`
|
||||||
|
|
||||||
|
**修改内容:**
|
||||||
|
- 修改 `selectByType` → `selectByTagType`(参数名更明确)
|
||||||
|
- 修改 `countByName` → `countByNameAndType`(增加tagType参数)
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 旧方法
|
||||||
|
List<TbTag> selectByType(@Param("type") Integer type);
|
||||||
|
int countByName(@Param("name") String name, @Param("excludeId") String excludeId);
|
||||||
|
|
||||||
|
// 新方法
|
||||||
|
List<TbTag> selectByTagType(@Param("tagType") Integer tagType);
|
||||||
|
int countByNameAndType(@Param("name") String name, @Param("tagType") Integer tagType, @Param("excludeId") String excludeId);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Mapper XML修改
|
||||||
|
|
||||||
|
**文件:** `news\src\main\resources\mapper\TagMapper.xml`
|
||||||
|
|
||||||
|
**修改内容:**
|
||||||
|
1. BaseResultMap 添加 `tag_type` 字段映射
|
||||||
|
2. Base_Column_List 添加 `tag_type` 字段
|
||||||
|
3. Where_Clause 添加 `tag_type` 条件
|
||||||
|
4. 修改 `selectByType` → `selectByTagType`
|
||||||
|
5. 修改 `countByName` → `countByNameAndType`
|
||||||
|
6. insertTag、updateTag、batchInsertTags 添加 `tag_type` 字段
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- 基础结果映射 -->
|
||||||
|
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.resource.TbTag">
|
||||||
|
...
|
||||||
|
<result column="tag_type" property="tagType" jdbcType="INTEGER"/>
|
||||||
|
...
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- 基础字段 -->
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
id, tag_id, name, color, description, tag_type, creator, updater, create_time,
|
||||||
|
update_time, delete_time, deleted
|
||||||
|
</sql>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Service接口修改
|
||||||
|
|
||||||
|
**文件:** `api\api-news\src\main\java\org\xyzh\api\news\tag\TagService.java`
|
||||||
|
|
||||||
|
**新增方法:**
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* @description 根据标签类型获取标签列表
|
||||||
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
* @return ResultDomain<TbTag> 标签列表
|
||||||
|
*/
|
||||||
|
ResultDomain<TbTag> getTagsByType(Integer tagType);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Service实现类修改
|
||||||
|
|
||||||
|
**文件:** `news\src\main\java\org\xyzh\news\service\impl\NCTagServiceImpl.java`
|
||||||
|
|
||||||
|
**修改内容:**
|
||||||
|
1. createTag 方法:调用 `countByNameAndType` 检查同类型下名称是否重复
|
||||||
|
2. updateTag 方法:调用 `countByNameAndType` 检查同类型下名称是否重复
|
||||||
|
3. 新增 getTagsByType 方法
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public ResultDomain<TbTag> getTagsByType(Integer tagType) {
|
||||||
|
ResultDomain<TbTag> resultDomain = new ResultDomain<>();
|
||||||
|
try {
|
||||||
|
if (tagType == null) {
|
||||||
|
resultDomain.fail("标签类型不能为空");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证标签类型是否有效(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
if (tagType < 1 || tagType > 3) {
|
||||||
|
resultDomain.fail("无效的标签类型");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TbTag> tags = tagMapper.selectByTagType(tagType);
|
||||||
|
resultDomain.success("查询成功", tags);
|
||||||
|
return resultDomain;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("根据类型查询标签异常: {}", e.getMessage(), e);
|
||||||
|
resultDomain.fail("根据类型查询标签失败: " + e.getMessage());
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Controller修改
|
||||||
|
|
||||||
|
**文件:** `news\src\main\java\org\xyzh\news\controller\TagController.java`
|
||||||
|
|
||||||
|
**新增接口:**
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 根据标签类型获取标签列表
|
||||||
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
*/
|
||||||
|
@GetMapping("/type/{tagType}")
|
||||||
|
public ResultDomain<TbTag> getTagsByType(@PathVariable Integer tagType) {
|
||||||
|
return tagService.getTagsByType(tagType);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 API接口说明
|
||||||
|
|
||||||
|
### 新增接口
|
||||||
|
|
||||||
|
**接口路径:** `GET /news/tags/type/{tagType}`
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
| 参数名 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|
|
||||||
|
| tagType | Integer | 是 | 标签类型:1-文章分类标签,2-课程分类标签,3-学习任务分类标签 |
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "查询成功",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "tag001",
|
||||||
|
"tagID": "tag_article_001",
|
||||||
|
"name": "党史",
|
||||||
|
"color": "#ff6b6b",
|
||||||
|
"description": "党史学习相关文章",
|
||||||
|
"tagType": 1,
|
||||||
|
"createTime": "2025-10-27 10:00:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修改的接口
|
||||||
|
|
||||||
|
**创建标签接口:** `POST /news/tags/tag`
|
||||||
|
|
||||||
|
现在创建标签时需要指定 `tagType` 字段:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "新标签",
|
||||||
|
"color": "#ff0000",
|
||||||
|
"description": "标签描述",
|
||||||
|
"tagType": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 注意事项
|
||||||
|
|
||||||
|
### 1. 数据迁移
|
||||||
|
|
||||||
|
如果已有旧数据,需要执行以下SQL为现有标签设置默认类型:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 为现有标签设置默认类型为1(文章分类标签)
|
||||||
|
UPDATE tb_tag SET tag_type = 1 WHERE tag_type IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 唯一性约束变更
|
||||||
|
|
||||||
|
- **旧约束:** 标签名称全局唯一
|
||||||
|
- **新约束:** 标签名称在同一类型下唯一
|
||||||
|
|
||||||
|
这意味着不同类型的标签可以使用相同的名称,例如:
|
||||||
|
- "基础" (tag_type=1, 文章分类标签)
|
||||||
|
- "基础" (tag_type=2, 课程分类标签)
|
||||||
|
|
||||||
|
### 3. 标签类型枚举值
|
||||||
|
|
||||||
|
| 类型值 | 说明 | 枚举常量 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| 1 | 文章分类标签 | TagType.ARTICLE_CATEGORY |
|
||||||
|
| 2 | 课程分类标签 | TagType.COURSE_CATEGORY |
|
||||||
|
| 3 | 学习任务分类标签 | TagType.LEARNING_TASK_CATEGORY |
|
||||||
|
|
||||||
|
### 4. 向后兼容性
|
||||||
|
|
||||||
|
- 所有创建标签的操作必须指定 `tagType`
|
||||||
|
- 如果不指定,将使用默认值1(文章分类标签)
|
||||||
|
- 查询所有标签的接口 `/news/tags/list` 保持不变,会返回所有类型的标签
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 测试建议
|
||||||
|
|
||||||
|
### 1. 功能测试
|
||||||
|
|
||||||
|
- [ ] 创建不同类型的标签
|
||||||
|
- [ ] 验证同类型下标签名称唯一性
|
||||||
|
- [ ] 验证不同类型可以使用相同标签名
|
||||||
|
- [ ] 根据类型查询标签
|
||||||
|
- [ ] 更新标签(包括更改类型)
|
||||||
|
- [ ] 删除标签
|
||||||
|
|
||||||
|
### 2. 数据一致性测试
|
||||||
|
|
||||||
|
- [ ] 检查所有标签都有 `tag_type` 字段
|
||||||
|
- [ ] 验证唯一索引生效
|
||||||
|
- [ ] 测试并发创建同名标签
|
||||||
|
|
||||||
|
### 3. API测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 创建文章分类标签
|
||||||
|
curl -X POST http://localhost:8080/news/tags/tag \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"测试标签","tagType":1,"color":"#ff0000"}'
|
||||||
|
|
||||||
|
# 2. 获取文章分类标签列表
|
||||||
|
curl http://localhost:8080/news/tags/type/1
|
||||||
|
|
||||||
|
# 3. 获取课程分类标签列表
|
||||||
|
curl http://localhost:8080/news/tags/type/2
|
||||||
|
|
||||||
|
# 4. 获取学习任务分类标签列表
|
||||||
|
curl http://localhost:8080/news/tags/type/3
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 相关文件清单
|
||||||
|
|
||||||
|
### 数据库文件
|
||||||
|
- `.bin\mysql\sql\createTableResource.sql` - 建表语句(已注释 tb_resource_category)
|
||||||
|
- `.bin\mysql\sql\initAllData.sql` - 初始化数据(已注释旧分类数据,新增标签数据)
|
||||||
|
|
||||||
|
### 新增/修改的 Java 文件
|
||||||
|
- `common\common-core\src\main\java\org\xyzh\common\core\enums\TagType.java` - 枚举类(新增)
|
||||||
|
- `common\common-dto\src\main\java\org\xyzh\common\dto\resource\TbTag.java` - DTO实体类(修改)
|
||||||
|
- `api\api-news\src\main\java\org\xyzh\api\news\tag\TagService.java` - Service接口(修改)
|
||||||
|
- `news\src\main\java\org\xyzh\news\mapper\TagMapper.java` - Mapper接口(修改)
|
||||||
|
- `news\src\main\resources\mapper\TagMapper.xml` - MyBatis XML(修改)
|
||||||
|
- `news\src\main\java\org\xyzh\news\service\impl\NCTagServiceImpl.java` - Service实现(修改)
|
||||||
|
- `news\src\main\java\org\xyzh\news\controller\TagController.java` - Controller(修改)
|
||||||
|
- `common\common-dto\src\main\java\org\xyzh\common\vo\ResourceVO.java` - VO类(修改,删除 resourceCategory 字段)
|
||||||
|
- `news\src\main\java\org\xyzh\news\controller\ResourceCenterController.java` - 资源中心控制器(修改)
|
||||||
|
|
||||||
|
### 已删除的文件
|
||||||
|
- ~~`common\common-dto\src\main\java\org\xyzh\common\dto\resource\TbResourceCategory.java`~~
|
||||||
|
- ~~`api\api-news\src\main\java\org\xyzh\api\news\category\ResourceCategoryService.java`~~
|
||||||
|
- ~~`news\src\main\java\org\xyzh\news\service\NCResourceCategoryService.java`~~
|
||||||
|
- ~~`news\src\main\java\org\xyzh\news\service\impl\NCResourceCategoryServiceImpl.java`~~
|
||||||
|
- ~~`news\src\main\java\org\xyzh\news\controller\ResourceCategoryController.java`~~
|
||||||
|
- ~~`news\src\main\java\org\xyzh\news\mapper\ResourceCategoryMapper.java`~~
|
||||||
|
- ~~`news\src\main\resources\mapper\ResourceCategoryMapper.xml`~~
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 总结
|
||||||
|
|
||||||
|
本次改造实现了标签系统的类型化管理,使得:
|
||||||
|
1. **统一标签管理** - 将原 `tb_resource_category` 合并到 `tb_tag`,使用统一的标签系统
|
||||||
|
2. **类型化分类** - 文章、课程、学习任务可以使用各自的标签分类体系
|
||||||
|
3. **避免混淆** - 同名标签在不同类型下可独立存在
|
||||||
|
4. **简化架构** - 减少数据表和相关代码,降低维护成本
|
||||||
|
5. **灵活扩展** - 为未来添加新标签类型预留了空间
|
||||||
|
|
||||||
|
### 迁移前后对比
|
||||||
|
|
||||||
|
| 项目 | 迁移前 | 迁移后 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| 数据表 | `tb_tag` + `tb_resource_category` | `tb_tag` (tag_type区分) |
|
||||||
|
| 实体类 | `TbTag` + `TbResourceCategory` | `TbTag` |
|
||||||
|
| Service | `TagService` + `ResourceCategoryService` | `TagService` |
|
||||||
|
| 文章分类 | 使用 `ResourceCategoryService` | 使用 `TagService.getTagsByType(1)` |
|
||||||
|
| 课程分类 | 无 | 使用 `TagService.getTagsByType(2)` |
|
||||||
|
| 学习任务分类 | 无 | 使用 `TagService.getTagsByType(3)` |
|
||||||
|
|
||||||
|
改造完成后,系统将具备更清晰的业务边界、更简洁的代码结构和更灵活的扩展能力。
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ CREATE TABLE `tb_resource` (
|
|||||||
`content` LONGTEXT COMMENT '资源内容',
|
`content` LONGTEXT COMMENT '资源内容',
|
||||||
`summary` VARCHAR(500) DEFAULT NULL COMMENT '资源简介',
|
`summary` VARCHAR(500) DEFAULT NULL COMMENT '资源简介',
|
||||||
`cover_image` VARCHAR(255) DEFAULT NULL COMMENT '封面图片',
|
`cover_image` VARCHAR(255) DEFAULT NULL COMMENT '封面图片',
|
||||||
`category_id` VARCHAR(50) DEFAULT NULL COMMENT '分类ID',
|
`tag_id` VARCHAR(50) DEFAULT NULL COMMENT '标签ID(文章分类标签,tagType=1)',
|
||||||
`author` VARCHAR(100) DEFAULT NULL COMMENT '作者',
|
`author` VARCHAR(100) DEFAULT NULL COMMENT '作者',
|
||||||
`source` VARCHAR(255) DEFAULT NULL COMMENT '来源',
|
`source` VARCHAR(255) DEFAULT NULL COMMENT '来源',
|
||||||
`source_url` VARCHAR(500) DEFAULT NULL COMMENT '来源URL',
|
`source_url` VARCHAR(500) DEFAULT NULL COMMENT '来源URL',
|
||||||
@@ -27,33 +27,12 @@ CREATE TABLE `tb_resource` (
|
|||||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_resource_id` (`resource_id`),
|
KEY `idx_resource_id` (`resource_id`),
|
||||||
KEY `idx_category` (`category_id`),
|
KEY `idx_tag` (`tag_id`),
|
||||||
KEY `idx_status` (`status`),
|
KEY `idx_status` (`status`),
|
||||||
KEY `idx_publish_time` (`publish_time`),
|
KEY `idx_publish_time` (`publish_time`),
|
||||||
KEY `idx_view_count` (`view_count`)
|
KEY `idx_view_count` (`view_count`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资源表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资源表';
|
||||||
|
|
||||||
-- 资源分类表
|
|
||||||
DROP TABLE IF EXISTS `tb_resource_category`;
|
|
||||||
CREATE TABLE `tb_resource_category` (
|
|
||||||
`id` VARCHAR(50) NOT NULL COMMENT '分类ID',
|
|
||||||
`category_id` VARCHAR(50) NOT NULL COMMENT '分类唯一标识',
|
|
||||||
`name` VARCHAR(100) NOT NULL COMMENT '分类名称',
|
|
||||||
`parent_id` VARCHAR(50) DEFAULT NULL COMMENT '父分类ID',
|
|
||||||
`description` VARCHAR(255) DEFAULT NULL COMMENT '分类描述',
|
|
||||||
`icon` VARCHAR(100) DEFAULT NULL COMMENT '分类图标',
|
|
||||||
`order_num` INT(4) DEFAULT 0 COMMENT '排序号',
|
|
||||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
|
||||||
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
|
||||||
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
||||||
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
||||||
`delete_time` TIMESTAMP NULL DEFAULT NULL COMMENT '删除时间',
|
|
||||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_category_id` (`category_id`),
|
|
||||||
KEY `idx_parent` (`parent_id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资源分类表';
|
|
||||||
|
|
||||||
|
|
||||||
-- Banner管理表
|
-- Banner管理表
|
||||||
DROP TABLE IF EXISTS `tb_banner`;
|
DROP TABLE IF EXISTS `tb_banner`;
|
||||||
@@ -103,6 +82,7 @@ CREATE TABLE `tb_tag` (
|
|||||||
`name` VARCHAR(100) NOT NULL COMMENT '标签名称',
|
`name` VARCHAR(100) NOT NULL COMMENT '标签名称',
|
||||||
`color` VARCHAR(20) DEFAULT NULL COMMENT '标签颜色',
|
`color` VARCHAR(20) DEFAULT NULL COMMENT '标签颜色',
|
||||||
`description` VARCHAR(255) DEFAULT NULL COMMENT '标签描述',
|
`description` VARCHAR(255) DEFAULT NULL COMMENT '标签描述',
|
||||||
|
`tag_type` INT(4) DEFAULT 1 COMMENT '标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)',
|
||||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||||
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
||||||
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
@@ -111,7 +91,8 @@ CREATE TABLE `tb_tag` (
|
|||||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `uk_tag_id` (`tag_id`),
|
UNIQUE KEY `uk_tag_id` (`tag_id`),
|
||||||
UNIQUE KEY `uk_tag_name` (`name`)
|
UNIQUE KEY `uk_tag_name_type` (`name`, `tag_type`),
|
||||||
|
KEY `idx_tag_type` (`tag_type`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='标签表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='标签表';
|
||||||
|
|
||||||
-- 资源标签关联表
|
-- 资源标签关联表
|
||||||
@@ -136,7 +117,7 @@ CREATE TABLE `tb_data_collection_config` (
|
|||||||
`source_url` VARCHAR(500) NOT NULL COMMENT '采集源URL',
|
`source_url` VARCHAR(500) NOT NULL COMMENT '采集源URL',
|
||||||
`source_type` VARCHAR(50) DEFAULT NULL COMMENT '采集源类型',
|
`source_type` VARCHAR(50) DEFAULT NULL COMMENT '采集源类型',
|
||||||
`frequency` VARCHAR(20) DEFAULT 'daily' COMMENT '采集频率(daily每天 weekly每周)',
|
`frequency` VARCHAR(20) DEFAULT 'daily' COMMENT '采集频率(daily每天 weekly每周)',
|
||||||
`category_id` VARCHAR(50) DEFAULT NULL COMMENT '默认分类ID',
|
`tag_id` VARCHAR(50) DEFAULT NULL COMMENT '默认标签ID(文章分类标签,tagType=1)',
|
||||||
`status` INT(4) DEFAULT 1 COMMENT '状态(0禁用 1启用)',
|
`status` INT(4) DEFAULT 1 COMMENT '状态(0禁用 1启用)',
|
||||||
`last_collect_time` TIMESTAMP NULL DEFAULT NULL COMMENT '最后采集时间',
|
`last_collect_time` TIMESTAMP NULL DEFAULT NULL COMMENT '最后采集时间',
|
||||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||||
|
|||||||
@@ -4,14 +4,30 @@ use school_news;
|
|||||||
INSERT INTO `tb_ai_agent_config` (id, name, system_prompt, model_name, temperature, max_tokens, status, creator, create_time) VALUES
|
INSERT INTO `tb_ai_agent_config` (id, name, system_prompt, model_name, temperature, max_tokens, status, creator, create_time) VALUES
|
||||||
('1', '思政小帮手', '你是一个专业的思政学习助手,致力于帮助用户学习思想政治理论知识。请基于提供的知识库内容,为用户提供准确、简洁的回答。', 'gpt-3.5-turbo', 0.7, 2000, 1, '1', now());
|
('1', '思政小帮手', '你是一个专业的思政学习助手,致力于帮助用户学习思想政治理论知识。请基于提供的知识库内容,为用户提供准确、简洁的回答。', 'gpt-3.5-turbo', 0.7, 2000, 1, '1', now());
|
||||||
|
|
||||||
-- 插入资源分类数据
|
-- 插入标签数据 (文章分类标签 tag_type=1)
|
||||||
INSERT INTO `tb_resource_category` (id, category_id, name, description, order_num, creator, create_time) VALUES
|
INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, create_time) VALUES
|
||||||
('1', 'party_history', '党史学习', '党史学习相关资源', 1, '1', now()),
|
('tag001', 'tag_article_001', '党史学习', '#ff6b6b', '党史学习相关文章', 1, '1', now()),
|
||||||
('2', 'leader_speech', '领导讲话', '领导讲话相关资源', 2, '1', now()),
|
('tag002', 'tag_article_002', '领导讲话', '#4ecdc4', '领导讲话相关文章', 1, '1', now()),
|
||||||
('3', 'policy_interpretation', '政策解读', '政策解读相关资源', 3, '1', now()),
|
('tag003', 'tag_article_003', '政策解读', '#45b7d1', '政策解读相关文章', 1, '1', now()),
|
||||||
('4', 'red_classic', '红色经典', '红色经典相关资源', 4, '1', now()),
|
('tag004', 'tag_article_004', '红色经典', '#f7b731', '红色经典相关文章', 1, '1', now()),
|
||||||
('5', 'special_report', '专题报告', '专题报告相关资源', 5, '1', now()),
|
('tag005', 'tag_article_005', '专题报告', '#45c7c1', '专题报告相关文章', 1, '1', now()),
|
||||||
('6', 'world_case', '思政案例', '思政案例相关资源', 6, '1', now());
|
('tag006', 'tag_article_006', '思政案例', '#5f27cd', '思政案例相关文章', 1, '1', now());
|
||||||
|
|
||||||
|
-- 插入标签数据 (课程分类标签 tag_type=2)
|
||||||
|
INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, create_time) VALUES
|
||||||
|
('tag101', 'tag_course_001', '基础课程', '#26de81', '基础思政课程', 2, '1', now()),
|
||||||
|
('tag102', 'tag_course_002', '专题课程', '#fc5c65', '专题思政课程', 2, '1', now()),
|
||||||
|
('tag103', 'tag_course_003', '实践课程', '#fd9644', '实践类思政课程', 2, '1', now()),
|
||||||
|
('tag104', 'tag_course_004', '在线课程', '#a55eea', '在线学习课程', 2, '1', now()),
|
||||||
|
('tag105', 'tag_course_005', '热门课程', '#eb3b5a', '热门推荐课程', 2, '1', now());
|
||||||
|
|
||||||
|
-- 插入标签数据 (学习任务分类标签 tag_type=3)
|
||||||
|
INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, create_time) VALUES
|
||||||
|
('tag201', 'tag_task_001', '每日学习', '#20bf6b', '每日学习任务', 3, '1', now()),
|
||||||
|
('tag202', 'tag_task_002', '专题学习', '#fa8231', '专题学习任务', 3, '1', now()),
|
||||||
|
('tag203', 'tag_task_003', '考核任务', '#0fb9b1', '考核类学习任务', 3, '1', now()),
|
||||||
|
('tag204', 'tag_task_004', '实践任务', '#f7b731', '实践类学习任务', 3, '1', now()),
|
||||||
|
('tag205', 'tag_task_005', '阶段任务', '#2d98da', '阶段性学习任务', 3, '1', now());
|
||||||
|
|
||||||
-- 插入系统配置数据
|
-- 插入系统配置数据
|
||||||
INSERT INTO `tb_sys_config` (id, config_key, config_value, config_type, config_group, description, is_system, creator, create_time) VALUES
|
INSERT INTO `tb_sys_config` (id, config_key, config_value, config_type, config_group, description, is_system, creator, create_time) VALUES
|
||||||
|
|||||||
@@ -98,60 +98,60 @@ INSERT INTO `tb_sys_menu` (id, menu_id, name, parent_id, url, component, icon, o
|
|||||||
-- 智能体模块
|
-- 智能体模块
|
||||||
('600', 'menu_ai_assistant', '智能体模块', NULL, '/ai-assistant', 'ai-assistant/AIAssistantView', 'el-icon-cpu', 6, 1, 'NavigationLayout', '1', now());
|
('600', 'menu_ai_assistant', '智能体模块', NULL, '/ai-assistant', 'ai-assistant/AIAssistantView', 'el-icon-cpu', 6, 1, 'NavigationLayout', '1', now());
|
||||||
|
|
||||||
-- 插入后端管理菜单数据
|
-- 插入后端管理菜单数据 (type=0 侧边栏菜单)
|
||||||
INSERT INTO `tb_sys_menu` (id, menu_id, name, parent_id, url, component, icon, order_num, type, layout, creator, create_time) VALUES
|
INSERT INTO `tb_sys_menu` (id, menu_id, name, parent_id, url, component, icon, order_num, type, layout, creator, create_time) VALUES
|
||||||
-- 系统总览
|
-- 系统总览
|
||||||
('1000', 'menu_admin_overview', '系统总览', NULL, '/admin/overview', 'admin/overview/SystemOverviewView', 'el-icon-data-analysis', 1, 1, 'NavigationLayout', '1', now()),
|
('1000', 'menu_admin_overview', '系统总览', NULL, '/admin/overview', 'admin/overview/SystemOverviewView', 'el-icon-data-analysis', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
|
|
||||||
-- 用户管理
|
-- 用户管理
|
||||||
('2000', 'menu_sys_manage', '系统管理', NULL, '', '', 'el-icon-user', 2, 1, '', '1', now()),
|
('2000', 'menu_sys_manage', '系统管理', NULL, '', '', 'el-icon-user', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('2001', 'menu_admin_user', '用户管理', 'menu_sys_manage', '/admin/manage/system/user', 'admin/manage/system/UserManageView', 'el-icon-user', 1, 1, 'NavigationLayout', '1', now()),
|
('2001', 'menu_admin_user', '用户管理', 'menu_sys_manage', '/admin/manage/system/user', 'admin/manage/system/UserManageView', 'el-icon-user', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
('2002', 'menu_admin_dept', '部门管理', 'menu_sys_manage', '/admin/manage/system/dept', 'admin/manage/system/DeptManageView', 'el-icon-office-building', 2, 1, 'NavigationLayout', '1', now()),
|
('2002', 'menu_admin_dept', '部门管理', 'menu_sys_manage', '/admin/manage/system/dept', 'admin/manage/system/DeptManageView', 'el-icon-office-building', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('2003', 'menu_admin_role', '角色管理', 'menu_sys_manage', '/admin/manage/system/role', 'admin/manage/system/RoleManageView', 'el-icon-user-solid', 3, 1, 'NavigationLayout', '1', now()),
|
('2003', 'menu_admin_role', '角色管理', 'menu_sys_manage', '/admin/manage/system/role', 'admin/manage/system/RoleManageView', 'el-icon-user-solid', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
('2005', 'menu_admin_menu', '菜单管理', 'menu_sys_manage', '/admin/manage/system/menu', 'admin/manage/system/MenuManageView', 'el-icon-menu', 4, 1, 'NavigationLayout', '1', now()),
|
('2005', 'menu_admin_menu', '菜单管理', 'menu_sys_manage', '/admin/manage/system/menu', 'admin/manage/system/MenuManageView', 'el-icon-menu', 4, 0, 'SidebarLayout', '1', now()),
|
||||||
('2006', 'menu_admin_module', '模块权限管理', 'menu_sys_manage', '/admin/manage/system/module-permission', 'admin/manage/system/ModulePermissionManageView', 'el-icon-s-grid', 5, 1, 'NavigationLayout', '1', now()),
|
('2006', 'menu_admin_module', '模块权限管理', 'menu_sys_manage', '/admin/manage/system/module-permission', 'admin/manage/system/ModulePermissionManageView', 'el-icon-s-grid', 5, 0, 'SidebarLayout', '1', now()),
|
||||||
|
|
||||||
-- 资源管理
|
-- 资源管理
|
||||||
('3000', 'menu_admin_resource_manage', '资源管理', NULL, '', '', 'el-icon-folder', 3, 1, '', '1', now()),
|
('3000', 'menu_admin_resource_manage', '资源管理', NULL, '', '', 'el-icon-folder', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
('3001', 'menu_admin_resource', '资源管理', 'menu_admin_resource_manage', '/admin/manage/resource/resource', 'admin/manage/resource/ResourceManagementView', 'el-icon-folder', 1, 1, 'NavigationLayout', '1', now()),
|
('3001', 'menu_admin_resource', '资源管理', 'menu_admin_resource_manage', '/admin/manage/resource/resource', 'admin/manage/resource/ResourceManagementView', 'el-icon-folder', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
('3002', 'menu_admin_article', '文章管理', 'menu_admin_resource_manage', '/admin/manage/resource/article', 'admin/manage/resource/ArticleManagementView', 'el-icon-document', 2, 1, 'NavigationLayout', '1', now()),
|
('3002', 'menu_admin_article', '文章管理', 'menu_admin_resource_manage', '/admin/manage/resource/article', 'admin/manage/resource/ArticleManagementView', 'el-icon-document', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('3003', 'menu_admin_data_records', '数据记录', 'menu_admin_resource_manage', '/admin/manage/resource/data-records', 'admin/manage/resource/DataRecordsView', 'el-icon-data-line', 3, 1, 'NavigationLayout', '1', now()),
|
('3003', 'menu_admin_data_records', '数据记录', 'menu_admin_resource_manage', '/admin/manage/resource/data-records', 'admin/manage/resource/DataRecordsView', 'el-icon-data-line', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
|
|
||||||
|
|
||||||
-- 文章相关
|
-- 文章相关
|
||||||
('3010', 'menu_article_add', '文章添加', 'menu_admin_article', '/article/add', 'article/ArticleAddView', 'el-icon-plus', 1, 3, 'NavigationLayout', '1', now()),
|
('3010', 'menu_article_add', '文章添加', 'menu_admin_article', '/article/add', 'article/ArticleAddView', 'el-icon-plus', 1, 3, 'SidebarLayout', '1', now()),
|
||||||
('3011', 'menu_article_show', '文章展示', 'menu_admin_article', '/article/show', 'article/ArticleShowView', 'el-icon-document', 2, 3, 'NavigationLayout', '1', now()),
|
('3011', 'menu_article_show', '文章展示', 'menu_admin_article', '/article/show', 'article/ArticleShowView', 'el-icon-document', 2, 3, 'SidebarLayout', '1', now()),
|
||||||
-- 运营管理
|
-- 运营管理
|
||||||
('4000', 'menu_admin_content_manage', '运营管理', NULL, '', '', 'el-icon-s-operation', 4, 1, '', '1', now()),
|
('4000', 'menu_admin_content_manage', '运营管理', NULL, '', '', 'el-icon-s-operation', 4, 0, 'SidebarLayout', '1', now()),
|
||||||
('4001', 'menu_admin_banner', 'Banner管理', 'menu_admin_content_manage', '/admin/manage/content/banner', 'admin/manage/content/BannerManagementView', 'el-icon-picture', 1, 1, 'NavigationLayout', '1', now()),
|
('4001', 'menu_admin_banner', 'Banner管理', 'menu_admin_content_manage', '/admin/manage/content/banner', 'admin/manage/content/BannerManagementView', 'el-icon-picture', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
('4002', 'menu_admin_tag', '标签管理', 'menu_admin_content_manage', '/admin/manage/content/tag', 'admin/manage/content/TagManagementView', 'el-icon-price-tag', 2, 1, 'NavigationLayout', '1', now()),
|
('4002', 'menu_admin_tag', '标签管理', 'menu_admin_content_manage', '/admin/manage/content/tag', 'admin/manage/content/TagManagementView', 'el-icon-price-tag', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('4003', 'menu_admin_column', '栏目管理', 'menu_admin_content_manage', '/admin/manage/content/column', 'admin/manage/content/ColumnManagementView', 'el-icon-menu', 3, 1, 'NavigationLayout', '1', now()),
|
('4003', 'menu_admin_column', '栏目管理', 'menu_admin_content_manage', '/admin/manage/content/column', 'admin/manage/content/ColumnManagementView', 'el-icon-menu', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
('4004', 'menu_admin_content', '内容管理', 'menu_admin_content_manage', '/admin/manage/content/content', 'admin/manage/content/ContentManagementView', 'el-icon-document', 4, 1, 'NavigationLayout', '1', now()),
|
('4004', 'menu_admin_content', '内容管理', 'menu_admin_content_manage', '/admin/manage/content/content', 'admin/manage/content/ContentManagementView', 'el-icon-document', 4, 0, 'SidebarLayout', '1', now()),
|
||||||
|
|
||||||
-- 学习管理
|
-- 学习管理
|
||||||
('5000', 'menu_admin_study_manage', '学习管理', NULL, '', '', 'el-icon-reading', 5, 1, '', '1', now()),
|
('5000', 'menu_admin_study_manage', '学习管理', NULL, '', '', 'el-icon-reading', 5, 0, 'SidebarLayout', '1', now()),
|
||||||
('5002', 'menu_admin_task_manage', '任务管理', 'menu_admin_study_manage', '/admin/manage/study/task-manage', 'admin/manage/study/TaskManageView', 'el-icon-s-order', 2, 1, 'NavigationLayout', '1', now()),
|
('5002', 'menu_admin_task_manage', '任务管理', 'menu_admin_study_manage', '/admin/manage/study/task-manage', 'admin/manage/study/TaskManageView', 'el-icon-s-order', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('5003', 'menu_admin_study_records', '学习记录', 'menu_admin_study_manage', '/admin/manage/study/study-records', 'admin/manage/study/StudyRecordsView', 'el-icon-document', 3, 1, 'NavigationLayout', '1', now()),
|
('5003', 'menu_admin_study_records', '学习记录', 'menu_admin_study_manage', '/admin/manage/study/study-records', 'admin/manage/study/StudyRecordsView', 'el-icon-document', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
('5004', 'menu_admin_course_manage', '课程管理', 'menu_admin_study_manage', '/admin/manage/study/course', 'admin/manage/study/CourseManagementView', 'el-icon-video-play', 4, 1, 'NavigationLayout', '1', now()),
|
('5004', 'menu_admin_course_manage', '课程管理', 'menu_admin_study_manage', '/admin/manage/study/course', 'admin/manage/study/CourseManagementView', 'el-icon-video-play', 4, 0, 'SidebarLayout', '1', now()),
|
||||||
('5005', 'menu_admin_achievement_manage', '成就管理', 'menu_admin_study_manage', '/admin/manage/study/achievement', 'admin/manage/achievement/AchievementManagementView', 'el-icon-trophy', 5, 1, 'NavigationLayout', '1', now()),
|
('5005', 'menu_admin_achievement_manage', '成就管理', 'menu_admin_study_manage', '/admin/manage/study/achievement', 'admin/manage/achievement/AchievementManagementView', 'el-icon-trophy', 5, 0, 'SidebarLayout', '1', now()),
|
||||||
-- 智能体管理
|
-- 智能体管理
|
||||||
('6000', 'menu_admin_ai_manage', '智能体管理', NULL, '', '', 'el-icon-cpu', 6, 1, '', '1', now()),
|
('6000', 'menu_admin_ai_manage', '智能体管理', NULL, '', '', 'el-icon-cpu', 6, 0, 'SidebarLayout', '1', now()),
|
||||||
('6001', 'menu_admin_ai', 'AI管理', 'menu_admin_ai_manage', '/admin/manage/ai/ai', 'admin/manage/ai/AIManagementView', 'el-icon-cpu', 1, 1, 'NavigationLayout', '1', now()),
|
('6001', 'menu_admin_ai', 'AI管理', 'menu_admin_ai_manage', '/admin/manage/ai/ai', 'admin/manage/ai/AIManagementView', 'el-icon-cpu', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
('6002', 'menu_admin_ai_config', 'AI配置', 'menu_admin_ai_manage', '/admin/manage/ai/config', 'admin/manage/ai/AIConfigView', 'el-icon-setting', 2, 1, 'NavigationLayout', '1', now()),
|
('6002', 'menu_admin_ai_config', 'AI配置', 'menu_admin_ai_manage', '/admin/manage/ai/config', 'admin/manage/ai/AIConfigView', 'el-icon-setting', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('6003', 'menu_admin_knowledge', '知识库管理', 'menu_admin_ai_manage', '/admin/manage/ai/knowledge', 'admin/manage/ai/KnowledgeManagementView', 'el-icon-collection', 3, 1, 'NavigationLayout', '1', now()),
|
('6003', 'menu_admin_knowledge', '知识库管理', 'menu_admin_ai_manage', '/admin/manage/ai/knowledge', 'admin/manage/ai/KnowledgeManagementView', 'el-icon-collection', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
|
|
||||||
-- 系统日志
|
-- 系统日志
|
||||||
('7000', 'menu_admin_logs_manage', '系统日志', NULL, '', '', 'el-icon-document', 7, 1, '', '1', now()),
|
('7000', 'menu_admin_logs_manage', '系统日志', NULL, '', '', 'el-icon-document', 7, 0, 'SidebarLayout', '1', now()),
|
||||||
('7001', 'menu_admin_system_logs', '系统日志', 'menu_admin_logs_manage', '/admin/manage/logs/system', 'admin/manage/logs/SystemLogsView', 'el-icon-document', 1, 1, 'NavigationLayout', '1', now()),
|
('7001', 'menu_admin_system_logs', '系统日志', 'menu_admin_logs_manage', '/admin/manage/logs/system', 'admin/manage/logs/SystemLogsView', 'el-icon-document', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
('7002', 'menu_admin_login_logs', '登录日志', 'menu_admin_logs_manage', '/admin/manage/logs/login', 'admin/manage/logs/LoginLogsView', 'el-icon-key', 2, 1, 'NavigationLayout', '1', now()),
|
('7002', 'menu_admin_login_logs', '登录日志', 'menu_admin_logs_manage', '/admin/manage/logs/login', 'admin/manage/logs/LoginLogsView', 'el-icon-key', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('7003', 'menu_admin_operation_logs', '操作日志', 'menu_admin_logs_manage', '/admin/manage/logs/operation', 'admin/manage/logs/OperationLogsView', 'el-icon-s-operation', 3, 1, 'NavigationLayout', '1', now()),
|
('7003', 'menu_admin_operation_logs', '操作日志', 'menu_admin_logs_manage', '/admin/manage/logs/operation', 'admin/manage/logs/OperationLogsView', 'el-icon-s-operation', 3, 0, 'SidebarLayout', '1', now()),
|
||||||
('7004', 'menu_admin_system_config', '系统配置', 'menu_admin_logs_manage', '/admin/manage/logs/config', 'admin/manage/logs/SystemConfigView', 'el-icon-setting', 4, 1, 'NavigationLayout', '1', now()),
|
('7004', 'menu_admin_system_config', '系统配置', 'menu_admin_logs_manage', '/admin/manage/logs/config', 'admin/manage/logs/SystemConfigView', 'el-icon-setting', 4, 0, 'SidebarLayout', '1', now()),
|
||||||
|
|
||||||
-- 定时任务管理
|
-- 定时任务管理
|
||||||
('8000', 'menu_admin_crontab_manage', '定时任务管理', NULL, '', '', 'el-icon-alarm-clock', 8, 1, '', '1', now()),
|
('8000', 'menu_admin_crontab_manage', '定时任务管理', NULL, '', '', 'el-icon-alarm-clock', 8, 0, 'SidebarLayout', '1', now()),
|
||||||
('8001', 'menu_admin_crontab_task', '任务管理', 'menu_admin_crontab_manage', '/admin/manage/crontab/task', 'admin/manage/crontab/TaskManagementView', 'el-icon-s-order', 1, 1, 'NavigationLayout', '1', now()),
|
('8001', 'menu_admin_crontab_task', '任务管理', 'menu_admin_crontab_manage', '/admin/manage/crontab/task', 'admin/manage/crontab/TaskManagementView', 'el-icon-s-order', 1, 0, 'SidebarLayout', '1', now()),
|
||||||
('8002', 'menu_admin_crontab_log', '执行日志', 'menu_admin_crontab_manage', '/admin/manage/crontab/log', 'admin/manage/crontab/LogManagementView', 'el-icon-document', 2, 1, 'NavigationLayout', '1', now()),
|
('8002', 'menu_admin_crontab_log', '执行日志', 'menu_admin_crontab_manage', '/admin/manage/crontab/log', 'admin/manage/crontab/LogManagementView', 'el-icon-document', 2, 0, 'SidebarLayout', '1', now()),
|
||||||
('8003', 'menu_admin_news_crawler', '新闻爬虫配置', 'menu_admin_crontab_manage', '/admin/manage/crontab/news-crawler', 'admin/manage/crontab/NewsCrawlerView', 'el-icon-share', 3, 1, 'NavigationLayout', '1', now());
|
('8003', 'menu_admin_news_crawler', '新闻爬虫配置', 'menu_admin_crontab_manage', '/admin/manage/crontab/news-crawler', 'admin/manage/crontab/NewsCrawlerView', 'el-icon-share', 3, 0, 'SidebarLayout', '1', now());
|
||||||
|
|
||||||
-- 插入菜单权限关联数据
|
-- 插入菜单权限关联数据
|
||||||
INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, create_time) VALUES
|
INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, create_time) VALUES
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
package org.xyzh.api.news.category;
|
|
||||||
|
|
||||||
import org.xyzh.common.core.domain.ResultDomain;
|
|
||||||
import org.xyzh.common.dto.resource.TbResourceCategory;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 资源分类服务接口
|
|
||||||
* @filename ResourceCategoryService.java
|
|
||||||
* @author yslg
|
|
||||||
* @copyright xyzh
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
public interface ResourceCategoryService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取所有分类列表
|
|
||||||
* @return ResultDomain<TbResourceCategory> 分类列表
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> getAllCategories();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取分类树形结构
|
|
||||||
* @return ResultDomain<TbResourceCategory> 分类树
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> getCategoryTree();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 根据ID获取分类详情
|
|
||||||
* @param categoryID 分类ID
|
|
||||||
* @return ResultDomain<TbResourceCategory> 分类详情
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> getCategoryById(String categoryID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 根据父ID获取子分类
|
|
||||||
* @param parentID 父分类ID
|
|
||||||
* @return ResultDomain<TbResourceCategory> 子分类列表
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> getCategoriesByParent(String parentID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 创建分类
|
|
||||||
* @param category 分类信息
|
|
||||||
* @return ResultDomain<TbResourceCategory> 创建结果
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> createCategory(TbResourceCategory category);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 更新分类
|
|
||||||
* @param category 分类信息
|
|
||||||
* @return ResultDomain<TbResourceCategory> 更新结果
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> updateCategory(TbResourceCategory category);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 删除分类
|
|
||||||
* @param categoryID 分类ID
|
|
||||||
* @return ResultDomain<Boolean> 删除结果
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<Boolean> deleteCategory(String categoryID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 更新分类排序
|
|
||||||
* @param categoryID 分类ID
|
|
||||||
* @param orderNum 排序号
|
|
||||||
* @return ResultDomain<TbResourceCategory> 更新结果
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<TbResourceCategory> updateCategoryOrder(String categoryID, Integer orderNum);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 检查分类是否有子分类
|
|
||||||
* @param categoryID 分类ID
|
|
||||||
* @return ResultDomain<Boolean> 是否有子分类
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<Boolean> hasChildCategories(String categoryID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 检查分类下是否有资源
|
|
||||||
* @param categoryID 分类ID
|
|
||||||
* @return ResultDomain<Boolean> 是否有资源
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
ResultDomain<Boolean> hasResources(String categoryID);
|
|
||||||
}
|
|
||||||
@@ -167,11 +167,11 @@ public interface ResourceService {
|
|||||||
/**
|
/**
|
||||||
* @description 搜索资源
|
* @description 搜索资源
|
||||||
* @param keyword 关键词
|
* @param keyword 关键词
|
||||||
* @param categoryID 分类ID(可选)
|
* @param tagID 分类ID(可选)
|
||||||
* @param status 状态(可选)
|
* @param status 状态(可选)
|
||||||
* @return ResultDomain<TbResource> 搜索结果
|
* @return ResultDomain<TbResource> 搜索结果
|
||||||
* @author yslg
|
* @author yslg
|
||||||
* @since 2025-10-15
|
* @since 2025-10-15
|
||||||
*/
|
*/
|
||||||
ResultDomain<TbResource> searchResources(String keyword, String categoryID, Integer status);
|
ResultDomain<TbResource> searchResources(String keyword, String tagID, Integer status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,15 @@ public interface TagService {
|
|||||||
*/
|
*/
|
||||||
ResultDomain<TbTag> searchTagsByName(String name);
|
ResultDomain<TbTag> searchTagsByName(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 根据标签类型获取标签列表
|
||||||
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
* @return ResultDomain<TbTag> 标签列表
|
||||||
|
* @author yslg
|
||||||
|
* @since 2025-10-27
|
||||||
|
*/
|
||||||
|
ResultDomain<TbTag> getTagsByType(Integer tagType);
|
||||||
|
|
||||||
// ----------------资源标签关联相关--------------------------------
|
// ----------------资源标签关联相关--------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ public class TbDataCollectionConfig extends BaseDTO {
|
|||||||
private String frequency;
|
private String frequency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 默认分类ID
|
* @description 默认标签ID(文章分类标签,tagType=1)
|
||||||
*/
|
*/
|
||||||
private String categoryID;
|
private String tagID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 状态(0禁用 1启用)
|
* @description 状态(0禁用 1启用)
|
||||||
@@ -91,12 +91,12 @@ public class TbDataCollectionConfig extends BaseDTO {
|
|||||||
this.frequency = frequency;
|
this.frequency = frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCategoryID() {
|
public String getTagID() {
|
||||||
return categoryID;
|
return tagID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCategoryID(String categoryID) {
|
public void setTagID(String tagID) {
|
||||||
this.categoryID = categoryID;
|
this.tagID = tagID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getStatus() {
|
public Integer getStatus() {
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public class TbResource extends BaseDTO {
|
|||||||
private String coverImage;
|
private String coverImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 分类ID
|
* @description 标签ID(文章分类标签,tagType=1)
|
||||||
*/
|
*/
|
||||||
private String categoryID;
|
private String tagID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 作者
|
* @description 作者
|
||||||
@@ -144,12 +144,12 @@ public class TbResource extends BaseDTO {
|
|||||||
this.coverImage = coverImage;
|
this.coverImage = coverImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCategoryID() {
|
public String getTagID() {
|
||||||
return categoryID;
|
return tagID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCategoryID(String categoryID) {
|
public void setTagID(String tagID) {
|
||||||
this.categoryID = categoryID;
|
this.tagID = tagID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuthor() {
|
public String getAuthor() {
|
||||||
@@ -254,7 +254,7 @@ public class TbResource extends BaseDTO {
|
|||||||
"id=" + getID() +
|
"id=" + getID() +
|
||||||
", resourceID='" + resourceID + '\'' +
|
", resourceID='" + resourceID + '\'' +
|
||||||
", title='" + title + '\'' +
|
", title='" + title + '\'' +
|
||||||
", categoryID='" + categoryID + '\'' +
|
", tagID='" + tagID + '\'' +
|
||||||
", author='" + author + '\'' +
|
", author='" + author + '\'' +
|
||||||
", status=" + status +
|
", status=" + status +
|
||||||
", viewCount=" + viewCount +
|
", viewCount=" + viewCount +
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
package org.xyzh.common.dto.resource;
|
|
||||||
|
|
||||||
import org.xyzh.common.dto.BaseDTO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 资源分类表
|
|
||||||
* @filename TbResourceCategory.java
|
|
||||||
* @author yslg
|
|
||||||
* @copyright xyzh
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
public class TbResourceCategory extends BaseDTO {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 分类唯一标识
|
|
||||||
*/
|
|
||||||
private String categoryID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 分类名称
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 父分类ID
|
|
||||||
*/
|
|
||||||
private String parentID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 分类描述
|
|
||||||
*/
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 分类图标
|
|
||||||
*/
|
|
||||||
private String icon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 排序号
|
|
||||||
*/
|
|
||||||
private Integer orderNum;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 创建者
|
|
||||||
*/
|
|
||||||
private String creator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 更新者
|
|
||||||
*/
|
|
||||||
private String updater;
|
|
||||||
|
|
||||||
public String getCategoryID() {
|
|
||||||
return categoryID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCategoryID(String categoryID) {
|
|
||||||
this.categoryID = categoryID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getParentID() {
|
|
||||||
return parentID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParentID(String parentID) {
|
|
||||||
this.parentID = parentID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIcon() {
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIcon(String icon) {
|
|
||||||
this.icon = icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getOrderNum() {
|
|
||||||
return orderNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOrderNum(Integer orderNum) {
|
|
||||||
this.orderNum = orderNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCreator() {
|
|
||||||
return creator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreator(String creator) {
|
|
||||||
this.creator = creator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUpdater() {
|
|
||||||
return updater;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdater(String updater) {
|
|
||||||
this.updater = updater;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "TbResourceCategory{" +
|
|
||||||
"id=" + getID() +
|
|
||||||
", categoryID='" + categoryID + '\'' +
|
|
||||||
", name='" + name + '\'' +
|
|
||||||
", parentID='" + parentID + '\'' +
|
|
||||||
", orderNum=" + orderNum +
|
|
||||||
", createTime=" + getCreateTime() +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,6 +33,11 @@ public class TbTag extends BaseDTO {
|
|||||||
*/
|
*/
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 标签类型 1-文章分类标签 2-课程分类标签 3-学习任务分类标签
|
||||||
|
*/
|
||||||
|
private Integer tagType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 创建者
|
* @description 创建者
|
||||||
*/
|
*/
|
||||||
@@ -91,6 +96,14 @@ public class TbTag extends BaseDTO {
|
|||||||
this.updater = updater;
|
this.updater = updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getTagType() {
|
||||||
|
return tagType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTagType(Integer tagType) {
|
||||||
|
this.tagType = tagType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TbTag{" +
|
return "TbTag{" +
|
||||||
@@ -98,6 +111,7 @@ public class TbTag extends BaseDTO {
|
|||||||
", tagID='" + tagID + '\'' +
|
", tagID='" + tagID + '\'' +
|
||||||
", name='" + name + '\'' +
|
", name='" + name + '\'' +
|
||||||
", color='" + color + '\'' +
|
", color='" + color + '\'' +
|
||||||
|
", tagType=" + tagType +
|
||||||
", createTime=" + getCreateTime() +
|
", createTime=" + getCreateTime() +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.xyzh.common.vo;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.xyzh.common.dto.resource.TbResource;
|
import org.xyzh.common.dto.resource.TbResource;
|
||||||
import org.xyzh.common.dto.resource.TbResourceCategory;
|
|
||||||
import org.xyzh.common.dto.resource.TbTag;
|
import org.xyzh.common.dto.resource.TbTag;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -20,8 +19,9 @@ public class ResourceVO implements Serializable{
|
|||||||
|
|
||||||
private TbResource resource;
|
private TbResource resource;
|
||||||
|
|
||||||
private TbResourceCategory resourceCategory;
|
/**
|
||||||
|
* 资源标签列表(包含文章分类标签 tag_type=1)
|
||||||
|
*/
|
||||||
private List<TbTag> tags;
|
private List<TbTag> tags;
|
||||||
|
|
||||||
public TbResource getResource() {
|
public TbResource getResource() {
|
||||||
@@ -32,13 +32,6 @@ public class ResourceVO implements Serializable{
|
|||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TbResourceCategory getResourceCategory() {
|
|
||||||
return resourceCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setResourceCategory(TbResourceCategory resourceCategory) {
|
|
||||||
this.resourceCategory = resourceCategory;
|
|
||||||
}
|
|
||||||
public List<TbTag> getTags() {
|
public List<TbTag> getTags() {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
package org.xyzh.news.controller;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.xyzh.api.news.category.ResourceCategoryService;
|
|
||||||
import org.xyzh.common.core.domain.ResultDomain;
|
|
||||||
import org.xyzh.common.dto.resource.TbResourceCategory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 资源分类控制器
|
|
||||||
* @filename ResourceCategoryController.java
|
|
||||||
* @author yslg
|
|
||||||
* @copyright xyzh
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/news/categorys")
|
|
||||||
public class ResourceCategoryController {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ResourceCategoryController.class);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ResourceCategoryService resourceCategoryService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取分类列表
|
|
||||||
*/
|
|
||||||
@GetMapping("/list")
|
|
||||||
public ResultDomain<TbResourceCategory> getCategoryList() {
|
|
||||||
return resourceCategoryService.getAllCategories();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据ID获取分类详情
|
|
||||||
*/
|
|
||||||
@GetMapping("/category/{categoryID}")
|
|
||||||
public ResultDomain<TbResourceCategory> getCategoryById(@PathVariable String categoryID) {
|
|
||||||
return resourceCategoryService.getCategoryById(categoryID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建分类
|
|
||||||
*/
|
|
||||||
@PostMapping("/category")
|
|
||||||
public ResultDomain<TbResourceCategory> createCategory(@RequestBody TbResourceCategory category) {
|
|
||||||
return resourceCategoryService.createCategory(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新分类
|
|
||||||
*/
|
|
||||||
@PutMapping("/category")
|
|
||||||
public ResultDomain<TbResourceCategory> updateCategory(@RequestBody TbResourceCategory category) {
|
|
||||||
return resourceCategoryService.updateCategory(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除分类
|
|
||||||
*/
|
|
||||||
@DeleteMapping("/category/{categoryID}")
|
|
||||||
public ResultDomain<Boolean> deleteCategory(@PathVariable String categoryID) {
|
|
||||||
return resourceCategoryService.deleteCategory(categoryID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新分类状态
|
|
||||||
*/
|
|
||||||
@PutMapping("/category/{categoryID}/status")
|
|
||||||
public ResultDomain<TbResourceCategory> updateCategoryStatus(@PathVariable String categoryID, @RequestParam Integer status) {
|
|
||||||
return null;
|
|
||||||
// return resourceCategoryService.updateCategoryStatus(categoryID, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取分类树
|
|
||||||
*/
|
|
||||||
@GetMapping("/tree")
|
|
||||||
public ResultDomain<TbResourceCategory> getCategoryTree() {
|
|
||||||
return resourceCategoryService.getCategoryTree();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取子分类
|
|
||||||
*/
|
|
||||||
@GetMapping("/category/{parentID}/children")
|
|
||||||
public ResultDomain<TbResourceCategory> getChildCategories(@PathVariable String parentID) {
|
|
||||||
return resourceCategoryService.getCategoriesByParent(parentID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.xyzh.common.core.domain.ResultDomain;
|
import org.xyzh.common.core.domain.ResultDomain;
|
||||||
import org.xyzh.common.dto.resource.TbResource;
|
import org.xyzh.common.dto.resource.TbResource;
|
||||||
import org.xyzh.common.dto.resource.TbResourceCategory;
|
import org.xyzh.common.dto.resource.TbTag;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -24,11 +24,11 @@ public class ResourceCenterController {
|
|||||||
// ==================== 专项分栏管理 ====================
|
// ==================== 专项分栏管理 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取专项分栏列表
|
* 获取专项分栏列表(使用标签 tag_type=1)
|
||||||
*/
|
*/
|
||||||
@GetMapping("/categories")
|
@GetMapping("/categories")
|
||||||
public ResultDomain<TbResourceCategory> getSpecialCategories() {
|
public ResultDomain<TbTag> getSpecialCategories() {
|
||||||
// TODO: 实现获取专项分栏(包含党史学习、领导讲话、政策解读、红色经典、专题报告、思政案例6个分栏)
|
// TODO: 实现获取专项分栏,使用 TagService.getTagsByType(1) 获取文章分类标签
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +101,9 @@ public class ResourceCenterController {
|
|||||||
/**
|
/**
|
||||||
* 根据分类ID获取资源
|
* 根据分类ID获取资源
|
||||||
*/
|
*/
|
||||||
@GetMapping("/category/{categoryID}/resources")
|
@GetMapping("/category/{tagID}/resources")
|
||||||
public ResultDomain<TbResource> getResourcesByCategory(
|
public ResultDomain<TbResource> getResourcesByCategory(
|
||||||
@PathVariable String categoryID,
|
@PathVariable String tagID,
|
||||||
@RequestParam(required = false) Integer pageNum,
|
@RequestParam(required = false) Integer pageNum,
|
||||||
@RequestParam(required = false) Integer pageSize) {
|
@RequestParam(required = false) Integer pageSize) {
|
||||||
// TODO: 实现根据分类ID获取资源
|
// TODO: 实现根据分类ID获取资源
|
||||||
@@ -118,7 +118,7 @@ public class ResourceCenterController {
|
|||||||
@GetMapping("/search")
|
@GetMapping("/search")
|
||||||
public ResultDomain<TbResource> searchResources(
|
public ResultDomain<TbResource> searchResources(
|
||||||
@RequestParam String keyword,
|
@RequestParam String keyword,
|
||||||
@RequestParam(required = false) String categoryID,
|
@RequestParam(required = false) String tagID,
|
||||||
@RequestParam(required = false) Integer pageNum,
|
@RequestParam(required = false) Integer pageNum,
|
||||||
@RequestParam(required = false) Integer pageSize) {
|
@RequestParam(required = false) Integer pageSize) {
|
||||||
// TODO: 实现支持模糊关键词检索,快速定位资源
|
// TODO: 实现支持模糊关键词检索,快速定位资源
|
||||||
@@ -238,11 +238,11 @@ public class ResourceCenterController {
|
|||||||
// ==================== 资源分类管理 ====================
|
// ==================== 资源分类管理 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有资源分类
|
* 获取所有资源分类(使用标签 tag_type=1)
|
||||||
*/
|
*/
|
||||||
@GetMapping("/categories/all")
|
@GetMapping("/categories/all")
|
||||||
public ResultDomain<TbResourceCategory> getAllCategories() {
|
public ResultDomain<TbTag> getAllCategories() {
|
||||||
// TODO: 实现获取所有资源分类
|
// TODO: 实现获取所有资源分类,使用 TagService.getTagsByType(1) 获取文章分类标签
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -186,8 +186,8 @@ public class ResourceController {
|
|||||||
@GetMapping("/search")
|
@GetMapping("/search")
|
||||||
public ResultDomain<TbResource> searchResources(
|
public ResultDomain<TbResource> searchResources(
|
||||||
@RequestParam("keyword") String keyword,
|
@RequestParam("keyword") String keyword,
|
||||||
@RequestParam(value = "categoryID", required = false) String categoryID,
|
@RequestParam(value = "tagID", required = false) String tagID,
|
||||||
@RequestParam(value = "status", required = false) Integer status) {
|
@RequestParam(value = "status", required = false) Integer status) {
|
||||||
return resourceService.searchResources(keyword, categoryID, status);
|
return resourceService.searchResources(keyword, tagID, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class TagController {
|
|||||||
* 根据ID获取标签详情
|
* 根据ID获取标签详情
|
||||||
*/
|
*/
|
||||||
@GetMapping("/tag/{tagID}")
|
@GetMapping("/tag/{tagID}")
|
||||||
public ResultDomain<TbTag> getTagById(@PathVariable String tagID) {
|
public ResultDomain<TbTag> getTagById(@PathVariable("tagID") String tagID) {
|
||||||
return tagService.getTagById(tagID);
|
return tagService.getTagById(tagID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ public class TagController {
|
|||||||
* 删除标签
|
* 删除标签
|
||||||
*/
|
*/
|
||||||
@DeleteMapping("/tag/{tagID}")
|
@DeleteMapping("/tag/{tagID}")
|
||||||
public ResultDomain<Boolean> deleteTag(@PathVariable String tagID) {
|
public ResultDomain<Boolean> deleteTag(@PathVariable("tagID") String tagID) {
|
||||||
return tagService.deleteTag(tagID);
|
return tagService.deleteTag(tagID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,17 +70,26 @@ public class TagController {
|
|||||||
* 搜索标签
|
* 搜索标签
|
||||||
*/
|
*/
|
||||||
@GetMapping("/search")
|
@GetMapping("/search")
|
||||||
public ResultDomain<TbTag> searchTags(@RequestParam String keyword) {
|
public ResultDomain<TbTag> searchTags(@RequestParam("keyword") String keyword) {
|
||||||
return tagService.searchTagsByName(keyword);
|
return tagService.searchTagsByName(keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据标签类型获取标签列表
|
||||||
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
*/
|
||||||
|
@GetMapping("/type/{tagType}")
|
||||||
|
public ResultDomain<TbTag> getTagsByType(@PathVariable("tagType") Integer tagType) {
|
||||||
|
return tagService.getTagsByType(tagType);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------资源标签关联相关--------------------------------
|
// ----------------资源标签关联相关--------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取资源的标签列表
|
* 获取资源的标签列表
|
||||||
*/
|
*/
|
||||||
@GetMapping("/resource/{resourceID}")
|
@GetMapping("/resource/{resourceID}")
|
||||||
public ResultDomain<TbTag> getResourceTags(@PathVariable String resourceID) {
|
public ResultDomain<TbTag> getResourceTags(@PathVariable("resourceID") String resourceID) {
|
||||||
return tagService.getResourceTags(resourceID);
|
return tagService.getResourceTags(resourceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +98,8 @@ public class TagController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/resource/{resourceID}/tag/{tagID}")
|
@PostMapping("/resource/{resourceID}/tag/{tagID}")
|
||||||
public ResultDomain<TbResourceTag> addResourceTag(
|
public ResultDomain<TbResourceTag> addResourceTag(
|
||||||
@PathVariable String resourceID,
|
@PathVariable("resourceID") String resourceID,
|
||||||
@PathVariable String tagID) {
|
@PathVariable("tagID") String tagID) {
|
||||||
return tagService.addResourceTag(resourceID, tagID);
|
return tagService.addResourceTag(resourceID, tagID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,8 +118,8 @@ public class TagController {
|
|||||||
*/
|
*/
|
||||||
@DeleteMapping("/resource/{resourceID}/tag/{tagID}")
|
@DeleteMapping("/resource/{resourceID}/tag/{tagID}")
|
||||||
public ResultDomain<Boolean> removeResourceTag(
|
public ResultDomain<Boolean> removeResourceTag(
|
||||||
@PathVariable String resourceID,
|
@PathVariable("resourceID") String resourceID,
|
||||||
@PathVariable String tagID) {
|
@PathVariable("tagID") String tagID) {
|
||||||
return tagService.removeResourceTag(resourceID, tagID);
|
return tagService.removeResourceTag(resourceID, tagID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +127,7 @@ public class TagController {
|
|||||||
* 清空资源的所有标签
|
* 清空资源的所有标签
|
||||||
*/
|
*/
|
||||||
@DeleteMapping("/resource/{resourceID}/tags")
|
@DeleteMapping("/resource/{resourceID}/tags")
|
||||||
public ResultDomain<Boolean> clearResourceTags(@PathVariable String resourceID) {
|
public ResultDomain<Boolean> clearResourceTags(@PathVariable("resourceID") String resourceID) {
|
||||||
return tagService.clearResourceTags(resourceID);
|
return tagService.clearResourceTags(resourceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +135,7 @@ public class TagController {
|
|||||||
* 根据标签获取资源列表
|
* 根据标签获取资源列表
|
||||||
*/
|
*/
|
||||||
@GetMapping("/tag/{tagID}/resources")
|
@GetMapping("/tag/{tagID}/resources")
|
||||||
public ResultDomain<String> getResourcesByTag(@PathVariable String tagID) {
|
public ResultDomain<String> getResourcesByTag(@PathVariable("tagID") String tagID) {
|
||||||
return tagService.getResourcesByTag(tagID);
|
return tagService.getResourcesByTag(tagID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,138 +1 @@
|
|||||||
package org.xyzh.news.mapper;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
import org.xyzh.common.core.page.PageParam;
|
|
||||||
import org.xyzh.common.dto.resource.TbResourceCategory;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description ResourceCategoryMapper.java文件描述 资源分类数据访问层
|
|
||||||
* @filename ResourceCategoryMapper.java
|
|
||||||
* @author yslg
|
|
||||||
* @copyright xyzh
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface ResourceCategoryMapper extends BaseMapper<TbResourceCategory> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 查询资源分类列表
|
|
||||||
* @param filter 过滤条件
|
|
||||||
* @return List<TbResourceCategory> 资源分类列表
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
List<TbResourceCategory> selectResourceCategories(TbResourceCategory filter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 根据分类ID查询分类信息
|
|
||||||
* @param categoryId 分类ID
|
|
||||||
* @return TbResourceCategory 分类信息
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
TbResourceCategory selectByCategoryId(@Param("categoryId") String categoryId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 根据父分类ID查询子分类列表
|
|
||||||
* @param parentId 父分类ID
|
|
||||||
* @return List<TbResourceCategory> 子分类列表
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
List<TbResourceCategory> selectByParentId(@Param("parentId") String parentId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 根据状态查询分类列表
|
|
||||||
* @param status 状态
|
|
||||||
* @return List<TbResourceCategory> 分类列表
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
List<TbResourceCategory> selectByStatus(@Param("status") Integer status);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 查询分类树结构
|
|
||||||
* @return List<TbResourceCategory> 分类树
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
List<TbResourceCategory> selectCategoryTree();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 检查分类名称是否存在
|
|
||||||
* @param name 分类名称
|
|
||||||
* @param excludeId 排除的分类ID(用于更新时排除自身)
|
|
||||||
* @return int 存在的数量
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
int countByName(@Param("name") String name, @Param("excludeId") String excludeId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 插入资源分类
|
|
||||||
* @param resourceCategory 资源分类
|
|
||||||
* @return int 影响行数
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
int insertResourceCategory(TbResourceCategory resourceCategory);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 更新资源分类
|
|
||||||
* @param resourceCategory 资源分类
|
|
||||||
* @return int 影响行数
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
int updateResourceCategory(TbResourceCategory resourceCategory);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 删除资源分类
|
|
||||||
* @param resourceCategory 资源分类
|
|
||||||
* @return int 影响行数
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
int deleteResourceCategory(TbResourceCategory resourceCategory);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 批量插入资源分类
|
|
||||||
* @param resourceCategoryList 资源分类列表
|
|
||||||
* @return int 影响行数
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
int batchInsertResourceCategories(@Param("resourceCategoryList") List<TbResourceCategory> resourceCategoryList);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 批量删除资源分类
|
|
||||||
* @param ids 分类ID列表
|
|
||||||
* @return int 影响行数
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
int batchDeleteResourceCategories(@Param("ids") List<String> ids);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 分页查询资源分类
|
|
||||||
* @param filter 过滤条件
|
|
||||||
* @param pageParam 分页参数
|
|
||||||
* @return List<TbResourceCategory> 资源分类列表
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
List<TbResourceCategory> selectResourceCategoriesPage(@Param("filter") TbResourceCategory filter, @Param("pageParam") PageParam pageParam);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 统计资源分类总数
|
|
||||||
* @param filter 过滤条件
|
|
||||||
* @return long 总数
|
|
||||||
* @author yslg
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
long countResourceCategories(@Param("filter") TbResourceCategory filter);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ public interface ResourceMapper extends BaseMapper<TbResource> {
|
|||||||
TbResource selectByResourceId(@Param("resourceId") String resourceId);
|
TbResource selectByResourceId(@Param("resourceId") String resourceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 根据分类ID查询资源列表
|
* @description 根据标签ID查询资源列表
|
||||||
* @param categoryId 分类ID
|
* @param tagId 标签ID(文章分类标签,tagType=1)
|
||||||
* @return List<TbResource> 资源列表
|
* @return List<TbResource> 资源列表
|
||||||
* @author yslg
|
* @author yslg
|
||||||
* @since 2025-10-15
|
* @since 2025-10-15
|
||||||
*/
|
*/
|
||||||
List<TbResource> selectByCategoryId(@Param("categoryId") String categoryId);
|
List<TbResource> selectByTagId(@Param("tagId") String tagId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 根据状态查询资源列表
|
* @description 根据状态查询资源列表
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ public interface TagMapper extends BaseMapper<TbTag> {
|
|||||||
List<TbTag> selectByStatus(@Param("status") Integer status);
|
List<TbTag> selectByStatus(@Param("status") Integer status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 根据类型查询标签列表
|
* @description 根据标签类型查询标签列表
|
||||||
* @param type 类型
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
* @return List<TbTag> 标签列表
|
* @return List<TbTag> 标签列表
|
||||||
* @author yslg
|
* @author yslg
|
||||||
* @since 2025-10-15
|
* @since 2025-10-27
|
||||||
*/
|
*/
|
||||||
List<TbTag> selectByType(@Param("type") Integer type);
|
List<TbTag> selectByTagType(@Param("tagType") Integer tagType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 查询热门标签列表
|
* @description 查询热门标签列表
|
||||||
@@ -73,14 +73,15 @@ public interface TagMapper extends BaseMapper<TbTag> {
|
|||||||
List<TbTag> selectHotTags(@Param("limit") Integer limit);
|
List<TbTag> selectHotTags(@Param("limit") Integer limit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 检查标签名称是否存在
|
* @description 检查标签名称是否存在(同类型下)
|
||||||
* @param name 标签名称
|
* @param name 标签名称
|
||||||
|
* @param tagType 标签类型
|
||||||
* @param excludeId 排除的标签ID(用于更新时排除自身)
|
* @param excludeId 排除的标签ID(用于更新时排除自身)
|
||||||
* @return int 存在的数量
|
* @return int 存在的数量
|
||||||
* @author yslg
|
* @author yslg
|
||||||
* @since 2025-10-15
|
* @since 2025-10-27
|
||||||
*/
|
*/
|
||||||
int countByName(@Param("name") String name, @Param("excludeId") String excludeId);
|
int countByNameAndType(@Param("name") String name, @Param("tagType") Integer tagType, @Param("excludeId") String excludeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 插入标签
|
* @description 插入标签
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package org.xyzh.news.service;
|
|
||||||
|
|
||||||
import org.xyzh.api.news.category.ResourceCategoryService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 资源分类服务接口
|
|
||||||
* @filename NCResourceCategoryService.java
|
|
||||||
* @author yslg
|
|
||||||
* @copyright xyzh
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
public interface NCResourceCategoryService extends ResourceCategoryService {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,360 +0,0 @@
|
|||||||
package org.xyzh.news.service.impl;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.xyzh.common.core.domain.ResultDomain;
|
|
||||||
import org.xyzh.common.dto.resource.TbResourceCategory;
|
|
||||||
import org.xyzh.common.utils.IDUtils;
|
|
||||||
import org.xyzh.news.mapper.ResourceCategoryMapper;
|
|
||||||
import org.xyzh.api.news.category.ResourceCategoryService;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 资源分类服务实现类
|
|
||||||
* @filename NCResourceCategoryServiceImpl.java
|
|
||||||
* @author yslg
|
|
||||||
* @copyright xyzh
|
|
||||||
* @since 2025-10-15
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class NCResourceCategoryServiceImpl implements ResourceCategoryService {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(NCResourceCategoryServiceImpl.class);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ResourceCategoryMapper resourceCategoryMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public ResultDomain<TbResourceCategory> createCategory(TbResourceCategory category) {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
// 参数验证
|
|
||||||
if (category == null || !StringUtils.hasText(category.getName())) {
|
|
||||||
resultDomain.fail("分类名称不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查分类名称是否已存在
|
|
||||||
int count = resourceCategoryMapper.countByName(category.getName(), null);
|
|
||||||
if (count > 0) {
|
|
||||||
resultDomain.fail("分类名称已存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置默认值
|
|
||||||
if (category.getID() == null) {
|
|
||||||
category.setID(IDUtils.generateID());
|
|
||||||
}
|
|
||||||
if (category.getCategoryID() == null) {
|
|
||||||
category.setCategoryID(IDUtils.generateID());
|
|
||||||
}
|
|
||||||
if (category.getOrderNum() == null) {
|
|
||||||
category.setOrderNum(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
category.setCreateTime(new Date());
|
|
||||||
category.setUpdateTime(new Date());
|
|
||||||
category.setDeleted(false);
|
|
||||||
|
|
||||||
// 插入数据库
|
|
||||||
int result = resourceCategoryMapper.insertResourceCategory(category);
|
|
||||||
if (result > 0) {
|
|
||||||
logger.info("创建分类成功: {}", category.getName());
|
|
||||||
resultDomain.success("创建分类成功", category);
|
|
||||||
return resultDomain;
|
|
||||||
} else {
|
|
||||||
resultDomain.fail("创建分类失败");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("创建分类异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("创建分类失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public ResultDomain<TbResourceCategory> updateCategory(TbResourceCategory category) {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
// 参数验证
|
|
||||||
if (category == null || !StringUtils.hasText(category.getID())) {
|
|
||||||
resultDomain.fail("分类ID不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查分类是否存在
|
|
||||||
TbResourceCategory existingCategory = resourceCategoryMapper.selectById(category.getID());
|
|
||||||
if (existingCategory == null || existingCategory.getDeleted()) {
|
|
||||||
resultDomain.fail("分类不存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查分类名称是否重复(排除自身)
|
|
||||||
if (StringUtils.hasText(category.getName())) {
|
|
||||||
int count = resourceCategoryMapper.countByName(category.getName(), category.getID());
|
|
||||||
if (count > 0) {
|
|
||||||
resultDomain.fail("分类名称已存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新时间
|
|
||||||
category.setUpdateTime(new Date());
|
|
||||||
|
|
||||||
// 更新数据库
|
|
||||||
int result = resourceCategoryMapper.updateResourceCategory(category);
|
|
||||||
if (result > 0) {
|
|
||||||
logger.info("更新分类成功: {}", category.getID());
|
|
||||||
// 重新查询返回完整数据
|
|
||||||
TbResourceCategory updated = resourceCategoryMapper.selectById(category.getID());
|
|
||||||
resultDomain.success("更新分类成功", updated);
|
|
||||||
return resultDomain;
|
|
||||||
} else {
|
|
||||||
resultDomain.fail("更新分类失败");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("更新分类异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("更新分类失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public ResultDomain<Boolean> deleteCategory(String categoryID) {
|
|
||||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
// 参数验证
|
|
||||||
if (!StringUtils.hasText(categoryID)) {
|
|
||||||
resultDomain.fail("分类ID不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查分类是否存在
|
|
||||||
TbResourceCategory category = resourceCategoryMapper.selectByCategoryId(categoryID);
|
|
||||||
if (category == null || category.getDeleted()) {
|
|
||||||
resultDomain.fail("分类不存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有子分类
|
|
||||||
ResultDomain<Boolean> hasChildResult = hasChildCategories(categoryID);
|
|
||||||
if (hasChildResult.isSuccess() && Boolean.TRUE.equals(hasChildResult.getData())) {
|
|
||||||
resultDomain.fail("该分类下存在子分类,无法删除");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有关联资源
|
|
||||||
ResultDomain<Boolean> hasResourceResult = hasResources(categoryID);
|
|
||||||
if (hasResourceResult.isSuccess() && Boolean.TRUE.equals(hasResourceResult.getData())) {
|
|
||||||
resultDomain.fail("该分类下存在资源,无法删除");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 物理删除
|
|
||||||
int result = resourceCategoryMapper.deleteResourceCategory(category);
|
|
||||||
if (result > 0) {
|
|
||||||
logger.info("删除分类成功: {}", categoryID);
|
|
||||||
resultDomain.success("删除分类成功", true);
|
|
||||||
return resultDomain;
|
|
||||||
} else {
|
|
||||||
resultDomain.fail("删除分类失败");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("删除分类异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("删除分类失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultDomain<TbResourceCategory> getCategoryById(String categoryID) {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
if (!StringUtils.hasText(categoryID)) {
|
|
||||||
resultDomain.fail("分类ID不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
TbResourceCategory category = resourceCategoryMapper.selectByCategoryId(categoryID);
|
|
||||||
if (category == null || category.getDeleted()) {
|
|
||||||
resultDomain.fail("分类不存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
resultDomain.success("查询成功", category);
|
|
||||||
return resultDomain;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("查询分类异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("查询分类失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultDomain<TbResourceCategory> getAllCategories() {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
List<TbResourceCategory> categories = resourceCategoryMapper.selectResourceCategories(new TbResourceCategory());
|
|
||||||
resultDomain.success("查询成功", categories);
|
|
||||||
return resultDomain;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("查询分类列表异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("查询分类列表失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultDomain<TbResourceCategory> getCategoriesByParent(String parentID) {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
if (!StringUtils.hasText(parentID)) {
|
|
||||||
resultDomain.fail("父分类ID不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TbResourceCategory> categories = resourceCategoryMapper.selectByParentId(parentID);
|
|
||||||
resultDomain.success("查询成功", categories);
|
|
||||||
return resultDomain;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("查询子分类列表异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("查询子分类列表失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultDomain<TbResourceCategory> getCategoryTree() {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
// 查询所有分类
|
|
||||||
List<TbResourceCategory> allCategories = resourceCategoryMapper.selectCategoryTree();
|
|
||||||
|
|
||||||
// 构建树形结构
|
|
||||||
List<TbResourceCategory> tree = buildCategoryTree(allCategories, null);
|
|
||||||
|
|
||||||
resultDomain.success("查询成功", tree);
|
|
||||||
return resultDomain;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("查询分类树异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("查询分类树失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultDomain<Boolean> hasChildCategories(String categoryID) {
|
|
||||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
if (!StringUtils.hasText(categoryID)) {
|
|
||||||
resultDomain.fail("分类ID不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TbResourceCategory> children = resourceCategoryMapper.selectByParentId(categoryID);
|
|
||||||
resultDomain.success("查询成功", !children.isEmpty());
|
|
||||||
return resultDomain;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("检查子分类异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("检查子分类失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultDomain<Boolean> hasResources(String categoryID) {
|
|
||||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
if (!StringUtils.hasText(categoryID)) {
|
|
||||||
resultDomain.fail("分类ID不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 需要查询资源表判断是否有关联资源
|
|
||||||
// 这里暂时返回false,需要在ResourceMapper中添加相应方法
|
|
||||||
resultDomain.success("查询成功", false);
|
|
||||||
return resultDomain;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("检查分类资源异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("检查分类资源失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public ResultDomain<TbResourceCategory> updateCategoryOrder(String categoryID, Integer orderNum) {
|
|
||||||
ResultDomain<TbResourceCategory> resultDomain = new ResultDomain<>();
|
|
||||||
try {
|
|
||||||
if (!StringUtils.hasText(categoryID) || orderNum == null) {
|
|
||||||
resultDomain.fail("参数不能为空");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
TbResourceCategory category = resourceCategoryMapper.selectByCategoryId(categoryID);
|
|
||||||
if (category == null || category.getDeleted()) {
|
|
||||||
resultDomain.fail("分类不存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
TbResourceCategory updateCategory = new TbResourceCategory();
|
|
||||||
updateCategory.setID(category.getID());
|
|
||||||
updateCategory.setOrderNum(orderNum);
|
|
||||||
updateCategory.setUpdateTime(new Date());
|
|
||||||
|
|
||||||
int result = resourceCategoryMapper.updateResourceCategory(updateCategory);
|
|
||||||
if (result > 0) {
|
|
||||||
logger.info("更新分类排序成功: {}", categoryID);
|
|
||||||
TbResourceCategory updated = resourceCategoryMapper.selectById(category.getID());
|
|
||||||
resultDomain.success("更新排序成功", updated);
|
|
||||||
return resultDomain;
|
|
||||||
} else {
|
|
||||||
resultDomain.fail("更新排序失败");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("更新分类排序异常: {}", e.getMessage(), e);
|
|
||||||
resultDomain.fail("更新排序失败: " + e.getMessage());
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建分类树形结构
|
|
||||||
* @param allCategories 所有分类列表
|
|
||||||
* @param parentID 父分类ID
|
|
||||||
* @return 树形结构列表
|
|
||||||
*/
|
|
||||||
private List<TbResourceCategory> buildCategoryTree(List<TbResourceCategory> allCategories, String parentID) {
|
|
||||||
List<TbResourceCategory> result = new ArrayList<>();
|
|
||||||
|
|
||||||
for (TbResourceCategory category : allCategories) {
|
|
||||||
// 找出当前父级下的子分类
|
|
||||||
if ((parentID == null && category.getParentID() == null) ||
|
|
||||||
(parentID != null && parentID.equals(category.getParentID()))) {
|
|
||||||
|
|
||||||
// 递归查找子分类(如果TbResourceCategory有children字段,可以在这里设置)
|
|
||||||
// List<TbResourceCategory> children = buildCategoryTree(allCategories, category.getCategoryID());
|
|
||||||
// category.setChildren(children);
|
|
||||||
|
|
||||||
result.add(category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -721,7 +721,7 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResultDomain<TbResource> searchResources(String keyword, String categoryID, Integer status) {
|
public ResultDomain<TbResource> searchResources(String keyword, String tagID, Integer status) {
|
||||||
ResultDomain<TbResource> resultDomain = new ResultDomain<>();
|
ResultDomain<TbResource> resultDomain = new ResultDomain<>();
|
||||||
try {
|
try {
|
||||||
// 参数验证
|
// 参数验证
|
||||||
@@ -734,8 +734,8 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
List<TbResource> list = resourceMapper.searchByKeyword(keyword);
|
List<TbResource> list = resourceMapper.searchByKeyword(keyword);
|
||||||
|
|
||||||
// 如果指定了分类ID,进行过滤
|
// 如果指定了分类ID,进行过滤
|
||||||
if (StringUtils.hasText(categoryID) && list != null) {
|
if (StringUtils.hasText(tagID) && list != null) {
|
||||||
list.removeIf(resource -> !categoryID.equals(resource.getCategoryID()));
|
list.removeIf(resource -> !tagID.equals(resource.getTagID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果指定了状态,进行过滤
|
// 如果指定了状态,进行过滤
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ public class NCTagServiceImpl implements TagService {
|
|||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查标签名称是否已存在
|
// 检查标签名称是否已存在(同类型下)
|
||||||
int count = tagMapper.countByName(tag.getName(), null);
|
int count = tagMapper.countByNameAndType(tag.getName(), tag.getTagType(), null);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
resultDomain.fail("标签名称已存在");
|
resultDomain.fail("该类型下标签名称已存在");
|
||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,11 +103,12 @@ public class NCTagServiceImpl implements TagService {
|
|||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查标签名称是否重复(排除自身)
|
// 检查标签名称是否重复(排除自身,同类型下)
|
||||||
if (StringUtils.hasText(tag.getName())) {
|
if (StringUtils.hasText(tag.getName())) {
|
||||||
int count = tagMapper.countByName(tag.getName(), tag.getID());
|
Integer tagType = tag.getTagType() != null ? tag.getTagType() : existingTag.getTagType();
|
||||||
|
int count = tagMapper.countByNameAndType(tag.getName(), tagType, tag.getID());
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
resultDomain.fail("标签名称已存在");
|
resultDomain.fail("该类型下标签名称已存在");
|
||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,4 +461,29 @@ public class NCTagServiceImpl implements TagService {
|
|||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultDomain<TbTag> getTagsByType(Integer tagType) {
|
||||||
|
ResultDomain<TbTag> resultDomain = new ResultDomain<>();
|
||||||
|
try {
|
||||||
|
if (tagType == null) {
|
||||||
|
resultDomain.fail("标签类型不能为空");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证标签类型是否有效(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
if (tagType < 1 || tagType > 3) {
|
||||||
|
resultDomain.fail("无效的标签类型");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TbTag> tags = tagMapper.selectByTagType(tagType);
|
||||||
|
resultDomain.success("查询成功", tags);
|
||||||
|
return resultDomain;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("根据类型查询标签异常: {}", e.getMessage(), e);
|
||||||
|
resultDomain.fail("根据类型查询标签失败: " + e.getMessage());
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<result column="source_url" property="sourceUrl" jdbcType="VARCHAR"/>
|
<result column="source_url" property="sourceUrl" jdbcType="VARCHAR"/>
|
||||||
<result column="source_type" property="sourceType" jdbcType="VARCHAR"/>
|
<result column="source_type" property="sourceType" jdbcType="VARCHAR"/>
|
||||||
<result column="frequency" property="frequency" jdbcType="VARCHAR"/>
|
<result column="frequency" property="frequency" jdbcType="VARCHAR"/>
|
||||||
<result column="category_id" property="categoryID" jdbcType="VARCHAR"/>
|
<result column="tag_id" property="tagID" jdbcType="VARCHAR"/>
|
||||||
<result column="status" property="status" jdbcType="INTEGER"/>
|
<result column="status" property="status" jdbcType="INTEGER"/>
|
||||||
<result column="last_collect_time" property="lastCollectTime" jdbcType="TIMESTAMP"/>
|
<result column="last_collect_time" property="lastCollectTime" jdbcType="TIMESTAMP"/>
|
||||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<!-- 基础字段 -->
|
<!-- 基础字段 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, name, source_url, source_type, frequency, category_id, status,
|
id, name, source_url, source_type, frequency, tag_id, status,
|
||||||
last_collect_time, creator, updater, create_time, update_time,
|
last_collect_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
</sql>
|
</sql>
|
||||||
@@ -40,8 +40,8 @@
|
|||||||
<if test="frequency != null and frequency != ''">
|
<if test="frequency != null and frequency != ''">
|
||||||
AND frequency = #{frequency}
|
AND frequency = #{frequency}
|
||||||
</if>
|
</if>
|
||||||
<if test="categoryID != null and categoryID != ''">
|
<if test="tagID != null and tagID != ''">
|
||||||
AND category_id = #{categoryID}
|
AND tag_id = #{tagID}
|
||||||
</if>
|
</if>
|
||||||
<if test="status != null">
|
<if test="status != null">
|
||||||
AND status = #{status}
|
AND status = #{status}
|
||||||
@@ -114,11 +114,11 @@
|
|||||||
<!-- 插入数据采集配置 -->
|
<!-- 插入数据采集配置 -->
|
||||||
<insert id="insertDataCollectionConfig" parameterType="org.xyzh.common.dto.resource.TbDataCollectionConfig">
|
<insert id="insertDataCollectionConfig" parameterType="org.xyzh.common.dto.resource.TbDataCollectionConfig">
|
||||||
INSERT INTO tb_data_collection_config (
|
INSERT INTO tb_data_collection_config (
|
||||||
id, name, source_url, source_type, frequency, category_id, status,
|
id, name, source_url, source_type, frequency, tag_id, status,
|
||||||
last_collect_time, creator, updater, create_time, update_time,
|
last_collect_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
#{id}, #{name}, #{sourceUrl}, #{sourceType}, #{frequency}, #{categoryID}, #{status},
|
#{id}, #{name}, #{sourceUrl}, #{sourceType}, #{frequency}, #{tagID}, #{status},
|
||||||
#{lastCollectTime}, #{creator}, #{updater}, #{createTime}, #{updateTime},
|
#{lastCollectTime}, #{creator}, #{updater}, #{createTime}, #{updateTime},
|
||||||
#{deleteTime}, #{deleted}
|
#{deleteTime}, #{deleted}
|
||||||
)
|
)
|
||||||
@@ -140,8 +140,8 @@
|
|||||||
<if test="frequency != null and frequency != ''">
|
<if test="frequency != null and frequency != ''">
|
||||||
frequency = #{frequency},
|
frequency = #{frequency},
|
||||||
</if>
|
</if>
|
||||||
<if test="categoryID != null and categoryID != ''">
|
<if test="tagID != null and tagID != ''">
|
||||||
category_id = #{categoryID},
|
tag_id = #{tagID},
|
||||||
</if>
|
</if>
|
||||||
<if test="status != null">
|
<if test="status != null">
|
||||||
status = #{status},
|
status = #{status},
|
||||||
@@ -174,14 +174,14 @@
|
|||||||
<!-- 批量插入数据采集配置 -->
|
<!-- 批量插入数据采集配置 -->
|
||||||
<insert id="batchInsertDataCollectionConfigs" parameterType="java.util.List">
|
<insert id="batchInsertDataCollectionConfigs" parameterType="java.util.List">
|
||||||
INSERT INTO tb_data_collection_config (
|
INSERT INTO tb_data_collection_config (
|
||||||
id, name, source_url, source_type, frequency, category_id, status,
|
id, name, source_url, source_type, frequency, tag_id, status,
|
||||||
last_collect_time, creator, updater, create_time, update_time,
|
last_collect_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
) VALUES
|
) VALUES
|
||||||
<foreach collection="dataCollectionConfigList" item="item" separator=",">
|
<foreach collection="dataCollectionConfigList" item="item" separator=",">
|
||||||
(
|
(
|
||||||
#{item.id}, #{item.name}, #{item.sourceUrl}, #{item.sourceType}, #{item.frequency},
|
#{item.id}, #{item.name}, #{item.sourceUrl}, #{item.sourceType}, #{item.frequency},
|
||||||
#{item.categoryID}, #{item.status}, #{item.lastCollectTime}, #{item.creator},
|
#{item.tagID}, #{item.status}, #{item.lastCollectTime}, #{item.creator},
|
||||||
#{item.updater}, #{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
|
#{item.updater}, #{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
|
||||||
)
|
)
|
||||||
</foreach>
|
</foreach>
|
||||||
|
|||||||
@@ -1,194 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
<mapper namespace="org.xyzh.news.mapper.ResourceCategoryMapper">
|
|
||||||
|
|
||||||
<!-- 基础结果映射 -->
|
|
||||||
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.resource.TbResourceCategory">
|
|
||||||
<id column="id" property="id" jdbcType="VARCHAR"/>
|
|
||||||
<result column="category_id" property="categoryID" jdbcType="VARCHAR"/>
|
|
||||||
<result column="name" property="name" jdbcType="VARCHAR"/>
|
|
||||||
<result column="parent_id" property="parentID" jdbcType="VARCHAR"/>
|
|
||||||
<result column="description" property="description" jdbcType="VARCHAR"/>
|
|
||||||
<result column="icon" property="icon" jdbcType="VARCHAR"/>
|
|
||||||
<result column="order_num" property="orderNum" jdbcType="INTEGER"/>
|
|
||||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
|
||||||
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
|
||||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
|
||||||
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
|
|
||||||
<result column="delete_time" property="deleteTime" jdbcType="TIMESTAMP"/>
|
|
||||||
<result column="deleted" property="deleted" jdbcType="BOOLEAN"/>
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<!-- 基础字段 -->
|
|
||||||
<sql id="Base_Column_List">
|
|
||||||
id, category_id, name, parent_id, description, icon, order_num,
|
|
||||||
creator, updater, create_time, update_time, delete_time, deleted
|
|
||||||
</sql>
|
|
||||||
|
|
||||||
<!-- 通用条件 -->
|
|
||||||
<sql id="Where_Clause">
|
|
||||||
<where>
|
|
||||||
deleted = 0
|
|
||||||
<if test="categoryID != null and categoryID != ''">
|
|
||||||
AND category_id = #{categoryID}
|
|
||||||
</if>
|
|
||||||
<if test="name != null and name != ''">
|
|
||||||
AND name LIKE CONCAT('%', #{name}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="parentID != null and parentID != ''">
|
|
||||||
AND parent_id = #{parentID}
|
|
||||||
</if>
|
|
||||||
</where>
|
|
||||||
</sql>
|
|
||||||
|
|
||||||
<!-- selectResourceCategories -->
|
|
||||||
<select id="selectResourceCategories" resultMap="BaseResultMap">
|
|
||||||
SELECT
|
|
||||||
<include refid="Base_Column_List"/>
|
|
||||||
FROM tb_resource_category
|
|
||||||
<include refid="Where_Clause"/>
|
|
||||||
ORDER BY order_num ASC, create_time ASC
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 根据分类ID查询分类信息 -->
|
|
||||||
<select id="selectByCategoryId" resultMap="BaseResultMap">
|
|
||||||
SELECT
|
|
||||||
<include refid="Base_Column_List" />
|
|
||||||
FROM tb_resource_category
|
|
||||||
WHERE category_id = #{categoryId} AND deleted = 0
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 根据父分类ID查询子分类列表 -->
|
|
||||||
<select id="selectByParentId" resultMap="BaseResultMap">
|
|
||||||
SELECT
|
|
||||||
<include refid="Base_Column_List" />
|
|
||||||
FROM tb_resource_category
|
|
||||||
WHERE parent_id = #{parentId} AND deleted = 0
|
|
||||||
ORDER BY order_num ASC, create_time ASC
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 根据状态查询分类列表 -->
|
|
||||||
<select id="selectByStatus" resultMap="BaseResultMap">
|
|
||||||
SELECT
|
|
||||||
<include refid="Base_Column_List" />
|
|
||||||
FROM tb_resource_category
|
|
||||||
WHERE deleted = 0
|
|
||||||
ORDER BY order_num ASC, create_time ASC
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 查询分类树结构 -->
|
|
||||||
<select id="selectCategoryTree" resultMap="BaseResultMap">
|
|
||||||
SELECT
|
|
||||||
<include refid="Base_Column_List" />
|
|
||||||
FROM tb_resource_category
|
|
||||||
WHERE deleted = 0
|
|
||||||
ORDER BY order_num ASC, create_time ASC
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 检查分类名称是否存在 -->
|
|
||||||
<select id="countByName" resultType="int">
|
|
||||||
SELECT COUNT(1)
|
|
||||||
FROM tb_resource_category
|
|
||||||
WHERE name = #{name} AND deleted = 0
|
|
||||||
<if test="excludeId != null and excludeId != ''">
|
|
||||||
AND id != #{excludeId}
|
|
||||||
</if>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 插入资源分类 -->
|
|
||||||
<insert id="insertResourceCategory" parameterType="org.xyzh.common.dto.resource.TbResourceCategory">
|
|
||||||
INSERT INTO tb_resource_category (
|
|
||||||
id, category_id, name, parent_id, description, icon, order_num,
|
|
||||||
creator, updater, create_time, update_time, delete_time, deleted
|
|
||||||
) VALUES (
|
|
||||||
#{id}, #{categoryID}, #{name}, #{parentID}, #{description}, #{icon}, #{orderNum},
|
|
||||||
#{creator}, #{updater}, #{createTime}, #{updateTime}, #{deleteTime}, #{deleted}
|
|
||||||
)
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<!-- 更新资源分类 -->
|
|
||||||
<update id="updateResourceCategory" parameterType="org.xyzh.common.dto.resource.TbResourceCategory">
|
|
||||||
UPDATE tb_resource_category
|
|
||||||
<set>
|
|
||||||
<if test="categoryID != null and categoryID != ''">
|
|
||||||
category_id = #{categoryID},
|
|
||||||
</if>
|
|
||||||
<if test="name != null and name != ''">
|
|
||||||
name = #{name},
|
|
||||||
</if>
|
|
||||||
<if test="parentID != null and parentID != ''">
|
|
||||||
parent_id = #{parentID},
|
|
||||||
</if>
|
|
||||||
<if test="description != null and description != ''">
|
|
||||||
description = #{description},
|
|
||||||
</if>
|
|
||||||
<if test="icon != null and icon != ''">
|
|
||||||
icon = #{icon},
|
|
||||||
</if>
|
|
||||||
<if test="orderNum != null">
|
|
||||||
order_num = #{orderNum},
|
|
||||||
</if>
|
|
||||||
<if test="updater != null and updater != ''">
|
|
||||||
updater = #{updater},
|
|
||||||
</if>
|
|
||||||
<if test="updateTime != null">
|
|
||||||
update_time = #{updateTime},
|
|
||||||
</if>
|
|
||||||
<if test="deleteTime != null">
|
|
||||||
delete_time = #{deleteTime},
|
|
||||||
</if>
|
|
||||||
<if test="deleted != null">
|
|
||||||
deleted = #{deleted},
|
|
||||||
</if>
|
|
||||||
</set>
|
|
||||||
WHERE id = #{id}
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<!-- 删除资源分类 -->
|
|
||||||
<delete id="deleteResourceCategory" parameterType="org.xyzh.common.dto.resource.TbResourceCategory">
|
|
||||||
DELETE FROM tb_resource_category
|
|
||||||
WHERE id = #{id}
|
|
||||||
</delete>
|
|
||||||
|
|
||||||
<!-- 批量插入资源分类 -->
|
|
||||||
<insert id="batchInsertResourceCategories" parameterType="java.util.List">
|
|
||||||
INSERT INTO tb_resource_category (
|
|
||||||
id, category_id, name, parent_id, description, icon, order_num,
|
|
||||||
creator, updater, create_time, update_time, delete_time, deleted
|
|
||||||
) VALUES
|
|
||||||
<foreach collection="resourceCategoryList" item="item" separator=",">
|
|
||||||
(
|
|
||||||
#{item.id}, #{item.categoryID}, #{item.name}, #{item.parentID}, #{item.description},
|
|
||||||
#{item.icon}, #{item.orderNum}, #{item.creator}, #{item.updater},
|
|
||||||
#{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
|
|
||||||
)
|
|
||||||
</foreach>
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<!-- 批量删除资源分类 -->
|
|
||||||
<delete id="batchDeleteResourceCategories">
|
|
||||||
DELETE FROM tb_resource_category
|
|
||||||
WHERE id IN
|
|
||||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
|
||||||
#{id}
|
|
||||||
</foreach>
|
|
||||||
</delete>
|
|
||||||
|
|
||||||
<!-- 分页查询资源分类 -->
|
|
||||||
<select id="selectResourceCategoriesPage" resultMap="BaseResultMap">
|
|
||||||
SELECT
|
|
||||||
<include refid="Base_Column_List" />
|
|
||||||
FROM tb_resource_category
|
|
||||||
<include refid="Where_Clause" />
|
|
||||||
ORDER BY order_num ASC, create_time ASC
|
|
||||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 统计资源分类总数 -->
|
|
||||||
<select id="countResourceCategories" resultType="long">
|
|
||||||
SELECT COUNT(1)
|
|
||||||
FROM tb_resource_category
|
|
||||||
<include refid="Where_Clause" />
|
|
||||||
</select>
|
|
||||||
|
|
||||||
</mapper>
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
|
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
|
||||||
<result column="summary" property="summary" jdbcType="VARCHAR"/>
|
<result column="summary" property="summary" jdbcType="VARCHAR"/>
|
||||||
<result column="cover_image" property="coverImage" jdbcType="VARCHAR"/>
|
<result column="cover_image" property="coverImage" jdbcType="VARCHAR"/>
|
||||||
<result column="category_id" property="categoryID" jdbcType="VARCHAR"/>
|
<result column="tag_id" property="tagID" jdbcType="VARCHAR"/>
|
||||||
<result column="author" property="author" jdbcType="VARCHAR"/>
|
<result column="author" property="author" jdbcType="VARCHAR"/>
|
||||||
<result column="source" property="source" jdbcType="VARCHAR"/>
|
<result column="source" property="source" jdbcType="VARCHAR"/>
|
||||||
<result column="source_url" property="sourceUrl" jdbcType="VARCHAR"/>
|
<result column="source_url" property="sourceUrl" jdbcType="VARCHAR"/>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<!-- 基础字段 -->
|
<!-- 基础字段 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, resource_id, title, content, summary, cover_image, category_id, author, source,
|
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
||||||
source_url, view_count, like_count, collect_count, status, is_recommend,
|
source_url, view_count, like_count, collect_count, status, is_recommend,
|
||||||
is_banner, publish_time, creator, updater, create_time, update_time,
|
is_banner, publish_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
<if test="title != null and title != ''">
|
<if test="title != null and title != ''">
|
||||||
AND title LIKE CONCAT('%', #{title}, '%')
|
AND title LIKE CONCAT('%', #{title}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="categoryID != null and categoryID != ''">
|
<if test="tagID != null and tagID != ''">
|
||||||
AND category_id = #{categoryID}
|
AND tag_id = #{tagID}
|
||||||
</if>
|
</if>
|
||||||
<if test="author != null and author != ''">
|
<if test="author != null and author != ''">
|
||||||
AND author LIKE CONCAT('%', #{author}, '%')
|
AND author LIKE CONCAT('%', #{author}, '%')
|
||||||
@@ -79,12 +79,12 @@
|
|||||||
WHERE resource_id = #{resourceId} AND deleted = 0
|
WHERE resource_id = #{resourceId} AND deleted = 0
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 根据分类ID查询资源列表 -->
|
<!-- 根据标签ID查询资源列表 -->
|
||||||
<select id="selectByCategoryId" resultMap="BaseResultMap">
|
<select id="selectByTagId" resultMap="BaseResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
<include refid="Base_Column_List" />
|
<include refid="Base_Column_List" />
|
||||||
FROM tb_resource
|
FROM tb_resource
|
||||||
WHERE category_id = #{categoryId} AND deleted = 0
|
WHERE tag_id = #{tagId} AND deleted = 0
|
||||||
ORDER BY publish_time DESC, create_time DESC
|
ORDER BY publish_time DESC, create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -97,12 +97,12 @@
|
|||||||
ORDER BY publish_time DESC, create_time DESC
|
ORDER BY publish_time DESC, create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 根据类型查询资源列表 -->
|
<!-- 根据标签类型查询资源列表 -->
|
||||||
<select id="selectByType" resultMap="BaseResultMap">
|
<select id="selectByType" resultMap="BaseResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
<include refid="Base_Column_List" />
|
<include refid="Base_Column_List" />
|
||||||
FROM tb_resource
|
FROM tb_resource
|
||||||
WHERE category_id = #{type} AND deleted = 0
|
WHERE tag_id = #{type} AND deleted = 0
|
||||||
ORDER BY publish_time DESC, create_time DESC
|
ORDER BY publish_time DESC, create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -155,12 +155,12 @@
|
|||||||
<!-- 插入资源 -->
|
<!-- 插入资源 -->
|
||||||
<insert id="insertResource" parameterType="org.xyzh.common.dto.resource.TbResource">
|
<insert id="insertResource" parameterType="org.xyzh.common.dto.resource.TbResource">
|
||||||
INSERT INTO tb_resource (
|
INSERT INTO tb_resource (
|
||||||
id, resource_id, title, content, summary, cover_image, category_id, author, source,
|
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
||||||
source_url, view_count, like_count, collect_count, status, is_recommend,
|
source_url, view_count, like_count, collect_count, status, is_recommend,
|
||||||
is_banner, publish_time, creator, updater, create_time, update_time,
|
is_banner, publish_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
#{id}, #{resourceID}, #{title}, #{content}, #{summary}, #{coverImage}, #{categoryID}, #{author}, #{source},
|
#{id}, #{resourceID}, #{title}, #{content}, #{summary}, #{coverImage}, #{tagID}, #{author}, #{source},
|
||||||
#{sourceUrl}, #{viewCount}, #{likeCount}, #{collectCount}, #{status}, #{isRecommend},
|
#{sourceUrl}, #{viewCount}, #{likeCount}, #{collectCount}, #{status}, #{isRecommend},
|
||||||
#{isBanner}, #{publishTime}, #{creator}, #{updater}, #{createTime}, #{updateTime},
|
#{isBanner}, #{publishTime}, #{creator}, #{updater}, #{createTime}, #{updateTime},
|
||||||
#{deleteTime}, #{deleted}
|
#{deleteTime}, #{deleted}
|
||||||
@@ -183,8 +183,8 @@
|
|||||||
<if test="coverImage != null and coverImage != ''">
|
<if test="coverImage != null and coverImage != ''">
|
||||||
cover_image = #{coverImage},
|
cover_image = #{coverImage},
|
||||||
</if>
|
</if>
|
||||||
<if test="categoryID != null and categoryID != ''">
|
<if test="tagID != null and tagID != ''">
|
||||||
category_id = #{categoryID},
|
tag_id = #{tagID},
|
||||||
</if>
|
</if>
|
||||||
<if test="author != null and author != ''">
|
<if test="author != null and author != ''">
|
||||||
author = #{author},
|
author = #{author},
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
<!-- 批量插入资源 -->
|
<!-- 批量插入资源 -->
|
||||||
<insert id="batchInsertResources" parameterType="java.util.List">
|
<insert id="batchInsertResources" parameterType="java.util.List">
|
||||||
INSERT INTO tb_resource (
|
INSERT INTO tb_resource (
|
||||||
id, resource_id, title, content, summary, cover_image, category_id, author, source,
|
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
||||||
source_url, view_count, like_count, collect_count, status, is_recommend,
|
source_url, view_count, like_count, collect_count, status, is_recommend,
|
||||||
is_banner, publish_time, creator, updater, create_time, update_time,
|
is_banner, publish_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
@@ -249,7 +249,7 @@
|
|||||||
<foreach collection="resourceList" item="item" separator=",">
|
<foreach collection="resourceList" item="item" separator=",">
|
||||||
(
|
(
|
||||||
#{item.id}, #{item.resourceID}, #{item.title}, #{item.content}, #{item.summary}, #{item.coverImage},
|
#{item.id}, #{item.resourceID}, #{item.title}, #{item.content}, #{item.summary}, #{item.coverImage},
|
||||||
#{item.categoryID}, #{item.author}, #{item.source}, #{item.sourceUrl},
|
#{item.tagID}, #{item.author}, #{item.source}, #{item.sourceUrl},
|
||||||
#{item.viewCount}, #{item.likeCount}, #{item.collectCount}, #{item.status},
|
#{item.viewCount}, #{item.likeCount}, #{item.collectCount}, #{item.status},
|
||||||
#{item.isRecommend}, #{item.isBanner}, #{item.publishTime}, #{item.creator},
|
#{item.isRecommend}, #{item.isBanner}, #{item.publishTime}, #{item.creator},
|
||||||
#{item.updater}, #{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
|
#{item.updater}, #{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
|
||||||
@@ -276,8 +276,8 @@
|
|||||||
<if test="filter.title != null and filter.title != ''">
|
<if test="filter.title != null and filter.title != ''">
|
||||||
AND title LIKE CONCAT('%', #{filter.title}, '%')
|
AND title LIKE CONCAT('%', #{filter.title}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="filter.categoryID != null and filter.categoryID != ''">
|
<if test="filter.tagID != null and filter.tagID != ''">
|
||||||
AND category_id = #{filter.categoryID}
|
AND tag_id = #{filter.tagID}
|
||||||
</if>
|
</if>
|
||||||
<if test="filter.author != null and filter.author != ''">
|
<if test="filter.author != null and filter.author != ''">
|
||||||
AND author LIKE CONCAT('%', #{filter.author}, '%')
|
AND author LIKE CONCAT('%', #{filter.author}, '%')
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<result column="name" property="name" jdbcType="VARCHAR"/>
|
<result column="name" property="name" jdbcType="VARCHAR"/>
|
||||||
<result column="color" property="color" jdbcType="VARCHAR"/>
|
<result column="color" property="color" jdbcType="VARCHAR"/>
|
||||||
<result column="description" property="description" jdbcType="VARCHAR"/>
|
<result column="description" property="description" jdbcType="VARCHAR"/>
|
||||||
|
<result column="tag_type" property="tagType" jdbcType="INTEGER"/>
|
||||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
||||||
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
||||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
|
|
||||||
<!-- 基础字段 -->
|
<!-- 基础字段 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, tag_id, name, color, description, creator, updater, create_time,
|
id, tag_id, name, color, description, tag_type, creator, updater, create_time,
|
||||||
update_time, delete_time, deleted
|
update_time, delete_time, deleted
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -36,6 +37,9 @@
|
|||||||
<if test="color != null and color != ''">
|
<if test="color != null and color != ''">
|
||||||
AND color = #{color}
|
AND color = #{color}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="tagType != null">
|
||||||
|
AND tag_type = #{tagType}
|
||||||
|
</if>
|
||||||
</where>
|
</where>
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -73,12 +77,15 @@
|
|||||||
ORDER BY create_time DESC
|
ORDER BY create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 根据类型查询标签列表 -->
|
<!-- 根据标签类型查询标签列表 -->
|
||||||
<select id="selectByType" resultMap="BaseResultMap">
|
<select id="selectByTagType" resultMap="BaseResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
<include refid="Base_Column_List" />
|
<include refid="Base_Column_List" />
|
||||||
FROM tb_tag
|
FROM tb_tag
|
||||||
WHERE deleted = 0
|
WHERE deleted = 0
|
||||||
|
<if test="tagType != null">
|
||||||
|
AND tag_type = #{tagType}
|
||||||
|
</if>
|
||||||
ORDER BY create_time DESC
|
ORDER BY create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -94,11 +101,14 @@
|
|||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 检查标签名称是否存在 -->
|
<!-- 检查标签名称是否存在(同类型下) -->
|
||||||
<select id="countByName" resultType="int">
|
<select id="countByNameAndType" resultType="int">
|
||||||
SELECT COUNT(1)
|
SELECT COUNT(1)
|
||||||
FROM tb_tag
|
FROM tb_tag
|
||||||
WHERE name = #{name} AND deleted = 0
|
WHERE name = #{name} AND deleted = 0
|
||||||
|
<if test="tagType != null">
|
||||||
|
AND tag_type = #{tagType}
|
||||||
|
</if>
|
||||||
<if test="excludeId != null and excludeId != ''">
|
<if test="excludeId != null and excludeId != ''">
|
||||||
AND id != #{excludeId}
|
AND id != #{excludeId}
|
||||||
</if>
|
</if>
|
||||||
@@ -107,10 +117,10 @@
|
|||||||
<!-- 插入标签 -->
|
<!-- 插入标签 -->
|
||||||
<insert id="insertTag" parameterType="org.xyzh.common.dto.resource.TbTag">
|
<insert id="insertTag" parameterType="org.xyzh.common.dto.resource.TbTag">
|
||||||
INSERT INTO tb_tag (
|
INSERT INTO tb_tag (
|
||||||
id, tag_id, name, color, description, creator, updater, create_time,
|
id, tag_id, name, color, description, tag_type, creator, updater, create_time,
|
||||||
update_time, delete_time, deleted
|
update_time, delete_time, deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
#{id}, #{tagID}, #{name}, #{color}, #{description}, #{creator}, #{updater}, #{createTime},
|
#{id}, #{tagID}, #{name}, #{color}, #{description}, #{tagType}, #{creator}, #{updater}, #{createTime},
|
||||||
#{updateTime}, #{deleteTime}, #{deleted}
|
#{updateTime}, #{deleteTime}, #{deleted}
|
||||||
)
|
)
|
||||||
</insert>
|
</insert>
|
||||||
@@ -131,6 +141,9 @@
|
|||||||
<if test="description != null and description != ''">
|
<if test="description != null and description != ''">
|
||||||
description = #{description},
|
description = #{description},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="tagType != null">
|
||||||
|
tag_type = #{tagType},
|
||||||
|
</if>
|
||||||
<if test="updater != null and updater != ''">
|
<if test="updater != null and updater != ''">
|
||||||
updater = #{updater},
|
updater = #{updater},
|
||||||
</if>
|
</if>
|
||||||
@@ -156,13 +169,13 @@
|
|||||||
<!-- 批量插入标签 -->
|
<!-- 批量插入标签 -->
|
||||||
<insert id="batchInsertTags" parameterType="java.util.List">
|
<insert id="batchInsertTags" parameterType="java.util.List">
|
||||||
INSERT INTO tb_tag (
|
INSERT INTO tb_tag (
|
||||||
id, tag_id, name, color, description, creator, updater, create_time,
|
id, tag_id, name, color, description, tag_type, creator, updater, create_time,
|
||||||
update_time, delete_time, deleted
|
update_time, delete_time, deleted
|
||||||
) VALUES
|
) VALUES
|
||||||
<foreach collection="tagList" item="item" separator=",">
|
<foreach collection="tagList" item="item" separator=",">
|
||||||
(
|
(
|
||||||
#{item.id}, #{item.tagID}, #{item.name}, #{item.color}, #{item.description},
|
#{item.id}, #{item.tagID}, #{item.name}, #{item.color}, #{item.description},
|
||||||
#{item.creator}, #{item.updater}, #{item.createTime}, #{item.updateTime},
|
#{item.tagType}, #{item.creator}, #{item.updater}, #{item.createTime}, #{item.updateTime},
|
||||||
#{item.deleteTime}, #{item.deleted}
|
#{item.deleteTime}, #{item.deleted}
|
||||||
)
|
)
|
||||||
</foreach>
|
</foreach>
|
||||||
|
|||||||
360
schoolNewsWeb/TAG_SYSTEM_MIGRATION.md
Normal file
360
schoolNewsWeb/TAG_SYSTEM_MIGRATION.md
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
# 前端标签系统类型化改造文档
|
||||||
|
|
||||||
|
## 📝 改造概述
|
||||||
|
|
||||||
|
前端标签系统已更新,支持3种标签类型,与后端保持一致:
|
||||||
|
1. **文章分类标签** (tagType=1) - 替代原 `ResourceCategory`
|
||||||
|
2. **课程分类标签** (tagType=2)
|
||||||
|
3. **学习任务分类标签** (tagType=3)
|
||||||
|
|
||||||
|
### 改造日期
|
||||||
|
2025-10-27
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 前端变更内容
|
||||||
|
|
||||||
|
### 1. 类型定义更新
|
||||||
|
|
||||||
|
#### 文件:`src/types/resource/index.ts`
|
||||||
|
|
||||||
|
**新增 TagType 枚举:**
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 标签类型枚举
|
||||||
|
*/
|
||||||
|
export enum TagType {
|
||||||
|
/** 文章分类标签 */
|
||||||
|
ARTICLE_CATEGORY = 1,
|
||||||
|
/** 课程分类标签 */
|
||||||
|
COURSE_CATEGORY = 2,
|
||||||
|
/** 学习任务分类标签 */
|
||||||
|
LEARNING_TASK_CATEGORY = 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tag 接口更新:**
|
||||||
|
```typescript
|
||||||
|
export interface Tag extends BaseDTO {
|
||||||
|
/** 标签ID */
|
||||||
|
tagID?: string;
|
||||||
|
/** 标签名称 */
|
||||||
|
name?: string;
|
||||||
|
/** 标签描述 */
|
||||||
|
description?: string;
|
||||||
|
/** 标签颜色 */
|
||||||
|
color?: string;
|
||||||
|
/** 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签) */
|
||||||
|
tagType?: number; // ✅ 新增字段
|
||||||
|
/** 排序号 */
|
||||||
|
orderNum?: number;
|
||||||
|
/** 状态(0禁用 1启用) */
|
||||||
|
status?: number;
|
||||||
|
/** 创建者 */
|
||||||
|
creator?: string;
|
||||||
|
/** 更新者 */
|
||||||
|
updater?: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**ResourceVO 接口更新:**
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 资源视图对象(已废弃category字段)
|
||||||
|
* @deprecated category字段已废弃,请使用tags字段中tagType=1的标签
|
||||||
|
*/
|
||||||
|
export interface ResourceVO extends BaseDTO{
|
||||||
|
resource: Resource;
|
||||||
|
/** @deprecated 已废弃,改用tags字段(tagType=1表示文章分类标签) */
|
||||||
|
category?: ResourceCategory;
|
||||||
|
tags: Tag[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. API 接口更新
|
||||||
|
|
||||||
|
#### 文件:`src/apis/resource/resourceTag.ts`
|
||||||
|
|
||||||
|
**新增方法:**
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 根据标签类型获取标签列表
|
||||||
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
* @returns Promise<ResultDomain<Tag>>
|
||||||
|
*/
|
||||||
|
async getTagsByType(tagType: number): Promise<ResultDomain<Tag>> {
|
||||||
|
const response = await api.get<Tag>(`/news/tags/type/${tagType}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
|
import { TagType } from '@/types/resource';
|
||||||
|
|
||||||
|
// 获取文章分类标签
|
||||||
|
const articleTags = await resourceTagApi.getTagsByType(TagType.ARTICLE_CATEGORY);
|
||||||
|
|
||||||
|
// 获取课程分类标签
|
||||||
|
const courseTags = await resourceTagApi.getTagsByType(TagType.COURSE_CATEGORY);
|
||||||
|
|
||||||
|
// 获取学习任务分类标签
|
||||||
|
const taskTags = await resourceTagApi.getTagsByType(TagType.LEARNING_TASK_CATEGORY);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. ResourceCategory API 废弃
|
||||||
|
|
||||||
|
#### 文件:`src/apis/resource/resourceCategory.ts`
|
||||||
|
|
||||||
|
**⚠️ 此 API 已废弃!**
|
||||||
|
|
||||||
|
从2025-10-27起,资源分类功能已迁移到标签系统(Tag)中。
|
||||||
|
|
||||||
|
**API 迁移对照表:**
|
||||||
|
|
||||||
|
| 原 ResourceCategory API | 新 Tag API | 说明 |
|
||||||
|
|------------------------|-----------|------|
|
||||||
|
| `resourceCategoryApi.getCategoryList()` | `resourceTagApi.getTagsByType(1)` | 获取文章分类标签列表 |
|
||||||
|
| `resourceCategoryApi.getCategoryById(id)` | `resourceTagApi.getTagById(id)` | 获取标签详情 |
|
||||||
|
| `resourceCategoryApi.createCategory(category)` | `resourceTagApi.createTag({...category, tagType: 1})` | 创建文章分类标签 |
|
||||||
|
| `resourceCategoryApi.updateCategory(category)` | `resourceTagApi.updateTag(category)` | 更新标签 |
|
||||||
|
| `resourceCategoryApi.deleteCategory(id)` | `resourceTagApi.deleteTag(id)` | 删除标签 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 已更新的组件
|
||||||
|
|
||||||
|
### 1. ArticleManagementView.vue
|
||||||
|
**文件:** `src/views/admin/manage/resource/ArticleManagementView.vue`
|
||||||
|
|
||||||
|
**变更内容:**
|
||||||
|
```typescript
|
||||||
|
// 修改前
|
||||||
|
import { resourceApi, resourceCategoryApi } from '@/apis/resource'
|
||||||
|
const categoryList = ref<ResourceCategory[]>([]);
|
||||||
|
const res = await resourceCategoryApi.getCategoryList();
|
||||||
|
|
||||||
|
// 修改后
|
||||||
|
import { resourceApi, resourceTagApi } from '@/apis/resource'
|
||||||
|
const categoryList = ref<Tag[]>([]); // 改为使用Tag类型(tagType=1表示文章分类)
|
||||||
|
const res = await resourceTagApi.getTagsByType(1); // 1 = 文章分类标签
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. ArticleAddView.vue
|
||||||
|
**文件:** `src/views/article/ArticleAddView.vue`
|
||||||
|
|
||||||
|
**变更内容:**
|
||||||
|
```typescript
|
||||||
|
// 修改前
|
||||||
|
import { resourceCategoryApi, resourceTagApi, resourceApi } from '@/apis/resource';
|
||||||
|
const categoryList = ref<ResourceCategory[]>([]);
|
||||||
|
const result = await resourceCategoryApi.getCategoryList();
|
||||||
|
|
||||||
|
// 修改后
|
||||||
|
import { resourceTagApi, resourceApi } from '@/apis/resource';
|
||||||
|
const categoryList = ref<Tag[]>([]); // 改为使用Tag类型(tagType=1表示文章分类)
|
||||||
|
const result = await resourceTagApi.getTagsByType(TagType.ARTICLE_CATEGORY);
|
||||||
|
```
|
||||||
|
|
||||||
|
**模板更新:**
|
||||||
|
```vue
|
||||||
|
<!-- 修改前 -->
|
||||||
|
<el-option
|
||||||
|
v-for="category in categoryList"
|
||||||
|
:key="category.tagID || category.id"
|
||||||
|
:label="category.name"
|
||||||
|
:value="category.tagID || category.id || ''"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<el-option
|
||||||
|
v-for="category in categoryList"
|
||||||
|
:key="category.tagID || category.id"
|
||||||
|
:label="category.name"
|
||||||
|
:value="category.tagID || category.id || ''"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. ResourceSideBar.vue
|
||||||
|
**文件:** `src/views/resource-center/components/ResourceSideBar.vue`
|
||||||
|
|
||||||
|
**变更内容:**
|
||||||
|
```typescript
|
||||||
|
// 修改前
|
||||||
|
import { resourceCategoryApi } from '@/apis/resource';
|
||||||
|
import type { ResourceCategory } from '@/types/resource';
|
||||||
|
const categories = ref<ResourceCategory[]>([]);
|
||||||
|
const res = await resourceCategoryApi.getCategoryList();
|
||||||
|
|
||||||
|
// 修改后
|
||||||
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
|
import type { Tag, TagType } from '@/types/resource';
|
||||||
|
const categories = ref<Tag[]>([]); // 改为使用Tag类型(tagType=1表示文章分类)
|
||||||
|
const res = await resourceTagApi.getTagsByType(1); // 1 = 文章分类标签
|
||||||
|
```
|
||||||
|
|
||||||
|
**模板更新:**
|
||||||
|
```vue
|
||||||
|
<!-- 修改前 -->
|
||||||
|
<div
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="category.tagID"
|
||||||
|
:class="{ active: category.tagID === activeCategoryId }"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<div
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="category.tagID || category.id"
|
||||||
|
:class="{ active: (category.tagID || category.id) === activeCategoryId }"
|
||||||
|
>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎓 学习任务和课程标签说明
|
||||||
|
|
||||||
|
### 课程标签(tagType=2)
|
||||||
|
|
||||||
|
**类型定义:** `src/types/study/index.ts`
|
||||||
|
|
||||||
|
课程标签使用统一的标签系统(tb_tag表):
|
||||||
|
- 使用 `tagType=2` 表示课程分类标签
|
||||||
|
- 通过 `resourceTagApi.getTagsByType(TagType.COURSE_CATEGORY)` 获取课程分类标签
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
|
import { TagType } from '@/types/resource';
|
||||||
|
|
||||||
|
// 在课程管理页面加载课程分类标签
|
||||||
|
async function loadCourseTags() {
|
||||||
|
const result = await resourceTagApi.getTagsByType(TagType.COURSE_CATEGORY);
|
||||||
|
if (result.success) {
|
||||||
|
courseTags.value = result.dataList || [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 学习任务标签(tagType=3)
|
||||||
|
|
||||||
|
**类型定义:** `src/types/study/index.ts`
|
||||||
|
|
||||||
|
学习任务分类使用统一的标签系统(tb_tag表):
|
||||||
|
- 使用 `tagType=3` 表示学习任务分类标签
|
||||||
|
- 通过 `resourceTagApi.getTagsByType(TagType.LEARNING_TASK_CATEGORY)` 获取学习任务分类标签
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
|
import { TagType } from '@/types/resource';
|
||||||
|
|
||||||
|
// 在学习任务管理页面加载任务分类标签
|
||||||
|
async function loadTaskTags() {
|
||||||
|
const result = await resourceTagApi.getTagsByType(TagType.LEARNING_TASK_CATEGORY);
|
||||||
|
if (result.success) {
|
||||||
|
taskTags.value = result.dataList || [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 迁移检查清单
|
||||||
|
|
||||||
|
### 开发人员检查清单
|
||||||
|
|
||||||
|
- [x] ✅ 更新 Tag 类型定义(添加 tagType 字段)
|
||||||
|
- [x] ✅ 添加 TagType 枚举
|
||||||
|
- [x] ✅ 更新 resourceTag API(添加 getTagsByType 方法)
|
||||||
|
- [x] ✅ 废弃 resourceCategory API(添加迁移说明)
|
||||||
|
- [x] ✅ 更新 ArticleManagementView 组件
|
||||||
|
- [x] ✅ 更新 ArticleAddView 组件
|
||||||
|
- [x] ✅ 更新 ResourceSideBar 组件
|
||||||
|
- [x] ✅ 添加课程标签说明文档
|
||||||
|
- [x] ✅ 添加学习任务标签说明文档
|
||||||
|
|
||||||
|
### 未来开发任务
|
||||||
|
|
||||||
|
当开发课程管理或学习任务管理功能时:
|
||||||
|
|
||||||
|
- [ ] 在课程管理页面使用 `resourceTagApi.getTagsByType(2)` 获取课程分类标签
|
||||||
|
- [ ] 在学习任务管理页面使用 `resourceTagApi.getTagsByType(3)` 获取任务分类标签
|
||||||
|
- [ ] 为课程添加分类标签选择功能
|
||||||
|
- [ ] 为学习任务添加分类标签选择功能
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 注意事项
|
||||||
|
|
||||||
|
### 1. 向后兼容性
|
||||||
|
|
||||||
|
- `ResourceCategory` 类型和 `resourceCategoryApi` 暂时保留,但标记为 `@deprecated`
|
||||||
|
- 建议尽快迁移到新的标签 API
|
||||||
|
- 旧代码仍可运行,但会在 IDE 中显示废弃警告
|
||||||
|
|
||||||
|
### 2. 字段映射变化
|
||||||
|
|
||||||
|
| ResourceCategory | Tag | 说明 |
|
||||||
|
|-----------------|-----|------|
|
||||||
|
| `tagID` | `tagID` | 唯一标识字段名变更 |
|
||||||
|
| `name` | `name` | 名称字段保持不变 |
|
||||||
|
| `description` | `description` | 描述字段保持不变 |
|
||||||
|
| - | `tagType` | 新增:标签类型(1/2/3) |
|
||||||
|
| - | `color` | 新增:标签颜色 |
|
||||||
|
|
||||||
|
### 3. 导入路径
|
||||||
|
|
||||||
|
所有标签相关的类型和 API 现在统一从以下位置导入:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 类型导入
|
||||||
|
import { Tag, TagType } from '@/types/resource';
|
||||||
|
|
||||||
|
// API 导入
|
||||||
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 总结
|
||||||
|
|
||||||
|
本次前端标签系统改造:
|
||||||
|
|
||||||
|
1. ✅ **统一标签管理** - 文章、课程、学习任务使用统一的标签系统
|
||||||
|
2. ✅ **类型化分类** - 通过 tagType 区分不同业务领域的标签
|
||||||
|
3. ✅ **简化架构** - 废弃 ResourceCategory,统一使用 Tag
|
||||||
|
4. ✅ **灵活扩展** - 为未来添加新标签类型预留空间
|
||||||
|
5. ✅ **向后兼容** - 旧 API 仍可使用(标记为废弃)
|
||||||
|
|
||||||
|
### 迁移前后对比
|
||||||
|
|
||||||
|
| 项目 | 迁移前 | 迁移后 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| 文章分类 | `resourceCategoryApi.getCategoryList()` | `resourceTagApi.getTagsByType(1)` |
|
||||||
|
| 课程分类 | 无 | `resourceTagApi.getTagsByType(2)` |
|
||||||
|
| 学习任务分类 | 无 | `resourceTagApi.getTagsByType(3)` |
|
||||||
|
| 类型定义 | `ResourceCategory` | `Tag` (with tagType) |
|
||||||
|
| 字段名 | `tagID` | `tagID` |
|
||||||
|
|
||||||
|
改造完成后,系统将具备更清晰的业务边界、更简洁的代码结构和更灵活的扩展能力。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 相关文档
|
||||||
|
|
||||||
|
- 后端迁移文档:`schoolNewsServ/.bin/mysql/sql/TAG_TYPE_MIGRATION.md`
|
||||||
|
- 后端移除清单:`schoolNewsServ/.bin/mysql/sql/RESOURCE_CATEGORY_REMOVAL.md`
|
||||||
|
- 前端项目结构:`schoolNewsWeb/PROJECT_STRUCTURE.md`
|
||||||
|
|
||||||
@@ -199,17 +199,17 @@ export const resourceApi = {
|
|||||||
/**
|
/**
|
||||||
* 搜索资源
|
* 搜索资源
|
||||||
* @param keyword 搜索关键词
|
* @param keyword 搜索关键词
|
||||||
* @param categoryID 分类ID(可选)
|
* @param tagID 分类ID(可选)
|
||||||
* @param status 状态(可选)
|
* @param status 状态(可选)
|
||||||
* @returns Promise<ResultDomain<Resource>>
|
* @returns Promise<ResultDomain<Resource>>
|
||||||
*/
|
*/
|
||||||
async searchResources(
|
async searchResources(
|
||||||
keyword: string,
|
keyword: string,
|
||||||
categoryID?: string,
|
tagID?: string,
|
||||||
status?: number
|
status?: number
|
||||||
): Promise<ResultDomain<Resource>> {
|
): Promise<ResultDomain<Resource>> {
|
||||||
const params: any = { keyword };
|
const params: any = { keyword };
|
||||||
if (categoryID) params.categoryID = categoryID;
|
if (tagID) params.tagID = tagID;
|
||||||
if (status !== undefined) params.status = status;
|
if (status !== undefined) params.status = status;
|
||||||
|
|
||||||
const response = await api.get<Resource>('/news/resources/search', params);
|
const response = await api.get<Resource>('/news/resources/search', params);
|
||||||
|
|||||||
@@ -4,6 +4,24 @@
|
|||||||
* @author yslg
|
* @author yslg
|
||||||
* @copyright xyzh
|
* @copyright xyzh
|
||||||
* @since 2025-10-15
|
* @since 2025-10-15
|
||||||
|
*
|
||||||
|
* ⚠️ 注意:此API已废弃!
|
||||||
|
*
|
||||||
|
* 从2025-10-27起,资源分类功能已迁移到标签系统(Tag)中。
|
||||||
|
*
|
||||||
|
* 迁移说明:
|
||||||
|
* - 原 tb_resource_category 表已废弃
|
||||||
|
* - 改为使用 tb_tag 表的 tag_type=1 表示文章分类标签
|
||||||
|
* - 请使用 resourceTagApi.getTagsByType(1) 替代本 API 的方法
|
||||||
|
*
|
||||||
|
* API 迁移对照:
|
||||||
|
* - getCategoryList() → resourceTagApi.getTagsByType(1)
|
||||||
|
* - getCategoryById(id) → resourceTagApi.getTagById(id)
|
||||||
|
* - createCategory(category) → resourceTagApi.createTag({...category, tagType: 1})
|
||||||
|
* - updateCategory(category) → resourceTagApi.updateTag(category)
|
||||||
|
* - deleteCategory(id) → resourceTagApi.deleteTag(id)
|
||||||
|
*
|
||||||
|
* @deprecated 请使用 resourceTagApi 代替
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { api } from '@/apis';
|
import { api } from '@/apis';
|
||||||
@@ -11,6 +29,7 @@ import type { ResultDomain, ResourceCategory } from '@/types';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 资源分类API服务
|
* 资源分类API服务
|
||||||
|
* @deprecated 已废弃,请使用 resourceTagApi.getTagsByType(1) 获取文章分类标签
|
||||||
*/
|
*/
|
||||||
export const resourceCategoryApi = {
|
export const resourceCategoryApi = {
|
||||||
/**
|
/**
|
||||||
@@ -24,11 +43,11 @@ export const resourceCategoryApi = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ID获取分类详情
|
* 根据ID获取分类详情
|
||||||
* @param categoryID 分类ID
|
* @param tagID 分类ID
|
||||||
* @returns Promise<ResultDomain<ResourceCategory>>
|
* @returns Promise<ResultDomain<ResourceCategory>>
|
||||||
*/
|
*/
|
||||||
async getCategoryById(categoryID: string): Promise<ResultDomain<ResourceCategory>> {
|
async getCategoryById(tagID: string): Promise<ResultDomain<ResourceCategory>> {
|
||||||
const response = await api.get<ResourceCategory>(`/news/categorys/category/${categoryID}`);
|
const response = await api.get<ResourceCategory>(`/news/categorys/category/${tagID}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -54,22 +73,22 @@ export const resourceCategoryApi = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除分类
|
* 删除分类
|
||||||
* @param categoryID 分类ID
|
* @param tagID 分类ID
|
||||||
* @returns Promise<ResultDomain<boolean>>
|
* @returns Promise<ResultDomain<boolean>>
|
||||||
*/
|
*/
|
||||||
async deleteCategory(categoryID: string): Promise<ResultDomain<boolean>> {
|
async deleteCategory(tagID: string): Promise<ResultDomain<boolean>> {
|
||||||
const response = await api.delete<boolean>(`/news/categorys/category/${categoryID}`);
|
const response = await api.delete<boolean>(`/news/categorys/category/${tagID}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新分类状态
|
* 更新分类状态
|
||||||
* @param categoryID 分类ID
|
* @param tagID 分类ID
|
||||||
* @param status 状态值
|
* @param status 状态值
|
||||||
* @returns Promise<ResultDomain<ResourceCategory>>
|
* @returns Promise<ResultDomain<ResourceCategory>>
|
||||||
*/
|
*/
|
||||||
async updateCategoryStatus(categoryID: string, status: number): Promise<ResultDomain<ResourceCategory>> {
|
async updateCategoryStatus(tagID: string, status: number): Promise<ResultDomain<ResourceCategory>> {
|
||||||
const response = await api.put<ResourceCategory>(`/news/categorys/category/${categoryID}/status`, null, {
|
const response = await api.put<ResourceCategory>(`/news/categorys/category/${tagID}/status`, null, {
|
||||||
params: { status }
|
params: { status }
|
||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const resourceTagApi = {
|
|||||||
// ==================== 标签基础操作 ====================
|
// ==================== 标签基础操作 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取标签列表
|
* 获取标签列表(获取所有标签)
|
||||||
* @returns Promise<ResultDomain<Tag>>
|
* @returns Promise<ResultDomain<Tag>>
|
||||||
*/
|
*/
|
||||||
async getTagList(): Promise<ResultDomain<Tag>> {
|
async getTagList(): Promise<ResultDomain<Tag>> {
|
||||||
@@ -24,6 +24,16 @@ export const resourceTagApi = {
|
|||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据标签类型获取标签列表
|
||||||
|
* @param tagType 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签)
|
||||||
|
* @returns Promise<ResultDomain<Tag>>
|
||||||
|
*/
|
||||||
|
async getTagsByType(tagType: number): Promise<ResultDomain<Tag>> {
|
||||||
|
const response = await api.get<Tag>(`/news/tags/type/${tagType}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ID获取标签详情
|
* 根据ID获取标签详情
|
||||||
* @param tagID 标签ID
|
* @param tagID 标签ID
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
v-if="expanded && !collapsed"
|
v-if="expanded && !collapsed"
|
||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-for="child in menu.children"
|
v-for="child in filteredChildren"
|
||||||
:key="child.menuID"
|
:key="child.menuID"
|
||||||
:menu="child"
|
:menu="child"
|
||||||
:collapsed="false"
|
:collapsed="false"
|
||||||
@@ -85,15 +85,23 @@ const emit = defineEmits<{
|
|||||||
'menu-click': [menu: SysMenu];
|
'menu-click': [menu: SysMenu];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 状态
|
// 状态 - 顶层菜单默认展开
|
||||||
const expanded = ref(false);
|
const expanded = ref(props.level === 0);
|
||||||
|
|
||||||
// Composition API
|
// Composition API
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const hasChildren = computed(() => {
|
const hasChildren = computed(() => {
|
||||||
return props.menu.children && props.menu.children.length > 0;
|
// 只显示SIDEBAR类型的子菜单,过滤掉PAGE类型
|
||||||
|
return props.menu.children &&
|
||||||
|
props.menu.children.filter((child: SysMenu) => child.type === MenuType.SIDEBAR).length > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 过滤后的子菜单(只显示SIDEBAR类型)
|
||||||
|
const filteredChildren = computed(() => {
|
||||||
|
if (!props.menu.children) return [];
|
||||||
|
return props.menu.children.filter((child: SysMenu) => child.type === MenuType.SIDEBAR);
|
||||||
});
|
});
|
||||||
|
|
||||||
const isActive = computed(() => {
|
const isActive = computed(() => {
|
||||||
@@ -109,7 +117,8 @@ function toggleExpanded() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
if (props.menu.type === MenuType.NAVIGATION && props.menu.url) {
|
// 支持NAVIGATION和SIDEBAR类型的菜单点击
|
||||||
|
if (props.menu.url && (props.menu.type === MenuType.NAVIGATION || props.menu.type === MenuType.SIDEBAR)) {
|
||||||
emit('menu-click', props.menu);
|
emit('menu-click', props.menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
<!-- <div class="breadcrumb-wrapper" v-if="breadcrumbItems.length > 0">
|
<!-- <div class="breadcrumb-wrapper" v-if="breadcrumbItems.length > 0">
|
||||||
<Breadcrumb :items="breadcrumbItems" />
|
<Breadcrumb :items="breadcrumbItems" />
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<!-- 显示导航栏的侧边栏和内容 -->
|
||||||
<!-- 侧边栏和内容 -->
|
|
||||||
<div class="content-wrapper" v-if="hasSidebarMenus">
|
<div class="content-wrapper" v-if="hasSidebarMenus">
|
||||||
<!-- 侧边栏 -->
|
<!-- 侧边栏 -->
|
||||||
<aside class="sidebar" :class="{ collapsed: sidebarCollapsed }">
|
<aside class="sidebar" :class="{ collapsed: sidebarCollapsed }">
|
||||||
|
|||||||
243
schoolNewsWeb/src/layouts/SidebarLayout.vue
Normal file
243
schoolNewsWeb/src/layouts/SidebarLayout.vue
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sidebar-layout">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<TopNavigation />
|
||||||
|
|
||||||
|
<!-- 主内容区域 -->
|
||||||
|
<div class="layout-content">
|
||||||
|
<!-- 侧边栏和内容 -->
|
||||||
|
<div class="content-wrapper" v-if="hasSidebarMenus">
|
||||||
|
<!-- 侧边栏 -->
|
||||||
|
<aside class="sidebar" :class="{ collapsed: sidebarCollapsed }">
|
||||||
|
<div class="sidebar-toggle-btn" @click="toggleSidebar">
|
||||||
|
<i class="toggle-icon">{{ sidebarCollapsed ? '▶' : '◀' }}</i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<MenuSidebar
|
||||||
|
:menus="sidebarMenus"
|
||||||
|
:collapsed="sidebarCollapsed"
|
||||||
|
@menu-click="handleMenuClick"
|
||||||
|
/>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- 页面内容 -->
|
||||||
|
<main class="main-content">
|
||||||
|
<router-view />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 没有侧边栏时直接显示内容 -->
|
||||||
|
<div class="content-wrapper-full" v-else>
|
||||||
|
<main class="main-content-full">
|
||||||
|
<router-view />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
import type { SysMenu } from '@/types';
|
||||||
|
import { MenuType } from '@/types/enums';
|
||||||
|
import { TopNavigation, MenuSidebar } from '@/components';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const sidebarCollapsed = ref(false);
|
||||||
|
|
||||||
|
// 获取所有菜单
|
||||||
|
const allMenus = computed(() => store.getters['auth/menuTree']);
|
||||||
|
|
||||||
|
// 获取所有顶层SIDEBAR菜单作为侧边栏
|
||||||
|
const sidebarMenus = computed(() => {
|
||||||
|
// 严格过滤:type=SIDEBAR 且 layout='SidebarLayout' 的顶层菜单
|
||||||
|
return allMenus.value.filter((menu: SysMenu) =>
|
||||||
|
menu.type === MenuType.SIDEBAR &&
|
||||||
|
!menu.parentID &&
|
||||||
|
(menu as any).layout === 'SidebarLayout'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 是否有侧边栏菜单
|
||||||
|
const hasSidebarMenus = computed(() => sidebarMenus.value.length > 0);
|
||||||
|
|
||||||
|
// 切换侧边栏
|
||||||
|
function toggleSidebar() {
|
||||||
|
sidebarCollapsed.value = !sidebarCollapsed.value;
|
||||||
|
localStorage.setItem('sidebarCollapsed', String(sidebarCollapsed.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理菜单点击
|
||||||
|
function handleMenuClick(menu: SysMenu) {
|
||||||
|
if (menu.url && menu.url !== route.path) {
|
||||||
|
router.push(menu.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复侧边栏状态
|
||||||
|
const savedState = localStorage.getItem('sidebarCollapsed');
|
||||||
|
if (savedState !== null) {
|
||||||
|
sidebarCollapsed.value = savedState === 'true';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.sidebar-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: calc(100vh - 76px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
margin: 16px;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 260px;
|
||||||
|
background: #001529;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
max-height: calc(100vh - 108px); // 顶部导航76px + 上下边距32px
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: -12px;
|
||||||
|
width: 24px;
|
||||||
|
height: 48px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
border-radius: 0 12px 12px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px 0;
|
||||||
|
|
||||||
|
// 美化滚动条
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
background: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||||
|
overflow-y: auto;
|
||||||
|
min-width: 0;
|
||||||
|
height: calc(100vh - 108px); // 固定高度:视口高度 - 顶部导航76px - 上下边距32px
|
||||||
|
max-height: calc(100vh - 108px);
|
||||||
|
|
||||||
|
// 美化滚动条
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-wrapper-full {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content-full {
|
||||||
|
background: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||||
|
height: calc(100vh - 108px);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
// 美化滚动条
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ export interface Resource extends BaseDTO {
|
|||||||
summary?: string;
|
summary?: string;
|
||||||
/** 封面图片 */
|
/** 封面图片 */
|
||||||
coverImage?: string;
|
coverImage?: string;
|
||||||
/** 分类ID */
|
/** 标签ID(文章分类标签,tagType=1) */
|
||||||
categoryID?: string;
|
tagID?: string;
|
||||||
/** 作者 */
|
/** 作者 */
|
||||||
author?: string;
|
author?: string;
|
||||||
/** 来源 */
|
/** 来源 */
|
||||||
@@ -81,10 +81,11 @@ export interface Banner extends BaseDTO {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 资源分类实体
|
* 资源分类实体
|
||||||
|
* @deprecated 已废弃,请使用 Tag 接口(tagType=1表示文章分类标签)
|
||||||
*/
|
*/
|
||||||
export interface ResourceCategory extends BaseDTO {
|
export interface ResourceCategory extends BaseDTO {
|
||||||
/** 分类唯一标识 */
|
/** 分类唯一标识 */
|
||||||
categoryID?: string;
|
tagID?: string;
|
||||||
/** 分类名称 */
|
/** 分类名称 */
|
||||||
name?: string;
|
name?: string;
|
||||||
/** 父分类ID */
|
/** 父分类ID */
|
||||||
@@ -111,6 +112,18 @@ export interface ResourceTag extends BaseDTO {
|
|||||||
tagID?: string;
|
tagID?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签类型枚举
|
||||||
|
*/
|
||||||
|
export enum TagType {
|
||||||
|
/** 文章分类标签 */
|
||||||
|
ARTICLE_CATEGORY = 1,
|
||||||
|
/** 课程分类标签 */
|
||||||
|
COURSE_CATEGORY = 2,
|
||||||
|
/** 学习任务分类标签 */
|
||||||
|
LEARNING_TASK_CATEGORY = 3
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签实体
|
* 标签实体
|
||||||
*/
|
*/
|
||||||
@@ -123,15 +136,21 @@ export interface Tag extends BaseDTO {
|
|||||||
description?: string;
|
description?: string;
|
||||||
/** 标签颜色 */
|
/** 标签颜色 */
|
||||||
color?: string;
|
color?: string;
|
||||||
|
/** 标签类型(1-文章分类标签 2-课程分类标签 3-学习任务分类标签) */
|
||||||
|
tagType?: number;
|
||||||
/** 排序号 */
|
/** 排序号 */
|
||||||
orderNum?: number;
|
orderNum?: number;
|
||||||
/** 状态(0禁用 1启用) */
|
/** 状态(0禁用 1启用) */
|
||||||
status?: number;
|
status?: number;
|
||||||
|
/** 创建者 */
|
||||||
|
creator?: string;
|
||||||
|
/** 更新者 */
|
||||||
|
updater?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ResourceVO extends BaseDTO{
|
export interface ResourceVO extends BaseDTO{
|
||||||
resource: Resource;
|
resource: Resource;
|
||||||
category: ResourceCategory;
|
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
}
|
}
|
||||||
export interface tagVO extends BaseDTO{
|
export interface tagVO extends BaseDTO{
|
||||||
@@ -198,8 +217,8 @@ export interface DataCollectionLog extends BaseDTO {
|
|||||||
export interface ResourceSearchParams {
|
export interface ResourceSearchParams {
|
||||||
/** 关键词 */
|
/** 关键词 */
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
/** 分类ID */
|
/** 标签ID(文章分类标签,tagType=1) */
|
||||||
categoryID?: string;
|
tagID?: string;
|
||||||
/** 状态 */
|
/** 状态 */
|
||||||
status?: number;
|
status?: number;
|
||||||
/** 是否推荐 */
|
/** 是否推荐 */
|
||||||
|
|||||||
@@ -71,11 +71,18 @@ export interface CourseChapter extends BaseDTO {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 课程标签关联实体
|
* 课程标签关联实体
|
||||||
|
*
|
||||||
|
* 说明:课程标签使用统一的标签系统(tb_tag表)
|
||||||
|
* - 使用 tagType=2 表示课程分类标签
|
||||||
|
* - 通过 resourceTagApi.getTagsByType(2) 或 resourceTagApi.getTagsByType(TagType.COURSE_CATEGORY) 获取课程分类标签
|
||||||
|
*
|
||||||
|
* @see Tag - 标签实体定义
|
||||||
|
* @see TagType - 标签类型枚举(COURSE_CATEGORY = 2)
|
||||||
*/
|
*/
|
||||||
export interface CourseTag extends BaseDTO {
|
export interface CourseTag extends BaseDTO {
|
||||||
/** 课程ID */
|
/** 课程ID */
|
||||||
courseID?: string;
|
courseID?: string;
|
||||||
/** 标签ID */
|
/** 标签ID(关联 tb_tag 表,tagType=2 的标签) */
|
||||||
tagID?: string;
|
tagID?: string;
|
||||||
/** 创建者 */
|
/** 创建者 */
|
||||||
creator?: string;
|
creator?: string;
|
||||||
@@ -124,6 +131,13 @@ export interface CourseVO extends BaseDTO {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 学习任务实体
|
* 学习任务实体
|
||||||
|
*
|
||||||
|
* 说明:学习任务分类使用统一的标签系统(tb_tag表)
|
||||||
|
* - 使用 tagType=3 表示学习任务分类标签
|
||||||
|
* - 通过 resourceTagApi.getTagsByType(3) 或 resourceTagApi.getTagsByType(TagType.LEARNING_TASK_CATEGORY) 获取学习任务分类标签
|
||||||
|
*
|
||||||
|
* @see Tag - 标签实体定义
|
||||||
|
* @see TagType - 标签类型枚举(LEARNING_TASK_CATEGORY = 3)
|
||||||
*/
|
*/
|
||||||
export interface LearningTask extends BaseDTO {
|
export interface LearningTask extends BaseDTO {
|
||||||
/** 任务唯一标识 */
|
/** 任务唯一标识 */
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ const LAYOUT_MAP: Record<string, () => Promise<any>> = {
|
|||||||
'BasicLayout': () => import('@/layouts/BasicLayout.vue'),
|
'BasicLayout': () => import('@/layouts/BasicLayout.vue'),
|
||||||
// 导航布局(新版,顶部导航+动态侧边栏)
|
// 导航布局(新版,顶部导航+动态侧边栏)
|
||||||
'NavigationLayout': () => import('@/layouts/NavigationLayout.vue'),
|
'NavigationLayout': () => import('@/layouts/NavigationLayout.vue'),
|
||||||
|
// 侧边栏布局(管理后台专用,顶层SIDEBAR菜单)
|
||||||
|
'SidebarLayout': () => import('@/layouts/SidebarLayout.vue'),
|
||||||
// 空白布局
|
// 空白布局
|
||||||
'BlankLayout': () => import('@/layouts/BlankLayout.vue'),
|
'BlankLayout': () => import('@/layouts/BlankLayout.vue'),
|
||||||
// 页面布局
|
// 页面布局
|
||||||
@@ -126,10 +128,11 @@ function generateRouteFromMenu(menu: SysMenu, isTopLevel = true): RouteRecordRaw
|
|||||||
route.component = getComponent(layout);
|
route.component = getComponent(layout);
|
||||||
} else if (hasChildren && isTopLevel) {
|
} else if (hasChildren && isTopLevel) {
|
||||||
// 如果有子菜单但没有指定布局,根据菜单类型选择默认布局
|
// 如果有子菜单但没有指定布局,根据菜单类型选择默认布局
|
||||||
if (isTopLevel && menu.type === MenuType.NAVIGATION) {
|
if (menu.type === MenuType.NAVIGATION) {
|
||||||
route.component = getComponent('NavigationLayout');
|
route.component = getComponent('NavigationLayout');
|
||||||
} else if (menu.type === MenuType.SIDEBAR) {
|
} else if (menu.type === MenuType.SIDEBAR && !menu.parentID) {
|
||||||
route.component = getComponent('BlankLayout');
|
// 顶层SIDEBAR菜单(管理后台)默认使用SidebarLayout
|
||||||
|
route.component = getComponent('SidebarLayout');
|
||||||
} else {
|
} else {
|
||||||
route.component = getComponent('BasicLayout');
|
route.component = getComponent('BasicLayout');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,55 +7,283 @@
|
|||||||
placeholder="搜索标签..."
|
placeholder="搜索标签..."
|
||||||
style="width: 300px"
|
style="width: 300px"
|
||||||
clearable
|
clearable
|
||||||
|
@change="handleSearch"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="tags" style="width: 100%">
|
<el-table :data="filteredTags" style="width: 100%" v-loading="loading">
|
||||||
<el-table-column prop="name" label="标签名称" min-width="150" />
|
<el-table-column prop="name" label="标签名称" min-width="150" />
|
||||||
<el-table-column prop="category" label="标签分类" width="120" />
|
<el-table-column prop="tagType" label="标签类型" width="120">
|
||||||
<el-table-column prop="color" label="颜色" width="100">
|
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="color-preview" :style="{ background: row.color }"></div>
|
<el-tag :type="getTagTypeColor(row.tagType)">
|
||||||
|
{{ getTagTypeName(row.tagType) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="color" label="颜色" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="color-display">
|
||||||
|
<div class="color-preview" :style="{ background: row.color }"></div>
|
||||||
|
<span>{{ row.color }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="status" label="状态" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.status === 1 ? 'success' : 'info'">
|
||||||
|
{{ row.status === 1 ? '启用' : '禁用' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="orderNum" label="排序" width="80" />
|
||||||
|
<el-table-column prop="createTime" label="创建时间" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatTime(row.createTime) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="usageCount" label="使用次数" width="100" />
|
|
||||||
<el-table-column prop="createDate" label="创建时间" width="150" />
|
|
||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button size="small" @click="editTag(row)">编辑</el-button>
|
<el-button link type="primary" size="small" @click="editTag(row)">编辑</el-button>
|
||||||
<el-button size="small" type="danger" @click="deleteTag(row)">删除</el-button>
|
<el-button link type="danger" size="small" @click="deleteTag(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 创建/编辑标签对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="isEdit ? '编辑标签' : '新增标签'"
|
||||||
|
width="500px"
|
||||||
|
@close="handleDialogClose"
|
||||||
|
>
|
||||||
|
<el-form :model="currentTag" :rules="rules" ref="formRef" label-width="100px">
|
||||||
|
<el-form-item label="标签名称" prop="name">
|
||||||
|
<el-input v-model="currentTag.name" placeholder="请输入标签名称" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="标签类型" prop="tagType">
|
||||||
|
<el-select v-model="currentTag.tagType" placeholder="请选择标签类型" style="width: 100%">
|
||||||
|
<el-option label="文章分类标签" :value="1" />
|
||||||
|
<el-option label="课程分类标签" :value="2" />
|
||||||
|
<el-option label="学习任务分类标签" :value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="标签颜色" prop="color">
|
||||||
|
<div class="color-picker-wrapper">
|
||||||
|
<el-color-picker v-model="currentTag.color" />
|
||||||
|
<el-input v-model="currentTag.color" placeholder="#000000" style="width: 150px; margin-left: 10px" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="标签描述">
|
||||||
|
<el-input
|
||||||
|
v-model="currentTag.description"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="请输入标签描述"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="排序号" prop="orderNum">
|
||||||
|
<el-input-number v-model="currentTag.orderNum" :min="0" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-radio-group v-model="currentTag.status">
|
||||||
|
<el-radio :label="1">启用</el-radio>
|
||||||
|
<el-radio :label="0">禁用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { ElButton, ElInput, ElTable, ElTableColumn, ElMessage } from 'element-plus';
|
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
|
||||||
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
|
import type { Tag } from '@/types/resource';
|
||||||
|
|
||||||
const searchKeyword = ref('');
|
const searchKeyword = ref('');
|
||||||
const tags = ref<any[]>([]);
|
const tags = ref<Tag[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const submitting = ref(false);
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const currentTag = ref<Partial<Tag>>({
|
||||||
|
name: '',
|
||||||
|
tagType: 1,
|
||||||
|
color: '#409EFF',
|
||||||
|
description: '',
|
||||||
|
orderNum: 0,
|
||||||
|
status: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules: FormRules = {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入标签名称', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
tagType: [
|
||||||
|
{ required: true, message: '请选择标签类型', trigger: 'change' }
|
||||||
|
],
|
||||||
|
color: [
|
||||||
|
{ required: true, message: '请选择标签颜色', trigger: 'change' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 过滤后的标签列表
|
||||||
|
const filteredTags = computed(() => {
|
||||||
|
if (!searchKeyword.value) return tags.value;
|
||||||
|
const keyword = searchKeyword.value.toLowerCase();
|
||||||
|
return tags.value.filter(tag =>
|
||||||
|
tag.name?.toLowerCase().includes(keyword) ||
|
||||||
|
tag.description?.toLowerCase().includes(keyword)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadTags();
|
loadTags();
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadTags() {
|
// 加载标签列表
|
||||||
// TODO: 加载标签数据
|
async function loadTags() {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const result = await resourceTagApi.getTagList();
|
||||||
|
if (result.success) {
|
||||||
|
tags.value = result.dataList || [];
|
||||||
|
} else {
|
||||||
|
ElMessage.error(result.message || '加载标签列表失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载标签列表失败:', error);
|
||||||
|
ElMessage.error('加载标签列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
function handleSearch() {
|
||||||
|
// 搜索由computed自动处理
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示创建对话框
|
||||||
function showCreateDialog() {
|
function showCreateDialog() {
|
||||||
// TODO: 显示创建标签对话框
|
isEdit.value = false;
|
||||||
|
currentTag.value = {
|
||||||
|
name: '',
|
||||||
|
tagType: 1,
|
||||||
|
color: '#409EFF',
|
||||||
|
description: '',
|
||||||
|
orderNum: 0,
|
||||||
|
status: 1
|
||||||
|
};
|
||||||
|
dialogVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function editTag(row: any) {
|
// 编辑标签
|
||||||
// TODO: 编辑标签
|
function editTag(row: Tag) {
|
||||||
|
isEdit.value = true;
|
||||||
|
currentTag.value = { ...row };
|
||||||
|
dialogVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteTag(row: any) {
|
// 删除标签
|
||||||
// TODO: 删除标签
|
async function deleteTag(row: Tag) {
|
||||||
ElMessage.success('删除成功');
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要删除标签"${row.name}"吗?删除后不可恢复。`,
|
||||||
|
'删除确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await resourceTagApi.deleteTag(row.tagID!);
|
||||||
|
if (result.success) {
|
||||||
|
ElMessage.success('删除成功');
|
||||||
|
loadTags();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(result.message || '删除失败');
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('删除标签失败:', error);
|
||||||
|
ElMessage.error('删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
async function handleSubmit() {
|
||||||
|
if (!formRef.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await formRef.value.validate();
|
||||||
|
submitting.value = true;
|
||||||
|
|
||||||
|
let result;
|
||||||
|
if (isEdit.value) {
|
||||||
|
result = await resourceTagApi.updateTag(currentTag.value as Tag);
|
||||||
|
} else {
|
||||||
|
result = await resourceTagApi.createTag(currentTag.value as Tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
ElMessage.success(isEdit.value ? '更新成功' : '创建成功');
|
||||||
|
dialogVisible.value = false;
|
||||||
|
loadTags();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(result.message || (isEdit.value ? '更新失败' : '创建失败'));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error);
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对话框关闭处理
|
||||||
|
function handleDialogClose() {
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取标签类型名称
|
||||||
|
function getTagTypeName(type?: number): string {
|
||||||
|
const map: Record<number, string> = {
|
||||||
|
1: '文章分类',
|
||||||
|
2: '课程分类',
|
||||||
|
3: '任务分类'
|
||||||
|
};
|
||||||
|
return map[type || 1] || '未知';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取标签类型颜色
|
||||||
|
function getTagTypeColor(type?: number): string {
|
||||||
|
const map: Record<number, string> = {
|
||||||
|
1: 'primary',
|
||||||
|
2: 'success',
|
||||||
|
3: 'warning'
|
||||||
|
};
|
||||||
|
return map[type || 1] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化时间
|
||||||
|
function formatTime(time?: string): string {
|
||||||
|
if (!time) return '-';
|
||||||
|
return new Date(time).toLocaleString('zh-CN');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -71,11 +299,21 @@ function deleteTag(row: any) {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-display {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.color-preview {
|
.color-preview {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
|
||||||
|
.color-picker-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -68,8 +68,8 @@
|
|||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import { ElButton, ElInput, ElTable, ElTableColumn, ElTag, ElPagination, ElMessage } from 'element-plus';
|
import { ElButton, ElInput, ElTable, ElTableColumn, ElTag, ElPagination, ElMessage } from 'element-plus';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { resourceApi, resourceCategoryApi } from '@/apis/resource'
|
import { resourceApi, resourceTagApi } from '@/apis/resource'
|
||||||
import type { PageParam, ResourceSearchParams, Resource, ResourceCategory } from '@/types';
|
import type { PageParam, ResourceSearchParams, Resource, Tag } from '@/types';
|
||||||
import { ArticleShowView } from '@/views/article';
|
import { ArticleShowView } from '@/views/article';
|
||||||
import { ArticleStatus } from '@/types/enums';
|
import { ArticleStatus } from '@/types/enums';
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ const total = ref<number>(0);
|
|||||||
const articles = ref<Resource[]>([]);
|
const articles = ref<Resource[]>([]);
|
||||||
const showViewDialog = ref(false);
|
const showViewDialog = ref(false);
|
||||||
const currentArticle = ref<any>(null);
|
const currentArticle = ref<any>(null);
|
||||||
const categoryList = ref<ResourceCategory[]>([]);
|
const categoryList = ref<Tag[]>([]); // 改为使用Tag类型(tagType=1表示文章分类)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadArticles();
|
loadArticles();
|
||||||
@@ -95,7 +95,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
async function loadCategories() {
|
async function loadCategories() {
|
||||||
try {
|
try {
|
||||||
const res = await resourceCategoryApi.getCategoryList();
|
// 使用新的标签API获取文章分类标签(tagType=1)
|
||||||
|
const res = await resourceTagApi.getTagsByType(1); // 1 = 文章分类标签
|
||||||
if (res.success && res.dataList) {
|
if (res.success && res.dataList) {
|
||||||
categoryList.value = res.dataList;
|
categoryList.value = res.dataList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,25 +15,13 @@
|
|||||||
<!-- 分类和标签 -->
|
<!-- 分类和标签 -->
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="文章分类" prop="resource.categoryID">
|
<el-form-item label="文章分类" prop="resource.tagID">
|
||||||
<el-select v-model="articleForm.resource.categoryID" placeholder="请选择分类" style="width: 100%" :loading="categoryLoading">
|
<el-select v-model="articleForm.resource.tagID" placeholder="请选择分类" style="width: 100%" :loading="categoryLoading" value-key="tagID">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="category in categoryList"
|
v-for="category in categoryList"
|
||||||
:key="category.categoryID || category.id"
|
:key="category.tagID || category.id"
|
||||||
:label="category.name"
|
:label="category.name"
|
||||||
:value="category.categoryID || category.id || ''"
|
:value="category.tagID||''"
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="标签" prop="tags">
|
|
||||||
<el-select v-model="articleForm.tags" multiple placeholder="请选择标签" style="width: 100%" :loading="tagLoading">
|
|
||||||
<el-option
|
|
||||||
v-for="tag in tagList"
|
|
||||||
:key="tag.id || tag.tagID"
|
|
||||||
:label="tag.name"
|
|
||||||
:value="tag.id || tag.tagID || ''"
|
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -127,8 +115,8 @@ import { ArrowLeft } from '@element-plus/icons-vue';
|
|||||||
import { RichTextComponent } from '@/components/text';
|
import { RichTextComponent } from '@/components/text';
|
||||||
import { FileUpload } from '@/components/file';
|
import { FileUpload } from '@/components/file';
|
||||||
import { ArticleShowView } from './index';
|
import { ArticleShowView } from './index';
|
||||||
import { resourceCategoryApi, resourceTagApi, resourceApi } from '@/apis/resource';
|
import { resourceTagApi, resourceApi } from '@/apis/resource';
|
||||||
import { ResourceVO, ResourceCategory, Tag } from '@/types/resource';
|
import { ResourceVO, Tag, TagType } from '@/types/resource';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -143,7 +131,7 @@ const previewVisible = ref(false);
|
|||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
|
|
||||||
// 数据状态
|
// 数据状态
|
||||||
const categoryList = ref<ResourceCategory[]>([]);
|
const categoryList = ref<Tag[]>([]); // 改为使用Tag类型(tagType=1表示文章分类)
|
||||||
const tagList = ref<Tag[]>([]);
|
const tagList = ref<Tag[]>([]);
|
||||||
const categoryLoading = ref(false);
|
const categoryLoading = ref(false);
|
||||||
const tagLoading = ref(false);
|
const tagLoading = ref(false);
|
||||||
@@ -152,7 +140,6 @@ const tagLoading = ref(false);
|
|||||||
const articleForm = ref<ResourceVO>({
|
const articleForm = ref<ResourceVO>({
|
||||||
resource: {
|
resource: {
|
||||||
},
|
},
|
||||||
category: {},
|
|
||||||
tags: [],
|
tags: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -162,7 +149,7 @@ const rules = {
|
|||||||
{ required: true, message: '请输入文章标题', trigger: 'blur' },
|
{ required: true, message: '请输入文章标题', trigger: 'blur' },
|
||||||
{ min: 5, max: 100, message: '标题长度在 5 到 100 个字符', trigger: 'blur' }
|
{ min: 5, max: 100, message: '标题长度在 5 到 100 个字符', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
'resource.categoryID': [
|
'resource.tagID': [
|
||||||
{ required: true, message: '请选择文章分类', trigger: 'change' }
|
{ required: true, message: '请选择文章分类', trigger: 'change' }
|
||||||
],
|
],
|
||||||
'resource.content': [
|
'resource.content': [
|
||||||
@@ -171,11 +158,12 @@ const rules = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 加载分类列表
|
// 加载分类列表(使用标签API,tagType=1表示文章分类标签)
|
||||||
async function loadCategoryList() {
|
async function loadCategoryList() {
|
||||||
try {
|
try {
|
||||||
categoryLoading.value = true;
|
categoryLoading.value = true;
|
||||||
const result = await resourceCategoryApi.getCategoryList();
|
// 使用新的标签API获取文章分类标签(tagType=1)
|
||||||
|
const result = await resourceTagApi.getTagsByType(TagType.ARTICLE_CATEGORY);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// 数组数据从 dataList 获取
|
// 数组数据从 dataList 获取
|
||||||
categoryList.value = result.dataList || [];
|
categoryList.value = result.dataList || [];
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h1 class="platform-title">红色思政学习平台</h1>
|
<h1 class="platform-title">红色思政学习平台</h1>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="login-title">账号登陆</h2>
|
<h2 class="login-title">账号登录</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 登录表单 -->
|
<!-- 登录表单 -->
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="loginForm.username"
|
v-model="loginForm.username"
|
||||||
placeholder="请输入学号"
|
placeholder="请输入学号、手机号"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
登录
|
登录
|
||||||
</el-button>
|
</el-button>
|
||||||
<p class="agreement-text">
|
<p class="agreement-text">
|
||||||
登录即为同意<span class="agreement-link" style="color: red">《红色思政智能体平台》</span>
|
<el-checkbox v-model="loginForm.rememberMe">登录即为同意<span class="agreement-link" style="color: red">《红色思政智能体平台》</span></el-checkbox>
|
||||||
</p>
|
</p>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|||||||
@@ -11,13 +11,13 @@
|
|||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<ResourceSideBar
|
<ResourceSideBar
|
||||||
:active-category-id="currentCategoryId"
|
:activeTagID="currentCategoryId"
|
||||||
@category-change="handleCategoryChange"
|
@category-change="handleCategoryChange"
|
||||||
/>
|
/>
|
||||||
<ResourceList
|
<ResourceList
|
||||||
v-if="!showArticle"
|
v-if="!showArticle"
|
||||||
ref="resourceListRef"
|
ref="resourceListRef"
|
||||||
:category-id="currentCategoryId"
|
:tagID="currentCategoryId"
|
||||||
:search-keyword="searchKeyword"
|
:search-keyword="searchKeyword"
|
||||||
@resource-click="handleResourceClick"
|
@resource-click="handleResourceClick"
|
||||||
@list-updated="handleListUpdated"
|
@list-updated="handleListUpdated"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<ResourceArticle
|
<ResourceArticle
|
||||||
v-if="showArticle"
|
v-if="showArticle"
|
||||||
:resource-id="currentResourceId"
|
:resource-id="currentResourceId"
|
||||||
:category-id="currentCategoryId"
|
:tagID="currentCategoryId"
|
||||||
:resource-list="resourceList"
|
:resource-list="resourceList"
|
||||||
@resource-change="handleResourceChange"
|
@resource-change="handleResourceChange"
|
||||||
@navigate="handleArticleNavigate"
|
@navigate="handleArticleNavigate"
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { ResourceSideBar, ResourceList, ResourceArticle } from './components';
|
import { ResourceSideBar, ResourceList, ResourceArticle } from './components';
|
||||||
import { Search, CenterHead } from '@/components/base';
|
import { Search, CenterHead } from '@/components/base';
|
||||||
import type { Resource, ResourceCategory } from '@/types/resource';
|
import type { Resource, Tag } from '@/types/resource';
|
||||||
|
|
||||||
const showArticle = ref(false);
|
const showArticle = ref(false);
|
||||||
const currentCategoryId = ref('party_history');
|
const currentCategoryId = ref('party_history');
|
||||||
@@ -50,8 +50,8 @@ const searchKeyword = ref('');
|
|||||||
const resourceListRef = ref();
|
const resourceListRef = ref();
|
||||||
const resourceList = ref<Resource[]>([]);
|
const resourceList = ref<Resource[]>([]);
|
||||||
|
|
||||||
function handleCategoryChange(category: ResourceCategory) {
|
function handleCategoryChange(category: Tag) {
|
||||||
currentCategoryId.value = category.categoryID || '';
|
currentCategoryId.value = category.tagID || category.id || '';
|
||||||
currentCategoryName.value = category.name || '';
|
currentCategoryName.value = category.name || '';
|
||||||
searchKeyword.value = '';
|
searchKeyword.value = '';
|
||||||
showArticle.value = false;
|
showArticle.value = false;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { CollectionType, type UserCollection } from '@/types';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
resourceId?: string;
|
resourceId?: string;
|
||||||
categoryId?: string;
|
tagID?: string;
|
||||||
resourceList?: Resource[];
|
resourceList?: Resource[];
|
||||||
}
|
}
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import type { PageParam } from '@/types';
|
|||||||
import defaultArticleImg from '@/assets/imgs/article-default.png';
|
import defaultArticleImg from '@/assets/imgs/article-default.png';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
categoryId?: string;
|
tagID?: string;
|
||||||
searchKeyword?: string;
|
searchKeyword?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ onMounted(() => {
|
|||||||
loadResources();
|
loadResources();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => [props.categoryId, props.searchKeyword], () => {
|
watch(() => [props.tagID, props.searchKeyword], () => {
|
||||||
currentPage.value = 1;
|
currentPage.value = 1;
|
||||||
loadResources();
|
loadResources();
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
@@ -82,14 +82,14 @@ async function loadResources() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const filter: ResourceSearchParams = {
|
const filter: ResourceSearchParams = {
|
||||||
categoryID: props.categoryId,
|
tagID: props.tagID,
|
||||||
keyword: props.searchKeyword,
|
keyword: props.searchKeyword,
|
||||||
// status: 1 // 只加载已发布的
|
// status: 1 // 只加载已发布的
|
||||||
};
|
};
|
||||||
|
|
||||||
const pageParam: PageParam = {
|
const pageParam: PageParam = {
|
||||||
page: currentPage.value,
|
pageNumber: currentPage.value,
|
||||||
size: pageSize
|
pageSize: pageSize
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await resourceApi.getResourcePage(pageParam, filter);
|
const res = await resourceApi.getResourcePage(pageParam, filter);
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<div
|
<div
|
||||||
v-for="category in categories"
|
v-for="category in categories"
|
||||||
:key="category.categoryID"
|
:key="category.tagID || category.id"
|
||||||
class="sidebar-item"
|
class="sidebar-item"
|
||||||
:class="{ active: category.categoryID === activeCategoryId }"
|
:class="{ active: (category.tagID || category.id) === activeTagID }"
|
||||||
@click="handleCategoryClick(category)"
|
@click="handleCategoryClick(category)"
|
||||||
>
|
>
|
||||||
<span class="category-name">{{ category.name }}</span>
|
<span class="category-name">{{ category.name }}</span>
|
||||||
<div v-if="category.categoryID === activeCategoryId" class="active-overlay"></div>
|
<div v-if="(category.tagID || category.id) === activeTagID" class="active-overlay"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -17,22 +17,22 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import { resourceCategoryApi } from '@/apis/resource';
|
import { resourceTagApi } from '@/apis/resource';
|
||||||
import type { ResourceCategory } from '@/types/resource';
|
import type { Tag, TagType } from '@/types/resource';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
activeCategoryId?: string;
|
activeTagID?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
withDefaults(defineProps<Props>(), {
|
||||||
activeCategoryId: 'party_history'
|
activeTagID: 'party_history'
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
'category-change': [category: ResourceCategory];
|
'category-change': [category: Tag]; // 改为Tag类型
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const categories = ref<ResourceCategory[]>([]);
|
const categories = ref<Tag[]>([]); // 改为使用Tag类型(tagType=1表示文章分类)
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadCategories();
|
await loadCategories();
|
||||||
@@ -40,7 +40,8 @@ onMounted(async () => {
|
|||||||
|
|
||||||
async function loadCategories() {
|
async function loadCategories() {
|
||||||
try {
|
try {
|
||||||
const res = await resourceCategoryApi.getCategoryList();
|
// 使用新的标签API获取文章分类标签(tagType=1)
|
||||||
|
const res = await resourceTagApi.getTagsByType(1); // 1 = 文章分类标签
|
||||||
if (res.success && res.dataList) {
|
if (res.success && res.dataList) {
|
||||||
categories.value = res.dataList;
|
categories.value = res.dataList;
|
||||||
}
|
}
|
||||||
@@ -49,7 +50,7 @@ async function loadCategories() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCategoryClick(category: ResourceCategory) {
|
function handleCategoryClick(category: Tag) {
|
||||||
emit('category-change', category);
|
emit('category-change', category);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user