根据需求开发:组件库系统开发完成

This commit is contained in:
lizhengwei 2026-03-06 22:59:51 +08:00
parent 0aed7d1295
commit e730c7745e
22 changed files with 1562 additions and 0 deletions

View 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());

View File

@ -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<>();
}
}

View File

@ -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);
}
}

View File

@ -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<>();
}
}

View File

@ -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);
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}