第 7 章:活动管理模块
"如果把系统比作一个舞台,那么'活动'就是舞台上的主角。"
本章我们将实现系统的核心业务------活动的创建、查看、编辑和删除(CRUD)。这不仅是数据库的增删改查,更涉及到状态流转和复杂的配置管理。
7.1 活动 CRUD 操作
所有的逻辑都在 server/activity/index.js 中实现。
7.1.1 创建活动 (Create)
管理员填写表单后,提交到后端。 关键逻辑:
- 默认值: 如果未指定封面,使用默认图;如果未指定时间,默认为当前时间。
- 初始化配置 : 创建时会生成默认的
registrationConfig(报名配置) 和voteConfig(投票配置) JSON 结构,避免后续读取时出现空指针。
javascript
// 默认的报名配置
const defaultRegConfig = {
displayMode: 'page',
fields: [] // 初始为空,由后续可视化编辑添加
}
7.1.2 查询列表 (Read)
支持分页、关键词搜索和状态筛选。 核心查询语句:
javascript
const filter = {
where: {
deleted: false, // 必须过滤软删除数据
$or: [
// 模糊搜索标题或描述
{ title: { $search: keyword } },
{ description: { $search: keyword } }
]
},
orderBy: [{ field: 'createdAt', direction: 'desc' }] // 最新创建的排前面
}
7.1.3 更新活动 (Update)
支持全量更新 和部分更新。
- 全量更新: 修改标题、时间等基础信息。
- 部分更新 : 专门用于更新
components(页面组件)、registrationConfig等大字段。因为这些字段通常由不同的编辑器页面独立保存,避免相互覆盖。
7.1.4 删除活动 (Delete)
这里的删除是逻辑删除 (Soft Delete)。
javascript
await models.activities.update({
filter: { _id: activityId },
data: { deleted: true, deletedAt: Date.now() }
})
7.2 活动状态管理
一个活动有三种基本状态:
- 已下架 (Inactive) :
isActive: false。只有管理员可见,普通用户无法访问。 - 未开始 (Not Started) :
isActive: true且now < startTime。用户可浏览详情,但无法报名/投票。 - 进行中 (Active) :
isActive: true且startTime <= now <= endTime。用户可正常参与。 - 已结束 (Ended) :
isActive: true且now > endTime。页面展示"活动已结束",禁用操作按钮。
前端展示逻辑:
typescript
const statusText = computed(() => {
if (!activity.isActive) return '已下架'
const now = Date.now()
if (now < activity.startTime) return '未开始'
if (now > activity.endTime) return '已结束'
return '进行中'
})
7.3 软删除与级联删除
当管理员狠心删除一个活动时,仅仅标记 activities 表是不够的。为了保持数据整洁,我们需要级联删除相关联的数据。
在 deleteActivity 云函数中:
- 标记活动为
deleted: true。 - 级联操作 :
- 查找所有关联的报名记录 (
registrations),标记为deleted: true。 - 查找所有关联的投票记录 (
votes),标记为deleted: true。 - 查找所有关联的弹幕 (
barrages),标记为deleted: true。
- 查找所有关联的报名记录 (
⚠️ 警告: 级联删除是危险操作。虽然我们可以恢复(把 deleted 改回 false),但在执行前最好在前端给管理员一个二次确认弹窗:"删除活动将同时删除所有报名和投票数据,确定吗?"
7.4 活动列表与详情页实现
列表页 (pages/activity/list)
使用原生 scroll-view 实现滚动加载。
- 分页逻辑 : 监听
onReachBottom事件,累加page参数请求下一页数据。 - 性能优化 : 列表项只展示封面、标题、时间,不加载庞大的
components和config字段,减少网络传输体积。
详情页 (pages/activity/detail)
这是用户访问最频繁的页面。
- 加载状态 : 简单的
uni.showLoading和v-if="loading"控制,数据返回前展示空白或 Loading 图标。 - 动态渲染 : 核心区域使用
<ActivityRenderer :components="activity.components" />组件,将后台配置的 JSON 渲染为真实的 UI(详见第 12 章)。 - 底部操作栏: 根据活动状态(报名中/投票中/已结束)动态显示"立即报名"或"参与投票"按钮。
本章小结 : 活动管理模块是系统的躯干。我们不仅实现了基础的增删改查,还处理了复杂的级联逻辑和状态流转。下一章,我们将聚焦于最实用的功能------那个能自动收集表单、还能收钱的报名系统。