Skip to content

开发资产:校园后勤服务平台

← 上一阶段:方案设计 | 下一阶段:系统落地 →


概述

在开发这个场景的过程中,我们沉淀了以下可复用的开发资产:

  1. Cursor Skill - 教室预约冲突检测规则
  2. PROMPT 模板 - 多级审批流程生成
  3. 实施指南 - 如何快速复现这个场景

这些资产可以帮助快速复用这个场景的开发经验。


1. Cursor Skill:教室预约冲突检测规则

使用场景

当你需要开发类似的"资源预约/预订"场景时,可以使用这个 Skill 让 AI 理解业务规则。

Skill 内容

markdown
# 资源预约冲突检测规则

## 业务场景
教室、会议室、设备等资源的预约管理,需要检测时间冲突,防止重复预约。

## 核心业务规则

### 1. 冲突检测规则

**规则一:时间重叠检测**
```typescript
// 检查两个时间段是否重叠
function isTimeOverlap(
  start1: Date,
  end1: Date,
  start2: Date,
  end2: Date
): boolean {
  // 时间段1的开始时间在时间段2内
  if (start1 >= start2 && start1 < end2) return true;
  
  // 时间段1的结束时间在时间段2内
  if (end1 > start2 && end1 <= end2) return true;
  
  // 时间段1完全包含时间段2
  if (start1 <= start2 && end1 >= end2) return true;
  
  // 时间段2完全包含时间段1
  if (start2 <= start1 && end2 >= end1) return true;
  
  return false;
}

规则二:时间间隔检测

typescript
// 检查前后预约之间是否有足够的时间间隔(用于打扫等)
function hasEnoughInterval(
  previousEnd: Date,
  nextStart: Date,
  minInterval: number = 10 // 最小间隔(分钟)
): boolean {
  const interval = (nextStart.getTime() - previousEnd.getTime()) / (1000 * 60);
  return interval >= minInterval;
}

规则三:冲突检测主函数

typescript
async function checkConflict(
  resourceId: string,
  startTime: Date,
  endTime: Date,
  excludeReservationId?: string // 排除当前预约(用于修改场景)
): Promise<ConflictResult> {
  // 1. 获取该资源的所有预约
  const reservations = await getReservations({
    resourceId,
    status: ['reserved', 'in-use'],
    excludeId: excludeReservationId
  });
  
  // 2. 检查时间重叠
  const timeConflicts = reservations.filter(reservation => 
    isTimeOverlap(
      startTime,
      endTime,
      reservation.startTime,
      reservation.endTime
    )
  );
  
  // 3. 检查时间间隔
  const intervalConflicts = [];
  
  // 检查与前一个预约的间隔
  const previousReservation = reservations
    .filter(r => r.endTime <= startTime)
    .sort((a, b) => b.endTime.getTime() - a.endTime.getTime())[0];
  
  if (previousReservation && !hasEnoughInterval(
    previousReservation.endTime,
    startTime
  )) {
    intervalConflicts.push({
      type: 'BEFORE',
      reservation: previousReservation,
      requiredInterval: 10
    });
  }
  
  // 检查与后一个预约的间隔
  const nextReservation = reservations
    .filter(r => r.startTime >= endTime)
    .sort((a, b) => a.startTime.getTime() - b.startTime.getTime())[0];
  
  if (nextReservation && !hasEnoughInterval(
    endTime,
    nextReservation.startTime
  )) {
    intervalConflicts.push({
      type: 'AFTER',
      reservation: nextReservation,
      requiredInterval: 10
    });
  }
  
  // 4. 返回冲突结果
  return {
    hasConflict: timeConflicts.length > 0 || intervalConflicts.length > 0,
    timeConflicts,
    intervalConflicts,
    canReserve: timeConflicts.length === 0 && intervalConflicts.length === 0
  };
}

2. 预约限制规则

规则一:每人每天预约次数限制

typescript
async function checkDailyLimit(
  userId: string,
  date: Date
): Promise<boolean> {
  const todayReservations = await getReservations({
    userId,
    date: date,
    status: ['reserved', 'in-use']
  });
  
  const maxDailyReservations = 2; // 每人每天最多2次
  return todayReservations.length < maxDailyReservations;
}

规则二:单次预约时长限制

typescript
function checkDurationLimit(
  startTime: Date,
  endTime: Date
): boolean {
  const duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60 * 60); // 小时
  const maxDuration = 4; // 最多4小时
  return duration <= maxDuration;
}

规则三:提前预约时间限制

typescript
function checkAdvanceBookingLimit(
  startTime: Date
): boolean {
  const now = new Date();
  const daysInAdvance = (startTime.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
  const maxDaysInAdvance = 7; // 最多提前7天
  return daysInAdvance <= maxDaysInAdvance && daysInAdvance >= 0;
}

3. 自动释放规则

规则一:超时未签到自动释放

typescript
async function autoReleaseTimeoutReservations() {
  const now = new Date();
  
  // 查找超时未签到的预约
  const timeoutReservations = await getReservations({
    status: 'reserved',
    startTime: { $lte: new Date(now.getTime() - 30 * 60 * 1000) } // 开始时间已过30分钟
  });
  
  for (const reservation of timeoutReservations) {
    // 检查是否已签到
    if (!reservation.checkInTime) {
      // 自动释放
      await updateReservation(reservation.id, {
        status: 'cancelled',
        cancelReason: '超时未签到自动释放'
      });
      
      // 通知申请人
      await notifyUser(reservation.userId, {
        type: 'RESERVATION_AUTO_RELEASED',
        reservationId: reservation.id
      });
    }
  }
}

数据模型

预约(Reservation)

typescript
interface Reservation {
  id: string;
  resourceId: string;        // 资源ID(教室/会议室)
  resourceName: string;       // 资源名称
  userId: string;             // 申请人ID
  userName: string;           // 申请人姓名
  startTime: Date;            // 开始时间
  endTime: Date;              // 结束时间
  purpose: string;           // 使用目的
  needApproval: boolean;      // 是否需要审批
  approvalStatus?: 'pending' | 'approved' | 'rejected';
  checkInTime?: Date;         // 签到时间
  checkOutTime?: Date;        // 签退时间
  status: 'reserved' | 'in-use' | 'completed' | 'cancelled';
  createdAt: Date;
  updatedAt: Date;
}

开发注意事项

  1. 时区处理:所有时间使用 UTC 或统一时区,避免时区问题
  2. 并发控制:预约时使用数据库锁或乐观锁,防止并发冲突
  3. 定时任务:需要定时任务检查超时预约并自动释放
  4. 通知机制:预约成功、冲突、超时等都需要及时通知用户

相似场景复用

这个规则可以复用到:

  • 会议室预约:企业会议室预约
  • 设备预约:实验室设备、教学设备预约
  • 场地预约:运动场地、活动场地预约
  • 车辆预约:公车、校车预约

### 如何使用这个 Skill

**步骤 1:保存为文件**

将上述内容保存为 `.cursorrules` 文件或在项目中创建 `docs/business-rules/resource-booking.md`

**步骤 2:在 Cursor 中引用**

在开发预约功能时,告诉 AI: "参考 resource-booking.md 中的业务规则, 实现资源预约冲突检测逻辑"


**步骤 3:AI 会理解并生成代码**

AI 会基于这个规则生成准确的冲突检测逻辑、预约限制等。

---

## 2. PROMPT 模板:多级审批流程生成

### 使用场景

当需要快速生成类似的"多级审批"代码时,使用这个 PROMPT 模板。

### PROMPT 模板

```text
你是一个业务逻辑开发专家。请根据以下业务规则,生成完整的多级审批流程代码。

## 业务场景
[描述你的具体场景,例如:物资申请多级审批]

## 审批流程定义
[描述审批流程,例如:
1. 普通物资:无需审批,自动批准
2. 贵重物资:需要辅导员审批
3. 高价值物资(>500元):需要系主任审批
4. 特殊物资:需要后勤主管审批
]

## 审批规则
[描述审批规则,例如:
- 辅导员审批:24小时内
- 系主任审批:48小时内
- 后勤主管审批:72小时内
- 超时自动提醒,超过3天自动拒绝
]

## 输出要求
1. TypeScript 代码实现
2. 包含完整的审批流程逻辑
3. 包含超时处理
4. 包含通知机制
5. 包含单元测试用例
6. 包含注释说明

请生成代码。

使用示例

输入 PROMPT:

text
你是一个业务逻辑开发专家。请根据以下业务规则,生成完整的多级审批流程代码。

## 业务场景
校园物资申请多级审批

## 审批流程定义
1. 普通物资(<100元):无需审批,自动批准
2. 贵重物资(100-500元):需要辅导员审批
3. 高价值物资(>500元):需要系主任审批
4. 特殊物资:需要后勤主管审批

## 审批规则
- 辅导员审批:24小时内
- 系主任审批:48小时内
- 后勤主管审批:72小时内
- 超时自动提醒,超过3天自动拒绝

## 输出要求
1. TypeScript 代码实现
2. 包含完整的审批流程逻辑
3. 包含超时处理
4. 包含通知机制
5. 包含单元测试用例
6. 包含注释说明

请生成代码。

3. 实施指南

快速复现步骤

如果你需要在新项目中实现类似的场景,按照以下步骤:

步骤 1:需求确认(1 小时)

  • [ ] 确认预约资源类型和规则
  • [ ] 确认冲突检测规则(时间重叠、时间间隔)
  • [ ] 确认预约限制(次数、时长、提前时间)
  • [ ] 确认审批流程(如果需要)

步骤 2:数据库设计(30 分钟)

sql
-- 资源表
CREATE TABLE resources (
  id VARCHAR(50) PRIMARY KEY,
  name VARCHAR(100),
  type VARCHAR(50),  -- 教室、会议室、设备等
  capacity INT,
  location VARCHAR(200),
  need_approval BOOLEAN DEFAULT FALSE,
  status VARCHAR(20),
  created_at TIMESTAMP
);

-- 预约表
CREATE TABLE reservations (
  id VARCHAR(50) PRIMARY KEY,
  resource_id VARCHAR(50),
  user_id VARCHAR(50),
  start_time TIMESTAMP,
  end_time TIMESTAMP,
  purpose TEXT,
  need_approval BOOLEAN,
  approval_status VARCHAR(20),
  check_in_time TIMESTAMP,
  check_out_time TIMESTAMP,
  status VARCHAR(20),
  created_at TIMESTAMP,
  updated_at TIMESTAMP
);

-- 审批记录表
CREATE TABLE approval_records (
  id VARCHAR(50) PRIMARY KEY,
  application_id VARCHAR(50),  -- 申请ID(预约/物资申请)
  application_type VARCHAR(50),  -- 申请类型
  approver_id VARCHAR(50),
  approver_role VARCHAR(50),
  approval_status VARCHAR(20),
  approval_time TIMESTAMP,
  comment TEXT,
  created_at TIMESTAMP
);

步骤 3:开发冲突检测(2 小时)

使用上述 Cursor Skill,快速生成冲突检测逻辑代码。

步骤 4:开发审批流程(2 小时)

使用 PROMPT 模板生成审批流程逻辑。

步骤 5:集成通知(1 小时)

  • 微信公众号模板消息
  • 企业微信机器人
  • 短信通知(备用)

步骤 6:测试(2 小时)

  • 冲突检测测试
  • 预约限制测试
  • 审批流程测试
  • 超时处理测试

总开发时间:约 8-10 小时

关键代码片段

后端 API 示例:

typescript
// POST /api/reservations/create
router.post('/create', async (req, res) => {
  const { resourceId, startTime, endTime, purpose } = req.body;
  const userId = req.user.id;
  
  // 1. 检查冲突
  const conflictResult = await checkConflict(
    resourceId,
    new Date(startTime),
    new Date(endTime)
  );
  
  if (!conflictResult.canReserve) {
    return res.status(400).json({
      success: false,
      message: '预约时间冲突',
      conflicts: conflictResult
    });
  }
  
  // 2. 检查预约限制
  const canReserve = await checkDailyLimit(userId, new Date(startTime));
  if (!canReserve) {
    return res.status(400).json({
      success: false,
      message: '已达到每日预约上限'
    });
  }
  
  // 3. 创建预约
  const reservation = await createReservation({
    resourceId,
    userId,
    startTime: new Date(startTime),
    endTime: new Date(endTime),
    purpose,
    needApproval: false, // 根据资源类型判断
    status: 'reserved'
  });
  
  // 4. 通知用户
  await notifyUser(userId, {
    type: 'RESERVATION_CREATED',
    reservationId: reservation.id
  });
  
  res.json({ success: true, reservation });
});

下一步

查看 系统落地 → 了解这个场景在完整系统中的实现。


相关链接

基于 AI 辅助开发,快速、灵活、可靠