好的, 我们可以添加雇主发布工作的功能和用户上传、管理个人简历的功能。这里是实现这些功能的步骤:

  1. 首先, 我们需要修改数据库结构。在 Turso 数据库中添加新的表:
-- 用户表
CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  email TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  role TEXT NOT NULL CHECK(role IN ('jobseeker', 'employer')),
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
 
-- 简历表
CREATE TABLE resumes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id INTEGER NOT NULL,
  file_name TEXT NOT NULL,
  file_path TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id)
);
 
-- 修改jobs表,添加employer_id
ALTER TABLE jobs ADD COLUMN employer_id INTEGER;
ALTER TABLE jobs ADD FOREIGN KEY (employer_id) REFERENCES users(id);
  1. 修改 auth.ts 文件, 在用户认证后创建或更新用户信息:
// auth.ts
// ... (保留之前的导入)
 
async function createOrUpdateUser(db, userInfo) {
  const existingUser = await db.execute({
    sql: 'SELECT * FROM users WHERE email = ?',
    args: [userInfo.email]
  });
 
  if (existingUser.rows.length === 0) {
    await db.execute({
      sql: 'INSERT INTO users (email, name, role) VALUES (?, ?, ?)',
      args: [userInfo.email, userInfo.name, 'jobseeker']
    });
  } else {
    await db.execute({
      sql: 'UPDATE users SET name = ? WHERE email = ?',
      args: [userInfo.name, userInfo.email]
    });
  }
 
  return await db.execute({
    sql: 'SELECT * FROM users WHERE email = ?',
    args: [userInfo.email]
  });
}
 
export const auth = (app: Elysia) =>
  app
    // ... (保留之前的代码)
    .get('/auth/google/callback', async ({ query, jwt, setCookie, set, db }) => {
      // ... (保留之前的代码)
      const userInfo = await oauth.getUserInfo(client, tokens);
      const dbUser = await createOrUpdateUser(db, {
        email: userInfo.email,
        name: userInfo.name
      });
      const token = await jwt.sign({
        id: dbUser.rows[0].id,
        email: dbUser.rows[0].email,
        name: dbUser.rows[0].name,
        role: dbUser.rows[0].role
      });
      // ... (保留之前的代码)
    })
    .get('/auth/github/callback', async ({ query, jwt, setCookie, set, db }) => {
      // ... (类似的修改)
    })
    // ... (保留之前的代码)
  1. src/index.ts 中添加新的路由和功能:
import { Elysia } from 'elysia'
import { html } from '@elysiajs/html'
import { createClient } from '@libsql/client'
import { staticPlugin } from '@elysiajs/static'
import { auth } from './auth'
import 'unocss'
 
const db = createClient({
  url: process.env.TURSO_DATABASE_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN
})
 
const app = new Elysia()
  .use(html())
  .use(staticPlugin())
  .use(auth)
  .get('/', ({ html, user }) => html`
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Job Board</title>
        <script src="https://unpkg.com/htmx.org@1.9.2"></script>
        <script src="https://unpkg.com/unocss@0.51.8/dist/unocss.js"></script>
      </head>
      <body class="p-4" id="main-body">
        <header class="flex justify-between items-center mb-4">
          <h1 class="text-2xl font-bold">Job Board</h1>
          ${user
            ? `<div>
                Welcome, ${user.name}!
                <a href="/profile" class="ml-2 text-blue-500">Profile</a>
                <a href="/auth/logout" class="ml-2 text-blue-500">Logout</a>
              </div>`
            : `<div>
                <a href="/auth/google" class="text-blue-500 mr-2">Login with Google</a>
                <a href="/auth/github" class="text-blue-500">Login with GitHub</a>
              </div>`
          }
        </header>
        ${user
          ? `<div class="mb-4">
              <label for="template-select">Choose a template:</label>
              <select id="template-select" hx-get="/apply-template" hx-target="#main-body" hx-swap="outerHTML">
                <option value="sunny">Sunny Sky</option>
                <option value="night">Night Sky</option>
                <option value="sunset">Red Sunset</option>
                <option value="rainy">Gentle Rain</option>
                <option value="snowy">Winter Snow</option>
              </select>
              <button hx-get="/edit-template" class="ml-2 bg-blue-500 text-white p-2 rounded">Edit Template</button>
            </div>
            <div id="job-list" hx-get="/jobs" hx-trigger="load"></div>
            ${user. Role === 'employer'
              ? `<form hx-post="/jobs" hx-target="#job-list" class="mt-4">
                  <input type="text" name="title" placeholder="Job Title" required class="border p-2 mb-2 w-full">
                  <input type="text" name="company" placeholder="Company" required class="border p-2 mb-2 w-full">
                  <textarea name="description" placeholder="Job Description" required class="border p-2 mb-2 w-full h-32"></textarea>
                  <button type="submit" class="bg-blue-500 text-white p-2 rounded">Post Job</button>
                </form>`
              : ''
            }`
          : `<p>Please login to view and post jobs.</p>`
        }
      </body>
    </html>
  `)
  .get ('/jobs', async ({ user }) => {
    if (!user) return 'Please login to view jobs.'
    const jobs = await db.execute('SELECT jobs.*, users.name as employer_name FROM jobs JOIN users ON jobs.employer_id = users.id ORDER BY jobs.created_at DESC')
    return jobs.rows.map(job => `
      <div class="job bg-white shadow-md rounded p-4 mb-4">
        <h2 class="text-xl font-bold">${job.title}</h2>
        <h3 class="text-lg">${job.company}</h3>
        <p class="text-sm text-gray-600">Posted by: ${job.employer_name}</p>
        <p class="mt-2">${job.description}</p>
        ${user.role === 'jobseeker'
          ? `<button hx-post="/apply/${job.id}" class="mt-2 bg-green-500 text-white p-2 rounded">Apply</button>`
          : ''
        }
      </div>
    `).join('')
  })
  .post('/jobs', async ({ body, user }) => {
    if (!user || user.role !== 'employer') return 'Only employers can post jobs.'
    const { title, company, description } = body
    await db.execute({
      sql: 'INSERT INTO jobs (title, company, description, employer_id) VALUES (?, ?, ?, ?)',
      args: [title, company, description, user.id]
    })
    return app.handle({ path: '/jobs', method: 'GET' })
  })
  .get('/profile', async ({ user, html }) => {
    if (!user) return 'Please login to view your profile.'
    const resumes = await db.execute({
      sql: 'SELECT * FROM resumes WHERE user_id = ?',
      args: [user.id]
    })
    return html`
      <div class="container mx-auto p-4">
        <h1 class="text-2xl font-bold mb-4">Your Profile</h1>
        <p>Name: ${user.name}</p>
        <p>Email: ${user.email}</p>
        <p>Role: ${user.role}</p>
        
        ${user.role === 'jobseeker'
          ? `<h2 class="text-xl font-bold mt-4 mb-2">Your Resumes</h2>
             <ul>
               ${resumes.rows.map(resume => `
                 <li>${resume.file_name} 
                   <button hx-delete="/resume/${resume.id}" hx-target="closest li" class="text-red-500">Delete</button>
                 </li>
               `).join('')}
             </ul>
             <form hx-post="/resume" hx-encoding="multipart/form-data" hx-target="ul">
               <input type="file" name="resume" accept=".pdf,.doc,.docx">
               <button type="submit" class="bg-blue-500 text-white p-2 rounded mt-2">Upload Resume</button>
             </form>`
          : ''
        }
        
        ${user.role === 'jobseeker'
          ? `<button hx-post="/switch-to-employer" hx-target="body" class="bg-yellow-500 text-white p-2 rounded mt-4">Switch to Employer</button>`
          : `<button hx-post="/switch-to-jobseeker" hx-target="body" class="bg-green-500 text-white p-2 rounded mt-4">Switch to Job Seeker</button>`
        }
      </div>
    `
  })
  .post ('/resume', async ({ user, request }) => {
    if (!user || user.role !== 'jobseeker') return 'Only job seekers can upload resumes.'
    const formData = await request.formData()
    const file = formData.get('resume') as File
    if (!file) return 'No file uploaded.'
    
    // 在实际应用中,你需要处理文件上传,这里我们只是模拟
    const fileName = file.name
    const filePath = `/uploads/${Date.now()}-${fileName}`
    
    Await db.Execute ({
      sql: 'INSERT INTO resumes (user_id, file_name, file_path) VALUES (?, ?, ?)',
      args: [user.id, fileName, filePath]
    })
    
    return `<li>${fileName} <button hx-delete="/resume/${fileName}" hx-target="closest li" class="text-red-500">Delete</button></li>`
  })
  .delete('/resume/:id', async ({ user, params }) => {
    if (!user || user.role !== 'jobseeker') return 'Only job seekers can delete resumes.'
    await db.execute({
      sql: 'DELETE FROM resumes WHERE id = ? AND user_id = ?',
      args: [params.id, user.id]
    })
    return ''
  })
  .post('/switch-to-employer', async ({ user }) => {
    if (!user) return 'Please login to switch roles.'
    await db.execute({
      sql: 'UPDATE users SET role = "employer" WHERE id = ?',
      args: [user.id]
    })
    return app.handle({ path: '/', method: 'GET' })
  })
  .post('/switch-to-jobseeker', async ({ user }) => {
    if (!user) return 'Please login to switch roles.'
    await db.execute({
      sql: 'UPDATE users SET role = "jobseeker" WHERE id = ?',
      args: [user.id]
    })
    return app.handle({ path: '/', method: 'GET' })
  })
  .post('/apply/:jobId', async ({ user, params }) => {
    if (!user || user.role !== 'jobseeker') return 'Only job seekers can apply for jobs.'
    // 在实际应用中,你需要处理职位申请逻辑
    return `<p>You have successfully applied for job ${params.jobId}</p>`
  })
  // ... (保留之前的路由)
  .listen(3000)
 
console.log(`Elysia is running at ${app.server?.hostname}:${app.server?.port}`)

这个实现添加了以下功能:

  1. 用户角色 (求职者和雇主)
  2. 雇主可以发布工作
  3. 求职者可以上传和管理简历
  4. 用户可以在求职者和雇主角色之间切换
  5. 求职者可以申请工作

请注意, 这个实现仍然是基本的, 你可能需要根据你的具体需求进行进一步的改进, 例如:

  • 实现更复杂的文件上传和存储逻辑
  • 添加职位申请的详细流程和跟踪
  • 实现雇主查看申请者信息的功能
  • 添加更多的用户资料信息
  • 实现更复杂的搜索和筛选功能
  • 添加通知系统

此外, 在生产环境中, 你应该:

  • 使用更安全的文件上传和存储方法
  • 实现更严格的输入验证和安全检查
  • 使用事务来确保数据一致性
  • 考虑使用更复杂的权限管理系统
  • 实现适当的错误处理和日志记录

这个实现为你提供了一个良好的起点, 你可以根据需求继续扩展和完善这个招聘网站。