人情往来站点服务端api代码基础版本

9/23/2025

# 人情往来站点服务端api代码基础版本

# 1. 数据库操作类 (db.js)

/**
 * 数据库操作类
 * 提供对所有数据表的CRUD操作
 */
export class Database {
  constructor(db) {
    this.db = db;
  }

  /**
   * 创建账户
   * @param {Object} account - 账户信息
   * @returns {Promise<Object>} 创建的账户对象
   */
  async createAccount(account) {
    const result = await this.db.prepare(
      `INSERT INTO accounts (username, email, password, avatar, nickname, phone, is_active, extra_data, last_login)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
       RETURNING *`
    ).bind(
      account.username,
      account.email,
      account.password,
      account.avatar,
      account.nickname,
      account.phone,
      account.is_active,
      account.extra_data,
      account.last_login
    ).run();
    
    return result.results[0];
  }

  /**
   * 根据用户名获取账户
   * @param {string} username - 用户名
   * @returns {Promise<Object|null>} 账户对象或null
   */
  async getAccountByUsername(username) {
    const result = await this.db.prepare(
      `SELECT * FROM accounts WHERE username = ? AND deleted_at IS NULL`
    ).bind(username).all();
    
    return result.results[0] || null;
  }

  /**
   * 根据ID获取账户
   * @param {number} id - 账户ID
   * @returns {Promise<Object|null>} 账户对象或null
   */
  async getAccountById(id) {
    const result = await this.db.prepare(
      `SELECT * FROM accounts WHERE id = ? AND deleted_at IS NULL`
    ).bind(id).all();
    
    return result.results[0] || null;
  }

  /**
   * 更新账户最后登录时间
   * @param {number} id - 账户ID
   * @returns {Promise<void>}
   */
  async updateAccountLastLogin(id) {
    await this.db.prepare(
      `UPDATE accounts SET last_login = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP WHERE id = ?`
    ).bind(id).run();
  }

  /**
   * 创建联系人
   * @param {Object} contact - 联系人信息
   * @returns {Promise<Object>} 创建的联系人对象
   */
  async createContact(contact) {
    const result = await this.db.prepare(
      `INSERT INTO contacts (account_id, name, phone, relationship, notes, avatar, email, address, is_active, extra_data)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
       RETURNING *`
    ).bind(
      contact.account_id,
      contact.name,
      contact.phone,
      contact.relationship,
      contact.notes,
      contact.avatar,
      contact.email,
      contact.address,
      contact.is_active,
      contact.extra_data
    ).run();
    
    return result.results[0];
  }

  /**
   * 获取联系人列表
   * @param {number} accountId - 账户ID
   * @param {number} page - 页码
   * @param {number} limit - 每页数量
   * @returns {Promise<Object>} 包含联系人列表和总数的对象
   */
  async getContacts(accountId, page = 1, limit = 20) {
    const offset = (page - 1) * limit;
    
    const [contactsResult, countResult] = await Promise.all([
      this.db.prepare(
        `SELECT * FROM contacts WHERE account_id = ? AND deleted_at IS NULL ORDER BY created_at DESC LIMIT ? OFFSET ?`
      ).bind(accountId, limit, offset).all(),
      this.db.prepare(
        `SELECT COUNT(*) as count FROM contacts WHERE account_id = ? AND deleted_at IS NULL`
      ).bind(accountId).all()
    ]);
    
    return {
      contacts: contactsResult.results,
      total: countResult.results[0].count
    };
  }

  /**
   * 根据ID获取联系人
   * @param {number} id - 联系人ID
   * @param {number} accountId - 账户ID
   * @returns {Promise<Object|null>} 联系人对象或null
   */
  async getContactById(id, accountId) {
    const result = await this.db.prepare(
      `SELECT * FROM contacts WHERE id = ? AND account_id = ? AND deleted_at IS NULL`
    ).bind(id, accountId).all();
    
    return result.results[0] || null;
  }

  /**
   * 更新联系人
   * @param {number} id - 联系人ID
   * @param {number} accountId - 账户ID
   * @param {Object} updates - 更新内容
   * @returns {Promise<Object|null>} 更新后的联系人对象或null
   */
  async updateContact(id, accountId, updates) {
    const fields = [];
    const values = [];
    
    for (const [key, value] of Object.entries(updates)) {
      if (value !== undefined) {
        fields.push(`${key} = ?`);
        values.push(value);
      }
    }
    
    if (fields.length === 0) return null;
    
    values.push(id, accountId);
    
    const result = await this.db.prepare(
      `UPDATE contacts SET ${fields.join(', ')}, updated_at = CURRENT_TIMESTAMP 
       WHERE id = ? AND account_id = ? AND deleted_at IS NULL
       RETURNING *`
    ).bind(...values).run();
    
    return result.results[0] || null;
  }

  /**
   * 删除联系人(软删除)
   * @param {number} id - 联系人ID
   * @param {number} accountId - 账户ID
   * @returns {Promise<boolean>} 是否成功
   */
  async deleteContact(id, accountId) {
    const result = await this.db.prepare(
      `UPDATE contacts SET deleted_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP 
       WHERE id = ? AND account_id = ? AND deleted_at IS NULL`
    ).bind(id, accountId).run();
    
    return result.success;
  }

  /**
   * 创建事件
   * @param {Object} event - 事件信息
   * @returns {Promise<Object>} 创建的事件对象
   */
  async createEvent(event) {
    // 处理JSON字段
    const photos = event.photos ? JSON.stringify(event.photos) : null;
    const tags = event.tags ? JSON.stringify(event.tags) : null;
    const extra_data = event.extra_data || null;

    const result = await this.db.prepare(
      `INSERT INTO events (account_id, contact_id, title, event_type, event_date, amount, description, direction, location, photos, tags, extra_data)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
       RETURNING *`
    ).bind(
      event.account_id,
      event.contact_id,
      event.title,
      event.event_type,
      event.event_date,
      event.amount,
      event.description,
      event.direction,
      event.location,
      photos,
      tags,
      extra_data
    ).run();
    
    const createdEvent = result.results[0];
    // 解析JSON字段
    if (createdEvent.photos) {
      try {
        createdEvent.photos = JSON.parse(createdEvent.photos);
      } catch (e) {
        createdEvent.photos = null;
      }
    }
    if (createdEvent.tags) {
      try {
        createdEvent.tags = JSON.parse(createdEvent.tags);
      } catch (e) {
        createdEvent.tags = null;
      }
    }
    
    return createdEvent;
  }

  /**
   * 获取事件列表
   * @param {number} accountId - 账户ID
   * @param {number} page - 页码
   * @param {number} limit - 每页数量
   * @param {Object} filters - 过滤条件
   * @returns {Promise<Object>} 包含事件列表和总数的对象
   */
  async getEvents(accountId, page = 1, limit = 20, filters = {}) {
    const offset = (page - 1) * limit;
    
    let whereClause = 'WHERE e.account_id = ? AND e.deleted_at IS NULL';
    const values = [accountId];
    
    if (filters.contact_id) {
      whereClause += ' AND e.contact_id = ?';
      values.push(filters.contact_id);
    }
    
    if (filters.event_type) {
      whereClause += ' AND e.event_type = ?';
      values.push(filters.event_type);
    }
    
    if (filters.direction) {
      whereClause += ' AND e.direction = ?';
      values.push(filters.direction);
    }
    
    if (filters.start_date) {
      whereClause += ' AND e.event_date >= ?';
      values.push(filters.start_date);
    }
    
    if (filters.end_date) {
      whereClause += ' AND e.event_date <= ?';
      values.push(filters.end_date);
    }
    
    const [eventsResult, countResult] = await Promise.all([
      this.db.prepare(
        `SELECT e.*, c.name as contact_name FROM events e 
         LEFT JOIN contacts c ON e.contact_id = c.id 
         ${whereClause} 
         ORDER BY e.event_date DESC, e.created_at DESC 
         LIMIT ? OFFSET ?`
      ).bind(...values, limit, offset).all(),
      this.db.prepare(
        `SELECT COUNT(*) as count FROM events e ${whereClause}`
      ).bind(...values).all()
    ]);
    
    const events = eventsResult.results.map(event => {
      const parsedEvent = { ...event };
      if (parsedEvent.photos) {
        try {
          parsedEvent.photos = JSON.parse(parsedEvent.photos);
        } catch (e) {
          parsedEvent.photos = null;
        }
      }
      if (parsedEvent.tags) {
        try {
          parsedEvent.tags = JSON.parse(parsedEvent.tags);
        } catch (e) {
          parsedEvent.tags = null;
        }
      }
      return parsedEvent;
    });
    
    return {
      events,
      total: countResult.results[0].count
    };
  }

  /**
   * 根据ID获取事件
   * @param {number} id - 事件ID
   * @param {number} accountId - 账户ID
   * @returns {Promise<Object|null>} 事件对象或null
   */
  async getEventById(id, accountId) {
    const result = await this.db.prepare(
      `SELECT e.*, c.name as contact_name FROM events e 
       LEFT JOIN contacts c ON e.contact_id = c.id 
       WHERE e.id = ? AND e.account_id = ? AND e.deleted_at IS NULL`
    ).bind(id, accountId).all();
    
    if (!result.results[0]) return null;
    
    const event = result.results[0];
    if (event.photos) {
      try {
        event.photos = JSON.parse(event.photos);
      } catch (e) {
        event.photos = null;
      }
    }
    if (event.tags) {
      try {
        event.tags = JSON.parse(event.tags);
      } catch (e) {
        event.tags = null;
      }
    }
    
    return event;
  }

  /**
   * 更新事件
   * @param {number} id - 事件ID
   * @param {number} accountId - 账户ID
   * @param {Object} updates - 更新内容
   * @returns {Promise<Object|null>} 更新后的事件对象或null
   */
  async updateEvent(id, accountId, updates) {
    const fields = [];
    const values = [];
    
    // 处理特殊字段
    const processedUpdates = { ...updates };
    if (processedUpdates.photos) {
      processedUpdates.photos = JSON.stringify(processedUpdates.photos);
    }
    if (processedUpdates.tags) {
      processedUpdates.tags = JSON.stringify(processedUpdates.tags);
    }
    
    for (const [key, value] of Object.entries(processedUpdates)) {
      if (value !== undefined) {
        fields.push(`${key} = ?`);
        values.push(value);
      }
    }
    
    if (fields.length === 0) return null;
    
    values.push(id, accountId);
    
    const result = await this.db.prepare(
      `UPDATE events SET ${fields.join(', ')}, updated_at = CURRENT_TIMESTAMP 
       WHERE id = ? AND account_id = ? AND deleted_at IS NULL
       RETURNING *`
    ).bind(...values).run();
    
    if (!result.results[0]) return null;
    
    const updatedEvent = result.results[0];
    if (updatedEvent.photos) {
      try {
        updatedEvent.photos = JSON.parse(updatedEvent.photos);
      } catch (e) {
        updatedEvent.photos = null;
      }
    }
    if (updatedEvent.tags) {
      try {
        updatedEvent.tags = JSON.parse(updatedEvent.tags);
      } catch (e) {
        updatedEvent.tags = null;
      }
    }
    
    return updatedEvent;
  }

  /**
   * 删除事件(软删除)
   * @param {number} id - 事件ID
   * @param {number} accountId - 账户ID
   * @returns {Promise<boolean>} 是否成功
   */
  async deleteEvent(id, accountId) {
    const result = await this.db.prepare(
      `UPDATE events SET deleted_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP 
       WHERE id = ? AND account_id = ? AND deleted_at IS NULL`
    ).bind(id, accountId).run();
    
    return result.success;
  }

  /**
   * 获取或创建统计记录
   * @param {number} accountId - 账户ID
   * @param {string} statType - 统计类型
   * @param {string} statKey - 统计键值
   * @param {number} giveAmount - 给出金额
   * @param {number} receiveAmount - 收到金额
   * @returns {Promise<Object>} 统计对象
   */
  async upsertStatistics(accountId, statType, statKey, giveAmount, receiveAmount) {
    const result = await this.db.prepare(
      `INSERT INTO statistics (account_id, stat_type, stat_key, total_give, total_receive, event_count)
       VALUES (?, ?, ?, ?, ?, 1)
       ON CONFLICT(account_id, stat_type, stat_key) 
       DO UPDATE SET 
         total_give = total_give + ?, 
         total_receive = total_receive + ?, 
         event_count = event_count + 1,
         updated_at = CURRENT_TIMESTAMP
       RETURNING *`
    ).bind(accountId, statType, statKey, giveAmount, receiveAmount, giveAmount, receiveAmount).run();
    
    return result.results[0];
  }

  /**
   * 根据条件获取统计信息
   * @param {number} accountId - 账户ID
   * @param {string} statType - 统计类型
   * @param {string} statKey - 统计键值
   * @returns {Promise<Object|null>} 统计对象或null
   */
  async getStatistics(accountId, statType, statKey) {
    const result = await this.db.prepare(
      `SELECT * FROM statistics WHERE account_id = ? AND stat_type = ? AND stat_key = ?`
    ).bind(accountId, statType, statKey).all();
    
    return result.results[0] || null;
  }

  /**
   * 根据键名获取配置
   * @param {string} key - 配置键名
   * @returns {Promise<Object|null>} 配置对象或null
   */
  async getConfig(key) {
    const result = await this.db.prepare(
      `SELECT * FROM config WHERE config_key = ?`
    ).bind(key).all();
    
    return result.results[0] || null;
  }

  /**
   * 获取所有配置
   * @returns {Promise<Object>} 配置对象
   */
  async getAllConfig() {
    const result = await this.db.prepare(
      `SELECT config_key, config_value FROM config`
    ).all();
    
    const config = {};
    for (const row of result.results) {
      try {
        config[row.config_key] = JSON.parse(row.config_value);
      } catch (e) {
        config[row.config_key] = row.config_value;
      }
    }
    
    return config;
  }
}

# 2. 中间件 (middleware.js)

import { jwt } from 'hono/jwt';
import { Database } from './db';

/**
 * 认证中间件
 * 验证JWT token并设置用户信息
 */
export const authMiddleware = async (c, next) => {
  const authHeader = c.req.header('Authorization');
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '未授权访问' 
    }, 401);
  }

  const token = authHeader.substring(7);
  try {
    const payload = await jwt.verify(token, c.env.JWT_SECRET);
    c.set('user', payload);
    await next();
  } catch (e) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的令牌' 
    }, 401);
  }
};

/**
 * 数据库中间件
 * 将数据库实例注入到上下文中
 */
export const dbMiddleware = async (c, next) => {
  const db = new Database(c.env.DB);
  c.set('db', db);
  await next();
};

/**
 * 统一响应格式中间件
 */
export const responseMiddleware = async (c, next) => {
  await next();
  // 这里可以添加统一的响应格式处理
};

# 3. 认证API (routes/auth.js)

import { Hono } from 'hono';
import { jwt } from 'hono/jwt';
import { hash, verify } from 'argon2';

/**
 * 认证相关API路由
 * 包括注册、登录、获取当前用户信息等功能
 */
const auth = new Hono();

/**
 * 用户注册接口
 * POST /api/auth/register
 * 
 * 请求体:
 * {
 *   "username": "用户名",
 *   "email": "邮箱",
 *   "password": "密码",
 *   "nickname": "昵称" (可选)
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 用户信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
auth.post('/register', async (c) => {
  const db = c.get('db');
  const body = await c.req.json();
  
  // 验证输入
  if (!body.username || !body.email || !body.password) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '用户名、邮箱和密码为必填项' 
    }, 400);
  }
  
  // 检查用户名是否已存在
  const existingUser = await db.getAccountByUsername(body.username);
  if (existingUser) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '用户名已存在' 
    }, 400);
  }
  
  // 密码加密
  const hashedPassword = await hash(body.password);
  
  try {
    const account = await db.createAccount({
      username: body.username,
      email: body.email,
      password: hashedPassword,
      nickname: body.nickname,
      is_active: true
    });
    
    // 生成JWT token
    const payload = {
      id: account.id,
      username: account.username,
      exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7 // 7天过期
    };
    
    const token = await jwt.sign(payload, c.env.JWT_SECRET);
    
    const { password, ...accountWithoutPassword } = account;
    return c.json({ 
      success: true, 
      data: {
        token,
        account: accountWithoutPassword
      }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '注册失败' 
    }, 500);
  }
});

/**
 * 用户登录接口
 * POST /api/auth/login
 * 
 * 请求体:
 * {
 *   "username": "用户名",
 *   "password": "密码"
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 用户信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
auth.post('/login', async (c) => {
  const db = c.get('db');
  const body = await c.req.json();
  
  if (!body.username || !body.password) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '用户名和密码为必填项' 
    }, 400);
  }
  
  const account = await db.getAccountByUsername(body.username);
  if (!account) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '用户名或密码错误' 
    }, 401);
  }
  
  const isValid = await verify(account.password, body.password);
  if (!isValid) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '用户名或密码错误' 
    }, 401);
  }
  
  // 更新最后登录时间
  await db.updateAccountLastLogin(account.id);
  
  // 生成JWT token
  const payload = {
    id: account.id,
    username: account.username,
    exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7 // 7天过期
  };
  
  const token = await jwt.sign(payload, c.env.JWT_SECRET);
  
  const { password, ...accountWithoutPassword } = account;
  return c.json({ 
    success: true, 
    data: {
      token,
      account: accountWithoutPassword
    }, 
    error: false, 
    errorMessage: null 
  });
});

/**
 * 获取当前用户信息接口
 * GET /api/auth/me
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 用户信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
auth.get('/me', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  
  const account = await db.getAccountById(user.id);
  if (!account) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '用户不存在' 
    }, 404);
  }
  
  const { password, ...accountWithoutPassword } = account;
  return c.json({ 
    success: true, 
    data: { account: accountWithoutPassword }, 
    error: false, 
    errorMessage: null 
  });
});

export default auth;

# 4. 联系人API (routes/contacts.js)

import { Hono } from 'hono';

/**
 * 联系人相关API路由
 * 包括创建、获取、更新、删除联系人等功能
 */
const contacts = new Hono();

/**
 * 创建联系人接口
 * POST /api/contacts
 * 
 * 请求体:
 * {
 *   "name": "联系人姓名",
 *   "phone": "电话" (可选),
 *   "relationship": "关系类型" (可选),
 *   "notes": "备注" (可选),
 *   "avatar": "头像URL" (可选),
 *   "email": "邮箱" (可选),
 *   "address": "地址" (可选)
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 联系人信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
contacts.post('/', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const body = await c.req.json();
  
  // 基本验证
  if (!body.name) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '联系人姓名为必填项' 
    }, 400);
  }
  
  try {
    const contact = await db.createContact({
      account_id: user.id,
      name: body.name,
      phone: body.phone,
      relationship: body.relationship,
      notes: body.notes,
      avatar: body.avatar,
      email: body.email,
      address: body.address,
      is_active: true
    });
    
    return c.json({ 
      success: true, 
      data: { contact }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '创建联系人失败' 
    }, 500);
  }
});

/**
 * 获取联系人列表接口
 * GET /api/contacts?page=1&limit=20
 * 
 * 查询参数:
 * - page: 页码 (默认1)
 * - limit: 每页数量 (默认20)
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 联系人列表和总数 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
contacts.get('/', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  
  let page = parseInt(c.req.query('page') || '1');
  let limit = parseInt(c.req.query('limit') || '20');
  
  // 参数验证
  if (isNaN(page) || page < 1) page = 1;
  if (isNaN(limit) || limit < 1 || limit > 100) limit = 20;
  
  try {
    const result = await db.getContacts(user.id, page, limit);
    return c.json({ 
      success: true, 
      data: result, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取联系人列表失败' 
    }, 500);
  }
});

/**
 * 获取单个联系人接口
 * GET /api/contacts/:id
 * 
 * 路径参数:
 * - id: 联系人ID
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 联系人信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
contacts.get('/:id', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const id = parseInt(c.req.param('id'));
  
  if (isNaN(id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的联系人ID' 
    }, 400);
  }
  
  try {
    const contact = await db.getContactById(id, user.id);
    if (!contact) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '联系人不存在' 
      }, 404);
    }
    
    return c.json({ 
      success: true, 
      data: { contact }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取联系人失败' 
    }, 500);
  }
});

/**
 * 更新联系人接口
 * PUT /api/contacts/:id
 * 
 * 路径参数:
 * - id: 联系人ID
 * 
 * 请求体:
 * {
 *   "name": "联系人姓名" (可选),
 *   "phone": "电话" (可选),
 *   "relationship": "关系类型" (可选),
 *   "notes": "备注" (可选),
 *   "avatar": "头像URL" (可选),
 *   "email": "邮箱" (可选),
 *   "address": "地址" (可选),
 *   "is_active": "是否激活" (可选)
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 更新后的联系人信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
contacts.put('/:id', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const id = parseInt(c.req.param('id'));
  const body = await c.req.json();
  
  if (isNaN(id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的联系人ID' 
    }, 400);
  }
  
  try {
    const contact = await db.updateContact(id, user.id, body);
    if (!contact) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '联系人不存在' 
      }, 404);
    }
    
    return c.json({ 
      success: true, 
      data: { contact }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '更新联系人失败' 
    }, 500);
  }
});

/**
 * 删除联系人接口
 * DELETE /api/contacts/:id
 * 
 * 路径参数:
 * - id: 联系人ID
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 删除结果 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
contacts.delete('/:id', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const id = parseInt(c.req.param('id'));
  
  if (isNaN(id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的联系人ID' 
    }, 400);
  }
  
  try {
    const success = await db.deleteContact(id, user.id);
    if (!success) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '联系人不存在' 
      }, 404);
    }
    
    return c.json({ 
      success: true, 
      data: { message: '联系人删除成功' }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '删除联系人失败' 
    }, 500);
  }
});

/**
 * 批量删除联系人接口
 * POST /api/contacts/batch-delete
 * 
 * 请求体:
 * {
 *   "ids": [1, 2, 3]  // 要删除的联系人ID数组
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 删除结果 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
contacts.post('/batch-delete', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const body = await c.req.json();
  
  if (!body.ids || !Array.isArray(body.ids) || body.ids.length === 0) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: 'ids数组为必填项' 
    }, 400);
  }
  
  let deletedCount = 0;
  let failedCount = 0;
  
  try {
    for (const id of body.ids) {
      const success = await db.deleteContact(id, user.id);
      if (success) {
        deletedCount++;
      } else {
        failedCount++;
      }
    }
    
    return c.json({ 
      success: true, 
      data: { 
        message: '批量删除成功',
        deleted: deletedCount,
        failed: failedCount
      }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '批量删除联系人失败' 
    }, 500);
  }
});

export default contacts;

# 5. 事件API (routes/events.js)

import { Hono } from 'hono';

/**
 * 事件相关API路由
 * 包括创建、获取、更新、删除人情往来事件等功能
 */
const events = new Hono();

/**
 * 创建事件接口
 * POST /api/events
 * 
 * 请求体:
 * {
 *   "contact_id": "联系人ID",
 *   "title": "事件标题",
 *   "event_type": "事件类型",
 *   "event_date": "事件日期 (YYYY-MM-DD)",
 *   "amount": "金额",
 *   "description": "描述" (可选),
 *   "direction": "方向 (give/receive)",
 *   "location": "地点" (可选),
 *   "photos": ["照片URL数组"] (可选),
 *   "tags": ["标签数组"] (可选)
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 事件信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
events.post('/', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const body = await c.req.json();
  
  // 基本验证
  if (!body.contact_id || !body.title || !body.event_type || !body.event_date || body.amount === undefined || !body.direction) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '联系人ID、事件标题、事件类型、事件日期、金额和方向为必填项' 
    }, 400);
  }
  
  // 验证方向字段
  if (body.direction !== 'give' && body.direction !== 'receive') {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '方向必须是"give"或"receive"' 
    }, 400);
  }
  
  // 验证金额
  if (isNaN(body.amount) || body.amount < 0) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '金额必须为非负数' 
    }, 400);
  }
  
  try {
    const event = await db.createEvent({
      account_id: user.id,
      contact_id: body.contact_id,
      title: body.title,
      event_type: body.event_type,
      event_date: body.event_date,
      amount: parseFloat(body.amount),
      description: body.description,
      direction: body.direction,
      location: body.location,
      photos: body.photos,
      tags: body.tags
    });
    
    // 更新统计信息
    const giveAmount = body.direction === 'give' ? parseFloat(body.amount) : 0;
    const receiveAmount = body.direction === 'receive' ? parseFloat(body.amount) : 0;
    
    const year = new Date(body.event_date).getFullYear();
    const month = new Date(body.event_date).getMonth() + 1;
    const yearMonth = `${year}-${month.toString().padStart(2, '0')}`;
    
    await db.upsertStatistics(user.id, 'month', yearMonth, giveAmount, receiveAmount);
    await db.upsertStatistics(user.id, 'year', year.toString(), giveAmount, receiveAmount);
    
    return c.json({ 
      success: true, 
      data: { event }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    console.error('Create event error:', error);
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '创建事件失败' 
    }, 500);
  }
});

/**
 * 获取事件列表接口
 * GET /api/events?page=1&limit=20&contact_id=1&event_type=birthday&direction=give&start_date=2024-01-01&end_date=2024-12-31
 * 
 * 查询参数:
 * - page: 页码 (默认1)
 * - limit: 每页数量 (默认20)
 * - contact_id: 联系人ID (可选)
 * - event_type: 事件类型 (可选)
 * - direction: 方向 (give/receive) (可选)
 * - start_date: 开始日期 (可选)
 * - end_date: 结束日期 (可选)
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 事件列表和总数 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
events.get('/', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  
  let page = parseInt(c.req.query('page') || '1');
  let limit = parseInt(c.req.query('limit') || '20');
  
  // 参数验证
  if (isNaN(page) || page < 1) page = 1;
  if (isNaN(limit) || limit < 1 || limit > 100) limit = 20;
  
  const filters = {
    contact_id: c.req.query('contact_id') ? parseInt(c.req.query('contact_id')) : undefined,
    event_type: c.req.query('event_type'),
    direction: c.req.query('direction'),
    start_date: c.req.query('start_date'),
    end_date: c.req.query('end_date')
  };
  
  // 过滤参数验证
  if (filters.contact_id && isNaN(filters.contact_id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的联系人ID' 
    }, 400);
  }
  
  if (filters.direction && filters.direction !== 'give' && filters.direction !== 'receive') {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '方向必须是"give"或"receive"' 
    }, 400);
  }
  
  try {
    const result = await db.getEvents(user.id, page, limit, filters);
    return c.json({ 
      success: true, 
      data: result, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取事件列表失败' 
    }, 500);
  }
});

/**
 * 获取单个事件接口
 * GET /api/events/:id
 * 
 * 路径参数:
 * - id: 事件ID
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 事件信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
events.get('/:id', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const id = parseInt(c.req.param('id'));
  
  if (isNaN(id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的事件ID' 
    }, 400);
  }
  
  try {
    const event = await db.getEventById(id, user.id);
    if (!event) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '事件不存在' 
      }, 404);
    }
    
    return c.json({ 
      success: true, 
      data: { event }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取事件失败' 
    }, 500);
  }
});

/**
 * 更新事件接口
 * PUT /api/events/:id
 * 
 * 路径参数:
 * - id: 事件ID
 * 
 * 请求体:
 * {
 *   "contact_id": "联系人ID" (可选),
 *   "title": "事件标题" (可选),
 *   "event_type": "事件类型" (可选),
 *   "event_date": "事件日期" (可选),
 *   "amount": "金额" (可选),
 *   "description": "描述" (可选),
 *   "direction": "方向" (可选),
 *   "location": "地点" (可选),
 *   "photos": ["照片URL数组"] (可选),
 *   "tags": ["标签数组"] (可选)
 * }
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 更新后的事件信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
events.put('/:id', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const id = parseInt(c.req.param('id'));
  const body = await c.req.json();
  
  if (isNaN(id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的事件ID' 
    }, 400);
  }
  
  try {
    const event = await db.updateEvent(id, user.id, body);
    if (!event) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '事件不存在' 
      }, 404);
    }
    
    return c.json({ 
      success: true, 
      data: { event }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '更新事件失败' 
    }, 500);
  }
});

/**
 * 删除事件接口
 * DELETE /api/events/:id
 * 
 * 路径参数:
 * - id: 事件ID
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 删除结果 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
events.delete('/:id', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  const id = parseInt(c.req.param('id'));
  
  if (isNaN(id)) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '无效的事件ID' 
    }, 400);
  }
  
  try {
    const success = await db.deleteEvent(id, user.id);
    if (!success) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '事件不存在' 
      }, 404);
    }
    
    return c.json({ 
      success: true, 
      data: { message: '事件删除成功' }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '删除事件失败' 
    }, 500);
  }
});

export default events;

# 6. 配置API (routes/config.js)

import { Hono } from 'hono';

/**
 * 配置相关API路由
 * 包括获取系统配置等功能
 */
const config = new Hono();

/**
 * 获取所有配置接口
 * GET /api/config
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 配置信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
config.get('/', async (c) => {
  const db = c.get('db');
  
  try {
    const configData = await db.getAllConfig();
    return c.json({ 
      success: true, 
      data: configData, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取配置失败' 
    }, 500);
  }
});

/**
 * 获取指定配置接口
 * GET /api/config/:key
 * 
 * 路径参数:
 * - key: 配置键名
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 配置信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
config.get('/:key', async (c) => {
  const db = c.get('db');
  const key = c.req.param('key');
  
  try {
    const configData = await db.getConfig(key);
    if (!configData) {
      return c.json({ 
        success: false, 
        data: null, 
        error: true, 
        errorMessage: '配置不存在' 
      }, 404);
    }
    
    // 解析配置值
    let parsedValue;
    try {
      parsedValue = JSON.parse(configData.config_value);
    } catch (e) {
      parsedValue = configData.config_value;
    }
    
    return c.json({ 
      success: true, 
      data: { 
        key: configData.config_key,
        value: parsedValue,
        description: configData.description
      }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取配置失败' 
    }, 500);
  }
});

export default config;

# 7. 统计API (routes/statistics.js)

import { Hono } from 'hono';

/**
 * 统计相关API路由
 * 包括获取统计信息等功能
 */
const statistics = new Hono();

/**
 * 获取统计信息接口
 * GET /api/statistics?type=month&key=2024-01
 * 
 * 查询参数:
 * - type: 统计类型 (year/month/quarter)
 * - key: 统计键值 (如: 2024, 2024-01, 2024-Q1)
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 统计信息 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
statistics.get('/', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  
  const type = c.req.query('type');
  const key = c.req.query('key');
  
  if (!type || !key) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '统计类型和键值为必填项' 
    }, 400);
  }
  
  try {
    const stat = await db.getStatistics(user.id, type, key);
    return c.json({ 
      success: true, 
      data: { statistics: stat }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取统计信息失败' 
    }, 500);
  }
});

/**
 * 获取年度统计概览
 * GET /api/statistics/overview?year=2024
 * 
 * 响应:
 * {
 *   "success": true/false,
 *   "data": { 统计概览 },
 *   "error": true/false,
 *   "errorMessage": "错误信息"
 * }
 */
statistics.get('/overview', async (c) => {
  const db = c.get('db');
  const user = c.get('user');
  
  const year = c.req.query('year') || new Date().getFullYear().toString();
  
  try {
    // 获取年度总计
    const yearStat = await db.getStatistics(user.id, 'year', year);
    
    // 获取该年度各月统计
    const monthStats = [];
    for (let month = 1; month <= 12; month++) {
      const monthKey = `${year}-${month.toString().padStart(2, '0')}`;
      const monthStat = await db.getStatistics(user.id, 'month', monthKey);
      if (monthStat) {
        monthStats.push(monthStat);
      }
    }
    
    return c.json({ 
      success: true, 
      data: {
        year_total_give: yearStat?.total_give || 0,
        year_total_receive: yearStat?.total_receive || 0,
        month_stats: monthStats
      }, 
      error: false, 
      errorMessage: null 
    });
  } catch (error) {
    return c.json({ 
      success: false, 
      data: null, 
      error: true, 
      errorMessage: '获取统计概览失败' 
    }, 500);
  }
});

export default statistics;

# 8. 入口文件 (index.js)

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { Database } from './db';
import { authMiddleware, dbMiddleware } from './middleware';

// 导入路由
import authRoutes from './routes/auth';
import contactsRoutes from './routes/contacts';
import eventsRoutes from './routes/events';
import configRoutes from './routes/config';
import statisticsRoutes from './routes/statistics';

/**
 * 主应用入口文件
 * 配置中间件和路由
 */
const app = new Hono();

// CORS中间件
app.use('*', cors());

// 数据库中间件
app.use('*', dbMiddleware);

// 公共路由(无需认证)
app.route('/api/auth', authRoutes);
app.route('/api/config', configRoutes);

// 需要认证的路由
app.use('/api/contacts/*', authMiddleware);
app.use('/api/events/*', authMiddleware);
app.use('/api/statistics/*', authMiddleware);

app.route('/api/contacts', contactsRoutes);
app.route('/api/events', eventsRoutes);
app.route('/api/statistics', statisticsRoutes);

// 健康检查接口
app.get('/health', (c) => {
  return c.json({ 
    success: true, 
    data: { status: 'ok', timestamp: new Date().toISOString() }, 
    error: false, 
    errorMessage: null 
  });
});

// API版本信息
app.get('/api', (c) => {
  return c.json({ 
    success: true, 
    data: { 
      version: '1.0.0',
      timestamp: new Date().toISOString()
    }, 
    error: false, 
    errorMessage: null 
  });
});

// 404处理
app.notFound((c) => {
  return c.json({ 
    success: false, 
    data: null, 
    error: true, 
    errorMessage: '接口不存在' 
  }, 404);
});

// 错误处理
app.onError((err, c) => {
  console.error('Error:', err);
  return c.json({ 
    success: false, 
    data: null, 
    error: true, 
    errorMessage: '服务器内部错误' 
  }, 500);
});

export default app;

# API接口文档

# 认证相关接口

  • POST /api/auth/register - 用户注册
  • POST /api/auth/login - 用户登录
  • GET /api/auth/me - 获取当前用户信息

# 联系人相关接口

  • POST /api/contacts - 创建联系人
  • GET /api/contacts - 获取联系人列表
  • GET /api/contacts/:id - 获取单个联系人
  • PUT /api/contacts/:id - 更新联系人
  • DELETE /api/contacts/:id - 删除联系人
  • POST /api/contacts/batch-delete - 批量删除联系人

# 事件相关接口

  • POST /api/events - 创建事件
  • GET /api/events - 获取事件列表
  • GET /api/events/:id - 获取单个事件
  • PUT /api/events/:id - 更新事件
  • DELETE /api/events/:id - 删除事件

# 统计相关接口

  • GET /api/statistics - 获取统计信息
  • GET /api/statistics/overview - 获取统计概览

# 配置相关接口

  • GET /api/config - 获取所有配置
  • GET /api/config/:key - 获取指定配置

所有API响应格式统一为:

{
  "success": true/false,
  "data": {},
  "error": true/false,
  "errorMessage": "错误信息"
}