文章目录
Softhub软件下载站实战开发(五):分类模块实现 💻🌳
本文我们将深入探讨Softhub软件下载站的分类模块设计与实现,这是构建软件下载站的核心功能之一。分类模块负责将海量软件进行有序组织,为用户提供清晰的浏览体验。
一、功能需求分析 🎯
分类模块需要满足以下核心需求:
- 分类管理:支持添加、编辑、删除软件分类
- 树形结构:支持两级分类(父/子分类)
- 分类关联:每个软件必须属于一个分类
- 数据验证:删除分类前需确保分类下无软件
- 图标支持:为每个分类设置个性化图标,基于fortawesome图标库
二、数据库设计 🗃️
分类表 ds_category
结构设计:
字段 | 类型 | 描述 | 约束 |
---|---|---|---|
id | int(11) | 主键ID | PRIMARY KEY |
parent_id | int(11) | 父分类ID | DEFAULT 0 |
category_name | varchar(50) | 分类名称 | NOT NULL |
icon | varchar(100) | 分类图标 | |
sort | int(11) | 排序 | NOT NULL |
remark | varchar(255) | 备注 | |
created_by | int(11) | 创建人 | NOT NULL |
updated_by | int(11) | 更新人 | NOT NULL |
created_at | datetime | 创建时间 | NOT NULL |
updated_at | datetime | 更新时间 | NOT NULL |
三、后端实现 🚀
1. 核心逻辑设计
2. 关键接口实现
添加分类逻辑:
func (s sDsCategory) Add(ctx context.Context, req *api.DsCategoryAddReq) error {
// 检查分类名称是否已存在
var category *model.DsCategoryInfo
dao.DsCategory.Ctx(ctx).Where(dao.DsCategory.Columns().CategoryName, req.CategoryName).Scan(&category)
if category != nil {
return fmt.Errorf("分类%s已经存在", category.CategoryName)
}
// 检查父分类是否存在
if req.ParentId != 0 {
var parentCategory *model.DsCategoryInfo
dao.DsCategory.Ctx(ctx).Where(dao.DsCategory.Columns().Id, req.ParentId).Scan(&parentCategory)
if parentCategory == nil {
return fmt.Errorf("父级分类不存在")
}
if parentCategory.ParentId != 0 {
return fmt.Errorf("只能在顶级分类下添加子分类")
}
}
// 插入新分类
_, err := dao.DsCategory.Ctx(ctx).Insert(do.DsCategory{
ParentId: req.ParentId,
CategoryName: req.CategoryName,
Icon: req.Icon,
Sort: req.Sort,
Remark: req.Remark,
CreatedBy: SystemS.Context().GetUserId(ctx),
UpdatedBy: SystemS.Context().GetUserId(ctx),
})
return err
}
删除分类逻辑:
func (s sDsCategory) Delete(ctx context.Context, id uint) error {
// 检查分类下是否有软件
var software *model.DsSoftwareInfo
dao.DsSoftware.Ctx(ctx).Where(dao.DsSoftware.Columns().CategoryId+" = ?", id).Limit(1).Scan(&software)
if software != nil {
return fmt.Errorf("该分类下有软件,无法删除")
}
// 执行删除
_, err := dao.DsCategory.Ctx(ctx).WherePri(id).Delete()
return err
}
四、前端实现 🖥️
1. 树形表格展示
<el-table
:data="tableData.data"
row-key="id"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
<el-table-column prop="categoryName" label="分类名称" />
<el-table-column label="图标">
<template #default="scope">
<font-awesome-icon v-if="scope.row.icon" :icon="getIconObject(scope.row.icon)" />
</template>
</el-table-column>
<el-table-column label="操作" width="240">
<template #default="scope">
<el-button
size="small"
text
type="success"
:disabled="!!scope.row.parentId"
@click="onOpenAddChildCategory(scope.row)">
新增子分类
</el-button>
<el-button
size="small"
text
type="primary"
@click="onOpenEditDsCategory(scope.row)">
修改
</el-button>
<el-button
size="small"
text
type="danger"
@click="onRowDel(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
2. 图标选择器组件
参考Vue3 + Element Plus 实现强大的图标选择器组件
<el-form-item label="图标" prop="icon">
<fs-icon-selector v-model="formData.icon" />
</el-form-item>
3. 添加/编辑分类对话框
<el-dialog v-model="isShowDialog">
<el-form :model="formData" label-width="90px">
<el-form-item label="上级分类" prop="parentId">
<el-select v-model="formData.parentId" placeholder="请选择上级分类">
<el-option
v-for="item in categoryTree"
:key="item.id"
:label="item.categoryName"
:value="item.id"
:disabled="item.id === formData.id" />
</el-select>
</el-form-item>
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="formData.categoryName" />
</el-form-item>
<el-form-item label="图标" prop="icon">
<fs-icon-selector v-model="formData.icon" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" />
</el-form-item>
</el-form>
</el-dialog>
五、实现效果展示 ✨
图1:分类管理页面 - 树形展示分类结构
图2:添加分类对话框 - 支持图标选择和父分类选择
六、关键问题解决 🛠️
-
树形结构性能优化:
- 后端一次性获取所有分类数据
- 前端使用递归算法构建树形结构
-
图标选择器实现:
- 集成Font Awesome图标库
- 实现图标搜索和分类功能
- 支持三种风格图标(solid/regular/brands)
七、总结 📝
本文详细介绍了Softhub软件下载站分类模块的设计与实现,包括:
- 设计合理的数据库结构存储分类信息
- 实现后端分类管理的核心逻辑
- 开发前端树形分类展示界面
- 实现分类的增删改查功能
softhub系列往期文章