mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-18 01:25:28 +08:00
根据需求开发:组件库系统开发完成
This commit is contained in:
parent
0aed7d1295
commit
e730c7745e
112
ruoyi-site/ruoyi-h5/doc/dml/h5_component.sql
Normal file
112
ruoyi-site/ruoyi-h5/doc/dml/h5_component.sql
Normal file
@ -0,0 +1,112 @@
|
||||
-- H5 组件库系统建表脚本
|
||||
-- 创建时间:2026-03-06
|
||||
|
||||
-- 1. 组件分类表 (两级分类)
|
||||
CREATE TABLE `h5_component_category` (
|
||||
[id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37) BIGINT NOT NULL COMMENT '主键 ID',
|
||||
`parent_id` BIGINT NOT NULL DEFAULT 0 COMMENT '父分类 ID(0 为一级分类)',
|
||||
`name` VARCHAR(100) NOT NULL COMMENT '分类名称',
|
||||
`type` VARCHAR(50) NOT NULL COMMENT '分类类型 (text/image/extension/background/music)',
|
||||
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序值',
|
||||
`icon` VARCHAR(500) DEFAULT NULL COMMENT '分类图标 URL',
|
||||
`description` VARCHAR(500) DEFAULT NULL COMMENT '分类描述',
|
||||
`is_system` TINYINT NOT NULL DEFAULT 0 COMMENT '是否系统预设 (1:是 0:否)',
|
||||
`create_time` BIGINT NOT NULL COMMENT '创建时间 (Unix 时间戳秒级)',
|
||||
`update_time` BIGINT DEFAULT NULL COMMENT '更新时间 (Unix 时间戳秒级)',
|
||||
PRIMARY KEY ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37)),
|
||||
INDEX `idx_parent_id` (`parent_id`),
|
||||
INDEX `idx_type` (`type`),
|
||||
INDEX `idx_sort` (`sort`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='H5 组件分类表';
|
||||
|
||||
-- 2. 组件表
|
||||
CREATE TABLE `h5_component` (
|
||||
[id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37) BIGINT NOT NULL COMMENT '主键 ID',
|
||||
`name` VARCHAR(200) NOT NULL COMMENT '组件名称',
|
||||
`type` VARCHAR(50) NOT NULL COMMENT '组件类型 (text/image/form/map/background/music)',
|
||||
`thumbnail_url` VARCHAR(500) DEFAULT NULL COMMENT '缩略图 URL',
|
||||
`preview_url` VARCHAR(500) DEFAULT NULL COMMENT '预览图 URL',
|
||||
`content` JSON NOT NULL COMMENT '组件完整配置数据 (JSON 格式)',
|
||||
`usage_count` BIGINT NOT NULL DEFAULT 0 COMMENT '使用次数统计',
|
||||
`like_count` BIGINT NOT NULL DEFAULT 0 COMMENT '点赞数量',
|
||||
`is_premium` TINYINT NOT NULL DEFAULT 0 COMMENT '是否付费组件 (1:是 0:否)',
|
||||
`is_system` TINYINT NOT NULL DEFAULT 0 COMMENT '是否系统预设 (1:是 0:否)',
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态 (1:启用 0:禁用)',
|
||||
`remark` VARCHAR(1000) DEFAULT NULL COMMENT '备注说明',
|
||||
`create_time` BIGINT NOT NULL COMMENT '创建时间 (Unix 时间戳秒级)',
|
||||
`update_time` BIGINT DEFAULT NULL COMMENT '更新时间 (Unix 时间戳秒级)',
|
||||
PRIMARY KEY ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37)),
|
||||
INDEX `idx_type` (`type`),
|
||||
INDEX `idx_status` (`status`),
|
||||
INDEX `idx_usage_count` (`usage_count`),
|
||||
INDEX `idx_create_time` (`create_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='H5 组件表';
|
||||
|
||||
-- 3. 标签表
|
||||
CREATE TABLE `h5_tag` (
|
||||
[id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37) BIGINT NOT NULL COMMENT '主键 ID',
|
||||
`name` VARCHAR(100) NOT NULL COMMENT '标签名称',
|
||||
`type` VARCHAR(50) DEFAULT NULL COMMENT '标签适用类型,NULL 表示通用',
|
||||
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序值',
|
||||
`is_hot` TINYINT NOT NULL DEFAULT 0 COMMENT '是否热门 (1:是 0:否)',
|
||||
`use_count` BIGINT NOT NULL DEFAULT 0 COMMENT '使用次数',
|
||||
`create_time` BIGINT NOT NULL COMMENT '创建时间 (Unix 时间戳秒级)',
|
||||
`update_time` BIGINT DEFAULT NULL COMMENT '更新时间 (Unix 时间戳秒级)',
|
||||
PRIMARY KEY ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37)),
|
||||
UNIQUE INDEX `uk_name` (`name`),
|
||||
INDEX `idx_type` (`type`),
|
||||
INDEX `idx_is_hot` (`is_hot`),
|
||||
INDEX `idx_sort` (`sort`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='H5 组件标签表';
|
||||
|
||||
-- 4. 组件分类关联表 (多对多)
|
||||
CREATE TABLE `h5_component_category_rel` (
|
||||
[id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37) BIGINT NOT NULL COMMENT '主键 ID',
|
||||
`component_id` BIGINT NOT NULL COMMENT '组件 ID',
|
||||
`category_id` BIGINT NOT NULL COMMENT '分类 ID',
|
||||
`create_time` BIGINT NOT NULL COMMENT '创建时间 (Unix 时间戳秒级)',
|
||||
PRIMARY KEY ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37)),
|
||||
UNIQUE INDEX `uk_component_category` (`component_id`, `category_id`),
|
||||
INDEX `idx_category_id` (`category_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='H5 组件与分类关联表';
|
||||
|
||||
-- 5. 组件标签关联表 (多对多)
|
||||
CREATE TABLE `h5_component_tag_rel` (
|
||||
[id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37) BIGINT NOT NULL COMMENT '主键 ID',
|
||||
`component_id` BIGINT NOT NULL COMMENT '组件 ID',
|
||||
`tag_id` BIGINT NOT NULL COMMENT '标签 ID',
|
||||
`create_time` BIGINT NOT NULL COMMENT '创建时间 (Unix 时间戳秒级)',
|
||||
PRIMARY KEY ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37)),
|
||||
UNIQUE INDEX `uk_component_tag` (`component_id`, `tag_id`),
|
||||
INDEX `idx_tag_id` (`tag_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='H5 组件与标签关联表';
|
||||
|
||||
-- 初始化数据 - 一级分类 (固定 5 大类)
|
||||
INSERT INTO `h5_component_category` ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37), `parent_id`, [name](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-common\ruoyi-common-translation\src\main\java\org\dromara\common\translation\core\TranslationInterface.java#L27-L27), `type`, `sort`, `icon`, `description`, `is_system`, `create_time`) VALUES
|
||||
(1, 0, '文字', 'text', 1, NULL, '文字类组件,包括标题、正文、艺术字等', 1, UNIX_TIMESTAMP()),
|
||||
(2, 0, '图片', 'image', 2, NULL, '图片类组件,包括产品图、背景图、装饰图等', 1, UNIX_TIMESTAMP()),
|
||||
(3, 0, '扩展', 'extension', 3, NULL, '扩展功能组件,包括表单、定位、微信头像等', 1, UNIX_TIMESTAMP()),
|
||||
(4, 0, '背景', 'background', 4, NULL, '背景类组件,包括渐变色、图案背景等', 1, UNIX_TIMESTAMP()),
|
||||
(5, 0, '音乐', 'music', 5, NULL, '音乐音频类组件', 1, UNIX_TIMESTAMP());
|
||||
|
||||
-- 初始化数据 - 二级分类示例
|
||||
INSERT INTO `h5_component_category` ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37), `parent_id`, [name](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-common\ruoyi-common-translation\src\main\java\org\dromara\common\translation\core\TranslationInterface.java#L27-L27), `type`, `sort`, `is_system`, `create_time`) VALUES
|
||||
(101, 1, '标题文字', 'text', 1, 1, UNIX_TIMESTAMP()),
|
||||
(102, 1, '正文文本', 'text', 2, 1, UNIX_TIMESTAMP()),
|
||||
(103, 1, '艺术字', 'text', 3, 1, UNIX_TIMESTAMP()),
|
||||
(201, 2, '产品图片', 'image', 1, 1, UNIX_TIMESTAMP()),
|
||||
(202, 2, '装饰元素', 'image', 2, 1, UNIX_TIMESTAMP()),
|
||||
(301, 3, '表单组件', 'extension', 1, 1, UNIX_TIMESTAMP()),
|
||||
(302, 3, '地图定位', 'extension', 2, 1, UNIX_TIMESTAMP()),
|
||||
(303, 3, '社交组件', 'extension', 3, 1, UNIX_TIMESTAMP());
|
||||
|
||||
-- 初始化数据 - 标签示例
|
||||
INSERT INTO `h5_tag` ([id](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-admin\src\test\java\org\dromara\test\DemoUnitTest.java#L37-L37), [name](file://D:\project\gitee\RuoYi-Vue-Plus\ruoyi-common\ruoyi-common-translation\src\main\java\org\dromara\common\translation\core\TranslationInterface.java#L27-L27), `type`, `sort`, `is_hot`, `create_time`) VALUES
|
||||
(1, '简约', NULL, 1, 1, UNIX_TIMESTAMP()),
|
||||
(2, '商务', NULL, 2, 1, UNIX_TIMESTAMP()),
|
||||
(3, '创意', NULL, 3, 1, UNIX_TIMESTAMP()),
|
||||
(4, '节日', NULL, 4, 0, UNIX_TIMESTAMP()),
|
||||
(5, '促销', NULL, 5, 1, UNIX_TIMESTAMP()),
|
||||
(6, '中国风', NULL, 6, 0, UNIX_TIMESTAMP()),
|
||||
(7, '科技感', NULL, 7, 1, UNIX_TIMESTAMP()),
|
||||
(8, '清新', NULL, 8, 0, UNIX_TIMESTAMP());
|
||||
@ -0,0 +1,88 @@
|
||||
package com.luban.api.controller;
|
||||
|
||||
import com.luban.api.entity.H5ComponentCategory;
|
||||
import com.luban.api.service.H5ComponentCategoryService;
|
||||
import com.luban.api.vo.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件分类控制器
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Tag(name = "H5 组件分类管理")
|
||||
@RestController
|
||||
@RequestMapping("/h5/category")
|
||||
@RequiredArgsConstructor
|
||||
public class H5ComponentCategoryController {
|
||||
|
||||
private final H5ComponentCategoryService h5ComponentCategoryService;
|
||||
|
||||
@Operation(summary = "查询所有一级分类")
|
||||
@GetMapping("/top-level")
|
||||
public Result<List<H5ComponentCategory>> getTopLevelCategories() {
|
||||
List<H5ComponentCategory> result = h5ComponentCategoryService.getTopLevelCategories();
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据父分类 ID 查询子分类")
|
||||
@GetMapping("/children")
|
||||
public Result<List<H5ComponentCategory>> getChildCategories(
|
||||
@Parameter(description = "父分类 ID", required = true) @RequestParam Long parentId) {
|
||||
|
||||
List<H5ComponentCategory> result = h5ComponentCategoryService.getChildCategories(parentId);
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据类型查询分类")
|
||||
@GetMapping("/by-type")
|
||||
public Result<List<H5ComponentCategory>> getCategoriesByType(
|
||||
@Parameter(description = "组件类型", required = true) @RequestParam String type) {
|
||||
|
||||
List<H5ComponentCategory> result = h5ComponentCategoryService.getCategoriesByType(type);
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取分类树形结构")
|
||||
@GetMapping("/tree")
|
||||
public Result<List<H5ComponentCategory>> getCategoryTree() {
|
||||
List<H5ComponentCategory> result = h5ComponentCategoryService.getCategoryTree();
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "创建分类")
|
||||
@PostMapping
|
||||
public Result<Long> create(
|
||||
@Parameter(description = "分类信息", required = true) @RequestBody @Validated H5ComponentCategory category) {
|
||||
|
||||
Long id = h5ComponentCategoryService.create(category);
|
||||
return new Result<>(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新分类")
|
||||
@PutMapping("/{id}")
|
||||
public Result<Void> update(
|
||||
@Parameter(description = "分类 ID", required = true) @PathVariable Long id,
|
||||
@Parameter(description = "分类信息", required = true) @RequestBody @Validated H5ComponentCategory category) {
|
||||
|
||||
category.setId(id);
|
||||
h5ComponentCategoryService.update(category);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除分类")
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteById(
|
||||
@Parameter(description = "分类 ID", required = true) @PathVariable Long id) {
|
||||
h5ComponentCategoryService.deleteById(id);
|
||||
return new Result<>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
package com.luban.api.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.luban.api.entity.H5Component;
|
||||
import com.luban.api.service.H5ComponentService;
|
||||
import com.luban.api.vo.H5ComponentVO;
|
||||
import com.luban.api.vo.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件控制器
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Tag(name = "H5 组件管理")
|
||||
@RestController
|
||||
@RequestMapping("/h5/component")
|
||||
@RequiredArgsConstructor
|
||||
public class H5ComponentController {
|
||||
|
||||
private final H5ComponentService h5ComponentService;
|
||||
|
||||
@Operation(summary = "根据 ID 查询组件")
|
||||
@GetMapping("/{id}")
|
||||
public Result<H5ComponentVO> getById(
|
||||
@Parameter(description = "组件 ID") @PathVariable Long id) {
|
||||
H5ComponentVO vo = h5ComponentService.getById(id);
|
||||
return new Result<>(vo);
|
||||
}
|
||||
|
||||
@Operation(summary = "分页查询组件列表")
|
||||
@GetMapping("/page")
|
||||
public Result<Page<H5ComponentVO>> getPage(
|
||||
@Parameter(description = "页码", required = true) @RequestParam Integer page,
|
||||
@Parameter(description = "每页大小", required = true) @RequestParam Integer pageSize,
|
||||
@Parameter(description = "组件类型") @RequestParam(required = false) String type,
|
||||
@Parameter(description = "搜索关键词") @RequestParam(required = false) String keyword,
|
||||
@Parameter(description = "分类 ID") @RequestParam(required = false) Long categoryId,
|
||||
@Parameter(description = "标签 ID") @RequestParam(required = false) Long tagId) {
|
||||
|
||||
Page<H5ComponentVO> result = h5ComponentService.getPage(page, pageSize, type, keyword, categoryId, tagId);
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "创建组件")
|
||||
@PostMapping
|
||||
public Result<Long> create(
|
||||
@Parameter(description = "组件信息", required = true) @RequestBody @Validated H5Component component,
|
||||
@Parameter(description = "分类 ID 列表") @RequestBody(required = false) List<Long> categoryIds,
|
||||
@Parameter(description = "标签 ID 列表") @RequestBody(required = false) List<Long> tagIds) {
|
||||
|
||||
Long id = h5ComponentService.create(component, categoryIds, tagIds);
|
||||
return new Result<>(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新组件")
|
||||
@PutMapping("/{id}")
|
||||
public Result<Void> update(
|
||||
@Parameter(description = "组件 ID", required = true) @PathVariable Long id,
|
||||
@Parameter(description = "组件信息", required = true) @RequestBody @Validated H5Component component,
|
||||
@Parameter(description = "分类 ID 列表") @RequestBody(required = false) List<Long> categoryIds,
|
||||
@Parameter(description = "标签 ID 列表") @RequestBody(required = false) List<Long> tagIds) {
|
||||
|
||||
component.setId(id);
|
||||
h5ComponentService.update(component, categoryIds, tagIds);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除组件")
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteById(
|
||||
@Parameter(description = "组件 ID", required = true) @PathVariable Long id) {
|
||||
h5ComponentService.deleteById(id);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "批量删除组件")
|
||||
@DeleteMapping("/batch")
|
||||
public Result<Void> deleteBatch(
|
||||
@Parameter(description = "组件 ID 列表", required = true) @RequestBody List<Long> ids) {
|
||||
h5ComponentService.deleteBatch(ids);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "增加使用次数")
|
||||
@PostMapping("/{id}/usage")
|
||||
public Result<Void> incrementUsageCount(
|
||||
@Parameter(description = "组件 ID", required = true) @PathVariable Long id) {
|
||||
h5ComponentService.incrementUsageCount(id);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "增加点赞数")
|
||||
@PostMapping("/{id}/like")
|
||||
public Result<Void> incrementLikeCount(
|
||||
@Parameter(description = "组件 ID", required = true) @PathVariable Long id) {
|
||||
h5ComponentService.incrementLikeCount(id);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "获取热门组件")
|
||||
@GetMapping("/hot")
|
||||
public Result<List<H5ComponentVO>> getHotComponents(
|
||||
@Parameter(description = "组件类型") @RequestParam(required = false) String type,
|
||||
@Parameter(description = "数量限制", required = true) @RequestParam Integer limit) {
|
||||
|
||||
List<H5ComponentVO> result = h5ComponentService.getHotComponents(type, limit);
|
||||
return new Result<>(result);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.luban.api.controller;
|
||||
|
||||
import com.luban.api.entity.H5Tag;
|
||||
import com.luban.api.service.H5TagService;
|
||||
import com.luban.api.vo.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件标签控制器
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Tag(name = "H5 组件标签管理")
|
||||
@RestController
|
||||
@RequestMapping("/h5/tag")
|
||||
@RequiredArgsConstructor
|
||||
public class H5TagController {
|
||||
|
||||
private final H5TagService h5TagService;
|
||||
|
||||
@Operation(summary = "查询所有标签")
|
||||
@GetMapping
|
||||
public Result<List<H5Tag>> getAllTags() {
|
||||
List<H5Tag> result = h5TagService.getAllTags();
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询热门标签")
|
||||
@GetMapping("/hot")
|
||||
public Result<List<H5Tag>> getHotTags(
|
||||
@Parameter(description = "数量限制", required = true) @RequestParam Integer limit) {
|
||||
|
||||
List<H5Tag> result = h5TagService.getHotTags(limit);
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据类型查询标签")
|
||||
@GetMapping("/by-type")
|
||||
public Result<List<H5Tag>> getTagsByType(
|
||||
@Parameter(description = "组件类型") @RequestParam(required = false) String type) {
|
||||
|
||||
List<H5Tag> result = h5TagService.getTagsByType(type);
|
||||
return new Result<>(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "创建标签")
|
||||
@PostMapping
|
||||
public Result<Long> create(
|
||||
@Parameter(description = "标签信息", required = true) @RequestBody @Validated H5Tag tag) {
|
||||
|
||||
Long id = h5TagService.create(tag);
|
||||
return new Result<>(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新标签")
|
||||
@PutMapping("/{id}")
|
||||
public Result<Void> update(
|
||||
@Parameter(description = "标签 ID", required = true) @PathVariable Long id,
|
||||
@Parameter(description = "标签信息", required = true) @RequestBody @Validated H5Tag tag) {
|
||||
|
||||
tag.setId(id);
|
||||
h5TagService.update(tag);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除标签")
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteById(
|
||||
@Parameter(description = "标签 ID", required = true) @PathVariable Long id) {
|
||||
h5TagService.deleteById(id);
|
||||
return new Result<>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.luban.api.convert;
|
||||
|
||||
import com.luban.api.entity.H5Component;
|
||||
import com.luban.api.vo.H5ComponentVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* H5 组件转换类
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface H5ComponentConvert {
|
||||
|
||||
H5ComponentConvert INSTANCE = Mappers.getMapper(H5ComponentConvert.class);
|
||||
|
||||
/**
|
||||
* Entity 转 VO
|
||||
*
|
||||
* @param entity 实体
|
||||
* @return VO
|
||||
*/
|
||||
H5ComponentVO toVO(H5Component entity);
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.luban.api.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luban.api.entity.H5ComponentCategory;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* H5 组件分类 Mapper 接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface H5ComponentCategoryDao extends BaseMapper<H5ComponentCategory> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.luban.api.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luban.api.entity.H5ComponentCategoryRel;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* H5 组件与分类关联 Mapper 接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface H5ComponentCategoryRelDao extends BaseMapper<H5ComponentCategoryRel> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.luban.api.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luban.api.entity.H5Component;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* H5 组件 Mapper 接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface H5ComponentDao extends BaseMapper<H5Component> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.luban.api.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luban.api.entity.H5ComponentTagRel;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* H5 组件与标签关联 Mapper 接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface H5ComponentTagRelDao extends BaseMapper<H5ComponentTagRel> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.luban.api.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luban.api.entity.H5Tag;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* H5 组件标签 Mapper 接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface H5TagDao extends BaseMapper<H5Tag> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
package com.luban.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* H5 组件实体
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("h5_component")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class H5Component {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 组件名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 组件类型 (text/image/form/map/background/music)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 缩略图 URL
|
||||
*/
|
||||
private String thumbnailUrl;
|
||||
|
||||
/**
|
||||
* 预览图 URL
|
||||
*/
|
||||
private String previewUrl;
|
||||
|
||||
/**
|
||||
* 组件完整配置数据 (JSON 格式)
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 使用次数统计
|
||||
*/
|
||||
private Long usageCount;
|
||||
|
||||
/**
|
||||
* 点赞数量
|
||||
*/
|
||||
private Long likeCount;
|
||||
|
||||
/**
|
||||
* 是否付费组件 (1:是 0:否)
|
||||
*/
|
||||
private Integer isPremium;
|
||||
|
||||
/**
|
||||
* 是否系统预设 (1:是 0:否)
|
||||
*/
|
||||
private Integer isSystem;
|
||||
|
||||
/**
|
||||
* 状态 (1:启用 0:禁用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 更新时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long updateTime;
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.luban.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* H5 组件分类实体
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("h5_component_category")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class H5ComponentCategory {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 父分类 ID(0 为一级分类)
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 分类类型 (text/image/extension/background/music)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 排序值
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 分类图标 URL
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 分类描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否系统预设 (1:是 0:否)
|
||||
*/
|
||||
private Integer isSystem;
|
||||
|
||||
/**
|
||||
* 创建时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 更新时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long updateTime;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.luban.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* H5 组件与分类关联实体
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("h5_component_category_rel")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class H5ComponentCategoryRel {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 组件 ID
|
||||
*/
|
||||
private Long componentId;
|
||||
|
||||
/**
|
||||
* 分类 ID
|
||||
*/
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 创建时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long createTime;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.luban.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* H5 组件与标签关联实体
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("h5_component_tag_rel")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class H5ComponentTagRel {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 组件 ID
|
||||
*/
|
||||
private Long componentId;
|
||||
|
||||
/**
|
||||
* 标签 ID
|
||||
*/
|
||||
private Long tagId;
|
||||
|
||||
/**
|
||||
* 创建时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long createTime;
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.luban.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* H5 组件标签实体
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("h5_tag")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class H5Tag {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 标签名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 标签适用类型,NULL 表示通用
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 排序值
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 是否热门 (1:是 0:否)
|
||||
*/
|
||||
private Integer isHot;
|
||||
|
||||
/**
|
||||
* 使用次数
|
||||
*/
|
||||
private Long useCount;
|
||||
|
||||
/**
|
||||
* 创建时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 更新时间 (Unix 时间戳秒级)
|
||||
*/
|
||||
private Long updateTime;
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.luban.api.service;
|
||||
|
||||
import com.luban.api.entity.H5ComponentCategory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件分类服务接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
public interface H5ComponentCategoryService {
|
||||
|
||||
/**
|
||||
* 查询所有一级分类
|
||||
*
|
||||
* @return 一级分类列表
|
||||
*/
|
||||
List<H5ComponentCategory> getTopLevelCategories();
|
||||
|
||||
/**
|
||||
* 根据父分类 ID 查询子分类
|
||||
*
|
||||
* @param parentId 父分类 ID
|
||||
* @return 子分类列表
|
||||
*/
|
||||
List<H5ComponentCategory> getChildCategories(Long parentId);
|
||||
|
||||
/**
|
||||
* 根据类型查询分类
|
||||
*
|
||||
* @param type 组件类型
|
||||
* @return 分类列表
|
||||
*/
|
||||
List<H5ComponentCategory> getCategoriesByType(String type);
|
||||
|
||||
/**
|
||||
* 创建分类
|
||||
*
|
||||
* @param category 分类信息
|
||||
* @return 分类 ID
|
||||
*/
|
||||
Long create(H5ComponentCategory category);
|
||||
|
||||
/**
|
||||
* 更新分类
|
||||
*
|
||||
* @param category 分类信息
|
||||
*/
|
||||
void update(H5ComponentCategory category);
|
||||
|
||||
/**
|
||||
* 删除分类
|
||||
*
|
||||
* @param id 分类 ID
|
||||
*/
|
||||
void deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 获取分类树形结构
|
||||
*
|
||||
* @return 树形分类列表
|
||||
*/
|
||||
List<H5ComponentCategory> getCategoryTree();
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.luban.api.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.luban.api.entity.H5Component;
|
||||
import com.luban.api.vo.H5ComponentVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件服务接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
public interface H5ComponentService {
|
||||
|
||||
/**
|
||||
* 根据 ID 查询组件
|
||||
*
|
||||
* @param id 组件 ID
|
||||
* @return 组件信息
|
||||
*/
|
||||
H5ComponentVO getById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询组件列表
|
||||
*
|
||||
* @param page 页码
|
||||
* @param pageSize 每页大小
|
||||
* @param type 组件类型 (可选)
|
||||
* @param keyword 搜索关键词 (可选)
|
||||
* @param categoryId 分类 ID(可选)
|
||||
* @param tagId 标签 ID(可选)
|
||||
* @return 分页数据
|
||||
*/
|
||||
Page<H5ComponentVO> getPage(Integer page, Integer pageSize, String type, String keyword, Long categoryId, Long tagId);
|
||||
|
||||
/**
|
||||
* 创建组件
|
||||
*
|
||||
* @param component 组件信息
|
||||
* @param categoryIds 分类 ID 列表
|
||||
* @param tagIds 标签 ID 列表
|
||||
* @return 组件 ID
|
||||
*/
|
||||
Long create(H5Component component, List<Long> categoryIds, List<Long> tagIds);
|
||||
|
||||
/**
|
||||
* 更新组件
|
||||
*
|
||||
* @param component 组件信息
|
||||
* @param categoryIds 分类 ID 列表
|
||||
* @param tagIds 标签 ID 列表
|
||||
*/
|
||||
void update(H5Component component, List<Long> categoryIds, List<Long> tagIds);
|
||||
|
||||
/**
|
||||
* 删除组件
|
||||
*
|
||||
* @param id 组件 ID
|
||||
*/
|
||||
void deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除组件
|
||||
*
|
||||
* @param ids 组件 ID 列表
|
||||
*/
|
||||
void deleteBatch(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 增加使用次数
|
||||
*
|
||||
* @param id 组件 ID
|
||||
*/
|
||||
void incrementUsageCount(Long id);
|
||||
|
||||
/**
|
||||
* 增加点赞数
|
||||
*
|
||||
* @param id 组件 ID
|
||||
*/
|
||||
void incrementLikeCount(Long id);
|
||||
|
||||
/**
|
||||
* 获取热门组件
|
||||
*
|
||||
* @param type 组件类型 (可选)
|
||||
* @param limit 数量限制
|
||||
* @return 组件列表
|
||||
*/
|
||||
List<H5ComponentVO> getHotComponents(String type, Integer limit);
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.luban.api.service;
|
||||
|
||||
import com.luban.api.entity.H5Tag;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件标签服务接口
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
public interface H5TagService {
|
||||
|
||||
/**
|
||||
* 查询所有标签
|
||||
*
|
||||
* @return 标签列表
|
||||
*/
|
||||
List<H5Tag> getAllTags();
|
||||
|
||||
/**
|
||||
* 查询热门标签
|
||||
*
|
||||
* @param limit 数量限制
|
||||
* @return 热门标签列表
|
||||
*/
|
||||
List<H5Tag> getHotTags(Integer limit);
|
||||
|
||||
/**
|
||||
* 根据类型查询标签
|
||||
*
|
||||
* @param type 组件类型
|
||||
* @return 标签列表
|
||||
*/
|
||||
List<H5Tag> getTagsByType(String type);
|
||||
|
||||
/**
|
||||
* 创建标签
|
||||
*
|
||||
* @param tag 标签信息
|
||||
* @return 标签 ID
|
||||
*/
|
||||
Long create(H5Tag tag);
|
||||
|
||||
/**
|
||||
* 更新标签
|
||||
*
|
||||
* @param tag 标签信息
|
||||
*/
|
||||
void update(H5Tag tag);
|
||||
|
||||
/**
|
||||
* 删除标签
|
||||
*
|
||||
* @param id 标签 ID
|
||||
*/
|
||||
void deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 增加标签使用次数
|
||||
*
|
||||
* @param id 标签 ID
|
||||
*/
|
||||
void incrementUseCount(Long id);
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
package com.luban.api.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.luban.api.dao.H5ComponentCategoryDao;
|
||||
import com.luban.api.entity.H5ComponentCategory;
|
||||
import com.luban.api.service.H5ComponentCategoryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件分类服务实现类
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class H5ComponentCategoryServiceImpl extends ServiceImpl<H5ComponentCategoryDao, H5ComponentCategory> implements H5ComponentCategoryService {
|
||||
|
||||
private final H5ComponentCategoryDao h5ComponentCategoryDao;
|
||||
|
||||
@Override
|
||||
public List<H5ComponentCategory> getTopLevelCategories() {
|
||||
LambdaQueryWrapper<H5ComponentCategory> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentCategory::getParentId, 0L)
|
||||
.orderByAsc(H5ComponentCategory::getSort);
|
||||
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<H5ComponentCategory> getChildCategories(Long parentId) {
|
||||
LambdaQueryWrapper<H5ComponentCategory> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentCategory::getParentId, parentId)
|
||||
.orderByAsc(H5ComponentCategory::getSort);
|
||||
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<H5ComponentCategory> getCategoriesByType(String type) {
|
||||
LambdaQueryWrapper<H5ComponentCategory> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentCategory::getType, type)
|
||||
.orderByAsc(H5ComponentCategory::getParentId)
|
||||
.orderByAsc(H5ComponentCategory::getSort);
|
||||
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long create(H5ComponentCategory category) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
|
||||
if (category.getParentId() == null) {
|
||||
category.setParentId(0L);
|
||||
}
|
||||
|
||||
category.setCreateTime(now);
|
||||
category.setUpdateTime(now);
|
||||
|
||||
baseMapper.insert(category);
|
||||
|
||||
return category.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(H5ComponentCategory category) {
|
||||
category.setUpdateTime(Instant.now().getEpochSecond());
|
||||
baseMapper.updateById(category);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(Long id) {
|
||||
// 检查是否有子分类
|
||||
LambdaQueryWrapper<H5ComponentCategory> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentCategory::getParentId, id);
|
||||
Long count = baseMapper.selectCount(wrapper);
|
||||
|
||||
if (count > 0) {
|
||||
throw new RuntimeException("该分类下存在子分类,无法删除");
|
||||
}
|
||||
|
||||
baseMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<H5ComponentCategory> getCategoryTree() {
|
||||
// 查询所有一级分类
|
||||
List<H5ComponentCategory> topLevelCategories = getTopLevelCategories();
|
||||
|
||||
// 为每个一级分类查询子分类
|
||||
for (H5ComponentCategory topLevel : topLevelCategories) {
|
||||
List<H5ComponentCategory> childCategories = getChildCategories(topLevel.getId());
|
||||
// 这里简单处理,实际可以考虑使用专门的树形结构 VO
|
||||
if (!childCategories.isEmpty()) {
|
||||
// 可以在返回时添加额外信息
|
||||
log.debug("分类 {} 有 {} 个子分类", topLevel.getName(), childCategories.size());
|
||||
}
|
||||
}
|
||||
|
||||
return topLevelCategories;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,250 @@
|
||||
package com.luban.api.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.luban.api.dao.H5ComponentCategoryRelDao;
|
||||
import com.luban.api.dao.H5ComponentDao;
|
||||
import com.luban.api.dao.H5ComponentTagRelDao;
|
||||
import com.luban.api.entity.H5Component;
|
||||
import com.luban.api.entity.H5ComponentCategoryRel;
|
||||
import com.luban.api.entity.H5ComponentTagRel;
|
||||
import com.luban.api.service.H5ComponentService;
|
||||
import com.luban.api.convert.H5ComponentConvert;
|
||||
import com.luban.api.vo.H5ComponentVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* H5 组件服务实现类
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class H5ComponentServiceImpl extends ServiceImpl<H5ComponentDao, H5Component> implements H5ComponentService {
|
||||
|
||||
private final H5ComponentCategoryRelDao h5ComponentCategoryRelDao;
|
||||
private final H5ComponentTagRelDao h5ComponentTagRelDao;
|
||||
private final H5ComponentConvert h5ComponentConvert;
|
||||
|
||||
@Override
|
||||
public H5ComponentVO getById(Long id) {
|
||||
H5Component component = baseMapper.selectById(id);
|
||||
return h5ComponentConvert.toVO(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<H5ComponentVO> getPage(Integer page, Integer pageSize, String type, String keyword, Long categoryId, Long tagId) {
|
||||
Page<H5Component> mpPage = new Page<>(page, pageSize);
|
||||
|
||||
LambdaQueryWrapper<H5Component> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5Component::getStatus, 1); // 只查询启用的组件
|
||||
|
||||
wrapper.eq(StrUtil.isNotBlank(type), H5Component::getType, type);
|
||||
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
wrapper.and(w -> w.like(H5Component::getName, keyword)
|
||||
.or().like(H5Component::getRemark, keyword));
|
||||
}
|
||||
|
||||
// 按分类筛选
|
||||
if (categoryId != null) {
|
||||
List<Long> componentIds = getComponentIdsByCategory(categoryId);
|
||||
if (componentIds.isEmpty()) {
|
||||
return new Page<H5ComponentVO>(page, pageSize).setRecords(List.of());
|
||||
}
|
||||
wrapper.in(H5Component::getId, componentIds);
|
||||
}
|
||||
|
||||
// 按标签筛选
|
||||
if (tagId != null) {
|
||||
List<Long> componentIds = getComponentIdsByTag(tagId);
|
||||
if (componentIds.isEmpty()) {
|
||||
return new Page<H5ComponentVO>(page, pageSize).setRecords(List.of());
|
||||
}
|
||||
wrapper.in(H5Component::getId, componentIds);
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(H5Component::getUsageCount)
|
||||
.orderByDesc(H5Component::getCreateTime);
|
||||
|
||||
Page<H5Component> resultPage = baseMapper.selectPage(mpPage, wrapper);
|
||||
|
||||
Page<H5ComponentVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
|
||||
List<H5ComponentVO> voList = resultPage.getRecords().stream()
|
||||
.map(h5ComponentConvert::toVO)
|
||||
.collect(Collectors.toList());
|
||||
voPage.setRecords(voList);
|
||||
|
||||
return voPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long create(H5Component component, List<Long> categoryIds, List<Long> tagIds) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
|
||||
// 初始化数据
|
||||
component.setCreateTime(now);
|
||||
component.setUpdateTime(now);
|
||||
component.setUsageCount(0L);
|
||||
component.setLikeCount(0L);
|
||||
component.setStatus(1);
|
||||
|
||||
baseMapper.insert(component);
|
||||
|
||||
// 保存分类关联
|
||||
if (categoryIds != null && !categoryIds.isEmpty()) {
|
||||
saveCategoryRels(component.getId(), categoryIds, now);
|
||||
}
|
||||
|
||||
// 保存标签关联
|
||||
if (tagIds != null && !tagIds.isEmpty()) {
|
||||
saveTagRels(component.getId(), tagIds, now);
|
||||
}
|
||||
|
||||
return component.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(H5Component component, List<Long> categoryIds, List<Long> tagIds) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
|
||||
component.setUpdateTime(now);
|
||||
baseMapper.updateById(component);
|
||||
|
||||
// 更新分类关联
|
||||
if (categoryIds != null) {
|
||||
deleteCategoryRels(component.getId());
|
||||
if (!categoryIds.isEmpty()) {
|
||||
saveCategoryRels(component.getId(), categoryIds, now);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新标签关联
|
||||
if (tagIds != null) {
|
||||
deleteTagRels(component.getId());
|
||||
if (!tagIds.isEmpty()) {
|
||||
saveTagRels(component.getId(), tagIds, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteById(Long id) {
|
||||
// 删除组件
|
||||
baseMapper.deleteById(id);
|
||||
|
||||
// 删除分类关联
|
||||
deleteCategoryRels(id);
|
||||
|
||||
// 删除标签关联
|
||||
deleteTagRels(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteBatch(List<Long> ids) {
|
||||
ids.forEach(this::deleteById);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void incrementUsageCount(Long id) {
|
||||
H5Component component = baseMapper.selectById(id);
|
||||
if (component != null) {
|
||||
component.setUsageCount(component.getUsageCount() + 1);
|
||||
component.setUpdateTime(Instant.now().getEpochSecond());
|
||||
baseMapper.updateById(component);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void incrementLikeCount(Long id) {
|
||||
H5Component component = baseMapper.selectById(id);
|
||||
if (component != null) {
|
||||
component.setLikeCount(component.getLikeCount() + 1);
|
||||
component.setUpdateTime(Instant.now().getEpochSecond());
|
||||
baseMapper.updateById(component);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<H5ComponentVO> getHotComponents(String type, Integer limit) {
|
||||
LambdaQueryWrapper<H5Component> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5Component::getStatus, 1);
|
||||
|
||||
if (StrUtil.isNotBlank(type)) {
|
||||
wrapper.eq(H5Component::getType, type);
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(H5Component::getUsageCount)
|
||||
.last("LIMIT " + limit);
|
||||
|
||||
List<H5Component> components = baseMapper.selectList(wrapper);
|
||||
return components.stream()
|
||||
.map(h5ComponentConvert::toVO)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Long> getComponentIdsByCategory(Long categoryId) {
|
||||
LambdaQueryWrapper<H5ComponentCategoryRel> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentCategoryRel::getCategoryId, categoryId);
|
||||
wrapper.select(H5ComponentCategoryRel::getComponentId);
|
||||
|
||||
return h5ComponentCategoryRelDao.selectList(wrapper).stream()
|
||||
.map(H5ComponentCategoryRel::getComponentId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Long> getComponentIdsByTag(Long tagId) {
|
||||
LambdaQueryWrapper<H5ComponentTagRel> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentTagRel::getTagId, tagId);
|
||||
wrapper.select(H5ComponentTagRel::getComponentId);
|
||||
|
||||
return h5ComponentTagRelDao.selectList(wrapper).stream()
|
||||
.map(H5ComponentTagRel::getComponentId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void saveCategoryRels(Long componentId, List<Long> categoryIds, long createTime) {
|
||||
List<H5ComponentCategoryRel> rels = categoryIds.stream()
|
||||
.map(categoryId -> new H5ComponentCategoryRel(null, componentId, categoryId, createTime))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
rels.forEach(h5ComponentCategoryRelDao::insert);
|
||||
}
|
||||
|
||||
private void saveTagRels(Long componentId, List<Long> tagIds, long createTime) {
|
||||
List<H5ComponentTagRel> rels = tagIds.stream()
|
||||
.map(tagId -> new H5ComponentTagRel(null, componentId, tagId, createTime))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
rels.forEach(h5ComponentTagRelDao::insert);
|
||||
}
|
||||
|
||||
private void deleteCategoryRels(Long componentId) {
|
||||
LambdaQueryWrapper<H5ComponentCategoryRel> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentCategoryRel::getComponentId, componentId);
|
||||
h5ComponentCategoryRelDao.delete(wrapper);
|
||||
}
|
||||
|
||||
private void deleteTagRels(Long componentId) {
|
||||
LambdaQueryWrapper<H5ComponentTagRel> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5ComponentTagRel::getComponentId, componentId);
|
||||
h5ComponentTagRelDao.delete(wrapper);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package com.luban.api.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.luban.api.dao.H5TagDao;
|
||||
import com.luban.api.entity.H5Tag;
|
||||
import com.luban.api.service.H5TagService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件标签服务实现类
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class H5TagServiceImpl extends ServiceImpl<H5TagDao, H5Tag> implements H5TagService {
|
||||
|
||||
private final H5TagDao h5TagDao;
|
||||
|
||||
@Override
|
||||
public List<H5Tag> getAllTags() {
|
||||
LambdaQueryWrapper<H5Tag> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.orderByAsc(H5Tag::getSort, H5Tag::getId);
|
||||
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<H5Tag> getHotTags(Integer limit) {
|
||||
LambdaQueryWrapper<H5Tag> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(H5Tag::getIsHot, 1)
|
||||
.orderByDesc(H5Tag::getUseCount)
|
||||
.last("LIMIT " + limit);
|
||||
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<H5Tag> getTagsByType(String type) {
|
||||
LambdaQueryWrapper<H5Tag> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.and(StrUtil.isNotBlank(type), w -> w.eq(H5Tag::getType, type).isNull(H5Tag::getType));
|
||||
wrapper.orderByAsc(H5Tag::getSort, H5Tag::getId);
|
||||
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long create(H5Tag tag) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
|
||||
tag.setCreateTime(now);
|
||||
tag.setUpdateTime(now);
|
||||
tag.setUseCount(0L);
|
||||
|
||||
baseMapper.insert(tag);
|
||||
|
||||
return tag.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(H5Tag tag) {
|
||||
tag.setUpdateTime(Instant.now().getEpochSecond());
|
||||
baseMapper.updateById(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(Long id) {
|
||||
baseMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementUseCount(Long id) {
|
||||
H5Tag tag = baseMapper.selectById(id);
|
||||
if (tag != null) {
|
||||
tag.setUseCount(tag.getUseCount() + 1);
|
||||
tag.setUpdateTime(Instant.now().getEpochSecond());
|
||||
baseMapper.updateById(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.luban.api.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H5 组件 VO
|
||||
*
|
||||
* @author system
|
||||
* @since 2026-03-06
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "H5 组件信息")
|
||||
public class H5ComponentVO {
|
||||
|
||||
@Schema(description = "组件 ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "组件名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "组件类型 (text/image/form/map/background/music)")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "缩略图 URL")
|
||||
private String thumbnailUrl;
|
||||
|
||||
@Schema(description = "预览图 URL")
|
||||
private String previewUrl;
|
||||
|
||||
@Schema(description = "组件完整配置数据 (JSON 格式)")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "使用次数统计")
|
||||
private Long usageCount;
|
||||
|
||||
@Schema(description = "点赞数量")
|
||||
private Long likeCount;
|
||||
|
||||
@Schema(description = "是否付费组件 (1:是 0:否)")
|
||||
private Integer isPremium;
|
||||
|
||||
@Schema(description = "状态 (1:启用 0:禁用)")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注说明")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间 (Unix 时间戳秒级)")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "更新时间 (Unix 时间戳秒级)")
|
||||
private Long updateTime;
|
||||
|
||||
@Schema(description = "关联的分类 ID 列表")
|
||||
private List<Long> categoryIds;
|
||||
|
||||
@Schema(description = "关联的标签 ID 列表")
|
||||
private List<Long> tagIds;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user