一个现代化的婚礼座位布置管理系统,支持多人实时协作。让婚礼座位安排变得简单、高效、有趣!
管理多个婚礼项目,一目了然查看所有筹备情况。
Excel 批量导入,支持标签分类和智能搜索,宾客信息管理轻松高效。
拖拽式座位安排,智能推荐,让排座变得简单快捷。
可视化场地编辑器,自由拖拽桌位布局,导出高清平面图。
实时统计宾客分布、座位安排进度,数据一目了然。
邀请团队成员,角色权限管理,多人协作无缝衔接。
- 📥 Excel 批量导入:一键导入宾客名单,支持标准 Excel 格式(.xlsx),自动识别姓名、人数、标签等信息
- 📝 信息编辑:完善的宾客信息管理,包括姓名、人数、电话、标签、备注等
- 🏷️ 标签分类:自定义标签管理宾客分类(如:新郎方、新娘方、领导、同事、朋友等)
- 🔍 智能搜索:支持按姓名、标签、是否已安排等多维度搜索和筛选
- 📊 批量操作:支持批量删除、批量导入、批量导出等操作
- 🖱️ 拖拽式操作:直观的拖拽界面,轻松将宾客拖动到指定桌位
- 🤖 智能推荐:基于宾客标签和约束条件,智能推荐最佳座位方案
- ⚡ 自动排座:一键自动排座功能,根据规则快速生成座位安排
- 🔗 排座约束:设置宾客关系(必须同桌/不能同桌),系统自动遵守约束
- 🔄 快速调整:支持座位交换、批量移动、一键清空等快捷操作
- 📝 实时预览:实时显示每桌人数、剩余座位等信息
- 📐 可视化编辑器:所见即所得的场地布局设计器
- 🖼️ 自由布局:拖拽桌位到任意位置,自定义容量
- 📏 网格对齐:智能网格吸附,让布局更规整美观
- 🎨 区域管理:划分不同区域(如主桌区、VIP 区、普通区等),设置区域颜色
- 📤 导出功能:导出高清 PNG 平面图,可直接用于打印或展示
- 🔗 邀请链接:生成专属邀请链接,一键邀请团队成员加入
- 🔐 角色权限:
- 主办人:完全控制权限,可管理项目、成员和所有数据
- 协作者:可编辑宾客和座位安排,协助筹备工作
- 只读成员:只能查看,不能修改,适合展示给其他人
- ⚡ 实时同步:基于 WebSocket 的实时数据同步,多人同时操作互不干扰
- 🟢 在线状态:显示团队成员在线状态,了解协作进度
- 📈 总览统计:总宾客数、已安排数、未安排数、总桌数等关键指标
- 🥧 标签分布:可视化展示各标签宾客占比,饼图/柱状图展示
- 📍 区域统计:各区域人数分布、使用率统计
- ✅ 进度跟踪:座位安排进度百分比,实时更新
- 📋 详细报表:导出详细的宾客名单、座位表、统计报表
- 👤 用户注册/登录:安全的账户体系,JWT 身份认证
- 🔒 数据隔离:每个项目数据完全隔离,确保隐私安全
- 🔄 自动登录:记住登录状态,长期有效的 Refresh Token
- 👥 多项目管理:一个账户可以管理多个婚礼项目
使用 Docker Compose 可以快速部署完整的应用栈,无需手动安装依赖。
- 安装 Docker 和 Docker Compose
- 确保 Docker 服务正在运行
1. 克隆项目(如果还没有)
git clone https://github.com/znonymous29/wedding-seating.git
cd wedding-seating2. 配置环境变量
# 复制环境变量示例文件
cp docker.env.example .env编辑 .env 文件,必须修改以下关键配置:
# 数据库密码(请设置强密码)
POSTGRES_PASSWORD=your-secure-password-here
# JWT 密钥(请生成随机字符串,至少32位)
JWT_SECRET=your-super-secret-jwt-key-change-in-production-at-least-32-chars
JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-in-production-at-least-32-chars
# ⚠️ 重要:站点访问地址(用于生成邀请链接)
# 本地测试环境:
CLIENT_URL=http://localhost:18080
CORS_ORIGIN=http://localhost:18080
# 局域网部署(替换为你的服务器IP):
# CLIENT_URL=http://192.168.1.100:18080
# CORS_ORIGIN=http://192.168.1.100:18080
# 生产环境(使用域名):
# CLIENT_URL=https://wedding.example.com
# CORS_ORIGIN=https://wedding.example.com💡 提示:如果不知道服务器 IP 地址,可以运行
ipconfig(Windows)或ifconfig(Linux/Mac)查看。
3. 启动服务
# 启动所有服务(首次启动会自动构建镜像)
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看实时日志
docker-compose logs -f
# 只查看某个服务的日志
docker-compose logs -f server4. 访问应用
- 前端界面: http://localhost:18080
- 后端 API: http://localhost:3001/api
首次访问请先注册账号,然后即可创建婚礼项目。
5. 服务管理
# 停止服务(保留数据)
docker-compose stop
# 重启服务
docker-compose restart
# 停止并删除容器(保留数据卷)
docker-compose down
# 停止并删除所有数据(⚠️ 谨慎操作)
docker-compose down -v
# 查看资源占用
docker stats- 使用反向代理:建议使用 Nginx 或 Caddy 配置 HTTPS
- 定期备份:定期备份 PostgreSQL 数据卷
- 修改默认端口:在
.env中修改CLIENT_PORT避免端口冲突 - 监控日志:定期检查应用日志,及时发现问题
# 备份数据库
docker exec wedding-postgres pg_dump -U wedding wedding_seating > backup.sql
# 恢复数据库
docker exec -i wedding-postgres psql -U wedding wedding_seating < backup.sql如果项目已经配置了 CI/CD 自动构建,可以直接使用预构建的 Docker 镜像快速部署。
1. 下载生产环境配置文件
# 创建部署目录
mkdir wedding-seating-prod && cd wedding-seating-prod
# 下载配置文件
wget https://raw.githubusercontent.com/znonymous29/wedding-seating/main/docker-compose.prod.yml
wget https://raw.githubusercontent.com/znonymous29/wedding-seating/main/docker.env.example -O .env2. 编辑环境变量
nano .env # 或使用其他编辑器修改镜像地址和必要配置:
# Docker 镜像地址(修改为你的镜像仓库地址)
SERVER_IMAGE=ghcr.io/znonymous29/wedding-seating-server:latest
CLIENT_IMAGE=ghcr.io/znonymous29/wedding-seating-client:latest
# 其他配置同方式一
POSTGRES_PASSWORD=your-secure-password
JWT_SECRET=your-jwt-secret
CLIENT_URL=http://your-domain-or-ip:180803. 启动服务
docker-compose -f docker-compose.prod.yml up -d适合开发者进行功能开发和调试。
- Node.js >= 18
- PostgreSQL >= 14
- npm 或 yarn
1. 克隆项目
git clone https://github.com/znonymous29/wedding-seating.git
cd wedding-seating2. 安装依赖
# 方式A:使用根目录脚本一键安装所有依赖
npm run install:all
# 方式B:手动分别安装
cd client && npm install
cd ../server && npm install3. 配置数据库
确保 PostgreSQL 服务正在运行,然后创建数据库:
CREATE DATABASE wedding_seating;4. 配置环境变量
# 后端环境变量
cd server
cp .env.example .env编辑 server/.env:
DATABASE_URL="postgresql://postgres:password@localhost:5432/wedding_seating"
JWT_SECRET="dev-secret-key-at-least-32-characters"
JWT_REFRESH_SECRET="dev-refresh-secret-at-least-32-characters"
CLIENT_URL="http://localhost:5173"
PORT=3001# 前端环境变量(可选)
cd ../client
cp .env.example .env编辑 client/.env:
VITE_API_URL=http://localhost:3001/api
VITE_SOCKET_URL=http://localhost:30015. 初始化数据库
cd server
npx prisma generate
npx prisma db push6. 启动开发服务器
# 方式A:使用根目录脚本同时启动前后端
npm run dev
# 方式B:分别启动
# 终端1 - 启动后端
cd server && npm run dev
# 终端2 - 启动前端
cd client && npm run dev7. 访问应用
- 前端开发服务器: http://localhost:5173
- 后端 API: http://localhost:3001/api
- 热重载已启用,修改代码自动刷新
- IDE: VS Code + TypeScript/ESLint 插件
- API 测试: Postman 或 Insomnia
- 数据库管理: Prisma Studio (
npx prisma studio) 或 pgAdmin
1. 注册账号
首次访问系统,点击"注册"按钮创建账号。
2. 创建项目
登录后,在项目面板点击"创建项目",填写婚礼基本信息:
- 项目名称(如:我们的婚礼)
- 婚礼日期
- 婚礼场地
3. 导入宾客
进入项目详情,切换到"宾客管理"标签:
- 点击"导入 Excel"按钮
- 下载模板文件,按格式填写宾客信息
- 上传填好的 Excel 文件
💡 Excel 模板格式:姓名 | 人数 | 标签 | 备注 | 电话
也可以手动逐个添加宾客。
4. 设置场地布局
切换到"场地布局"标签:
- 创建区域(如:主桌区、VIP 区、普通区)
- 添加桌位,设置桌号和容量
- 拖拽桌位到合适的位置
- 调整桌位大小和形状
5. 安排座位
切换到"座位安排"标签:
手动安排:
- 从左侧宾客列表拖拽宾客到右侧桌位
- 可以预览每桌人数和剩余座位
- 支持拖拽交换座位
智能推荐:
- 点击某个宾客,查看推荐座位
- 系统会根据标签和约束推荐最佳桌位
自动排座:
- 点击"自动排座"按钮
- 系统自动根据规则分配所有未安排宾客
6. 邀请团队成员
切换到"项目设置"标签:
- 点击"邀请成员"按钮
- 选择角色(协作者/只读)
- 复制邀请链接发送给团队成员
- 团队成员打开链接即可加入项目
7. 查看统计
切换到"数据统计"标签:
- 查看宾客标签分布
- 查看各区域人数统计
- 查看座位安排进度
8. 导出结果
- 导出座位表:在座位安排页面导出 Excel 座位表
- 导出平面图:在场地布局页面导出高清 PNG 平面图
标签管理
- 使用标签给宾客分类(新郎方/新娘方、领导/同事/朋友等)
- 可以按标签筛选和批量操作
- 自动排座会优先同标签宾客安排在一起
排座约束
- 设置"必须同桌"约束:系统会确保这些宾客在同一桌
- 设置"不能同桌"约束:系统会避免这些宾客同桌
- 智能推荐和自动排座都会遵守约束
宾客关系约束
- 设置"必须同桌"关系:确保特定宾客安排在同一桌
- 设置"不能同桌"关系:避免特定宾客同桌
- 在宾客管理页面轻松设置和查看关系
- 智能推荐和自动排座会自动遵守约束规则
实时协作
- 多人同时编辑时,会显示其他成员的在线状态
- 数据自动实时同步,无需手动刷新
- 不同成员的操作互不冲突
wedding-seating/
├── client/ # 前端项目 (React + TypeScript)
│ ├── public/ # 静态资源
│ ├── src/
│ │ ├── components/ # React 组件
│ │ │ ├── GuestManagement.tsx # 宾客管理
│ │ │ ├── SeatingArrangement.tsx # 座位安排
│ │ │ ├── FloorPlan.tsx # 场地布局
│ │ │ ├── Statistics.tsx # 数据统计
│ │ │ └── ProjectSettings.tsx # 项目设置
│ │ ├── pages/ # 页面组件
│ │ │ ├── Login.tsx # 登录页
│ │ │ ├── Dashboard.tsx # 项目面板
│ │ │ └── ProjectDetail.tsx # 项目详情
│ │ ├── services/ # API 服务层
│ │ │ ├── api.ts # HTTP 请求
│ │ │ └── socket.ts # WebSocket 连接
│ │ ├── stores/ # Zustand 状态管理
│ │ │ └── authStore.ts # 认证状态
│ │ ├── App.tsx # 应用入口
│ │ └── main.tsx # React 入口
│ ├── Dockerfile # 前端 Docker 构建文件
│ ├── nginx.conf # Nginx 配置
│ └── package.json # 前端依赖
│
├── server/ # 后端项目 (Express + TypeScript)
│ ├── src/
│ │ ├── routes/ # API 路由
│ │ │ ├── auth.ts # 认证相关
│ │ │ ├── project.ts # 项目管理
│ │ │ ├── guest.ts # 宾客管理
│ │ │ ├── table.ts # 桌位管理
│ │ │ ├── seating.ts # 座位安排
│ │ │ └── area.ts # 区域管理
│ │ ├── middleware/ # Express 中间件
│ │ │ ├── auth.ts # JWT 认证
│ │ │ └── errorHandler.ts # 错误处理
│ │ ├── socket/ # WebSocket 处理
│ │ │ └── index.ts # Socket.IO 逻辑
│ │ └── index.ts # 服务器入口
│ ├── prisma/
│ │ └── schema.prisma # Prisma 数据库模型
│ ├── Dockerfile # 后端 Docker 构建文件
│ └── package.json # 后端依赖
│
├── docs/
│ └── screenshots/ # 项目截图
│
├── docker-compose.yml # 开发环境 Docker 配置
├── docker-compose.prod.yml # 生产环境 Docker 配置
├── docker.env.example # 环境变量示例
├── package.json # 根目录脚本
└── README.md # 项目文档
| 技术 | 版本 | 用途 |
|---|---|---|
| React | 18.x | UI 框架,组件化开发 |
| TypeScript | 5.x | 类型安全,提升代码质量 |
| Vite | 5.x | 快速的构建工具和开发服务器 |
| Ant Design | 5.x | 企业级 UI 组件库 |
| Zustand | 4.x | 轻量级状态管理 |
| React Query | 5.x | 强大的数据请求和缓存 |
| Axios | 1.x | HTTP 客户端 |
| dnd-kit | 6.x | 现代化拖拽库 |
| Socket.IO Client | 4.x | 实时通信客户端 |
| dayjs | 1.x | 日期时间处理 |
| SheetJS | 0.x | Excel 文件处理 |
| 技术 | 版本 | 用途 |
|---|---|---|
| Node.js | 18+ | JavaScript 运行时 |
| Express | 4.x | Web 框架 |
| TypeScript | 5.x | 类型安全 |
| Prisma | 5.x | 现代化 ORM |
| PostgreSQL | 15.x | 关系型数据库 |
| JWT | 9.x | 身份认证 |
| Socket.IO | 4.x | WebSocket 实时通信 |
| bcryptjs | 2.x | 密码加密 |
| cors | 2.x | 跨域资源共享 |
| SheetJS | 0.x | Excel 文件解析 |
| 技术 | 用途 |
|---|---|
| Docker | 容器化部署 |
| Docker Compose | 多容器编排 |
| Nginx | 前端静态文件服务器 |
| GitHub Actions | CI/CD 自动化 |
| 变量名 | 必填 | 默认值 | 说明 |
|---|---|---|---|
DATABASE_URL |
✅ | - | PostgreSQL 数据库连接字符串 格式: postgresql://用户:密码@主机:端口/数据库名 |
JWT_SECRET |
✅ | - | JWT 访问令牌密钥(至少 32 位字符) |
JWT_REFRESH_SECRET |
✅ | - | JWT 刷新令牌密钥(至少 32 位字符) |
JWT_EXPIRES_IN |
❌ | 15m |
访问令牌过期时间 |
JWT_REFRESH_EXPIRES_IN |
❌ | 7d |
刷新令牌过期时间 |
PORT |
❌ | 3001 |
后端服务器端口 |
NODE_ENV |
❌ | development |
运行环境(development/production) |
CLIENT_URL |
✅ | - | 前端访问地址,用于生成邀请链接 生产环境必须修改为实际地址 |
CORS_ORIGIN |
✅ | - | 允许的 CORS 来源,通常与 CLIENT_URL 相同多个来源用逗号分隔 |
示例配置:
# 开发环境
DATABASE_URL="postgresql://postgres:password@localhost:5432/wedding_seating"
JWT_SECRET="dev-jwt-secret-at-least-32-characters-long"
JWT_REFRESH_SECRET="dev-refresh-secret-at-least-32-characters-long"
CLIENT_URL="http://localhost:5173"
CORS_ORIGIN="http://localhost:5173"
PORT=3001
NODE_ENV=development
# 生产环境(Docker)
DATABASE_URL="postgresql://wedding:your-password@postgres:5432/wedding_seating"
JWT_SECRET="production-jwt-secret-random-string-32-chars"
JWT_REFRESH_SECRET="production-refresh-secret-random-string-32-chars"
CLIENT_URL="http://192.168.1.100:18080" # 或使用域名
CORS_ORIGIN="http://192.168.1.100:18080"
PORT=3001
NODE_ENV=production| 变量名 | 必填 | 默认值 | 说明 |
|---|---|---|---|
VITE_API_URL |
❌ | /api |
后端 API 地址 |
VITE_SOCKET_URL |
❌ | '' |
WebSocket 服务地址 |
示例配置:
# 开发环境
VITE_API_URL=http://localhost:3001/api
VITE_SOCKET_URL=http://localhost:3001
# 生产环境(通常使用相对路径,由 Nginx 代理)
VITE_API_URL=/api
VITE_SOCKET_URL=| 变量名 | 必填 | 说明 |
|---|---|---|
SERVER_IMAGE |
✅ | 后端镜像地址(使用预构建镜像时) |
CLIENT_IMAGE |
✅ | 前端镜像地址(使用预构建镜像时) |
POSTGRES_USER |
❌ | 数据库用户名(默认:wedding) |
POSTGRES_PASSWORD |
✅ | 数据库密码(必须修改) |
POSTGRES_DB |
❌ | 数据库名(默认:wedding_seating) |
CLIENT_PORT |
❌ | 前端端口映射(默认:18080) |
JWT_SECRET |
✅ | JWT 密钥 |
JWT_REFRESH_SECRET |
✅ | 刷新令牌密钥 |
CLIENT_URL |
✅ | 前端访问地址(必须修改) |
CORS_ORIGIN |
✅ | CORS 来源(通常与 CLIENT_URL 相同) |
💡 安全提示:
- 生产环境务必修改所有默认密码和密钥
- JWT 密钥建议使用随机生成的长字符串
- 不要将
.env文件提交到版本控制系统
所有 API 接口基础路径为 /api,除了认证接口外,其他接口都需要在请求头中携带 JWT Token:
Authorization: Bearer <access_token>
| 方法 | 路径 | 说明 | 请求体 | 响应 |
|---|---|---|---|---|
POST |
/auth/register |
用户注册 | { email, password, name } |
{ user, accessToken, refreshToken } |
POST |
/auth/login |
用户登录 | { email, password } |
{ user, accessToken, refreshToken } |
POST |
/auth/refresh |
刷新访问令牌 | { refreshToken } |
{ accessToken } |
GET |
/auth/me |
获取当前用户信息 | - | { user } |
| 方法 | 路径 | 说明 | 参数 |
|---|---|---|---|
GET |
/projects |
获取当前用户的所有项目 | - |
POST |
/projects |
创建新项目 | { name, weddingDate, venue } |
GET |
/projects/:id |
获取项目详情(含成员信息) | - |
PUT |
/projects/:id |
更新项目信息 | { name, weddingDate, venue } |
DELETE |
/projects/:id |
删除项目(仅主办人) | - |
| 方法 | 路径 | 说明 | 参数 |
|---|---|---|---|
GET |
/projects/:id/members |
获取项目成员列表 | - |
POST |
/projects/:id/invite |
生成邀请链接 | { role: 'editor' | 'viewer' } |
POST |
/projects/join/:inviteToken |
通过邀请链接加入项目 | - |
PUT |
/projects/:id/members/:userId |
修改成员角色 | { role } |
DELETE |
/projects/:id/members/:userId |
移除成员 | - |
| 方法 | 路径 | 说明 | 参数 |
|---|---|---|---|
GET |
/guests/project/:projectId |
获取项目的所有宾客 | 查询参数:?search=&tags=&assigned= |
POST |
/guests |
添加宾客 | { name, count, tags, note, phone, projectId } |
PUT |
/guests/:id |
更新宾客信息 | { name, count, tags, note, phone } |
DELETE |
/guests/:id |
删除宾客 | - |
POST |
/guests/batch-delete |
批量删除宾客 | { guestIds: string[] } |
POST |
/guests/import/:projectId |
导入 Excel 宾客名单 | 表单数据:file |
GET |
/guests/export/:projectId |
导出宾客名单 Excel | - |
| 方法 | 路径 | 说明 | 参数 |
|---|---|---|---|
GET |
/tables/project/:projectId |
获取项目的所有桌位 | - |
POST |
/tables |
创建单个桌位 | { name, capacity, x, y, projectId, areaId } |
POST |
/tables/batch |
批量创建桌位 | { tables: [...], projectId } |
PUT |
/tables/:id |
更新桌位信息 | { name, capacity, x, y, areaId } |
DELETE |
/tables/:id |
删除桌位 | - |
POST |
/tables/batch-update |
批量更新桌位位置 | { updates: [{ id, x, y }] } |
| 方法 | 路径 | 说明 | 参数 |
|---|---|---|---|
GET |
/areas/project/:projectId |
获取项目的所有区域 | - |
POST |
/areas |
创建区域 | { name, color, projectId } |
PUT |
/areas/:id |
更新区域 | { name, color } |
DELETE |
/areas/:id |
删除区域 | - |
| 方法 | 路径 | 说明 | 参数 |
|---|---|---|---|
POST |
/seating/assign |
安排宾客到桌位 | { guestId, tableId, position } |
DELETE |
/seating/unassign/:guestId |
移除宾客座位 | - |
PUT |
/seating/move |
移动宾客座位 | { guestId, tableId, position } |
POST |
/seating/swap |
交换两个宾客座位 | { guest1Id, guest2Id } |
POST |
/seating/auto-assign |
自动排座 | { projectId, constraints } |
GET |
/seating/suggestions/:guestId |
获取推荐座位 | - |
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/stats/:projectId |
获取项目统计数据(宾客数、桌位数、安排进度等) |
客户端连接到 WebSocket 后,会自动加入项目房间,实时接收以下事件:
| 事件名 | 说明 | 数据 |
|---|---|---|
guest:created |
新增宾客 | { guest } |
guest:updated |
更新宾客 | { guest } |
guest:deleted |
删除宾客 | { guestId } |
table:created |
新增桌位 | { table } |
table:updated |
更新桌位 | { table } |
table:deleted |
删除桌位 | { tableId } |
seating:assigned |
安排座位 | { guest, table } |
seating:unassigned |
移除座位 | { guestId } |
user:online |
用户上线 | { userId, name } |
user:offline |
用户离线 | { userId } |
项目使用 GitHub Actions 自动构建和推送 Docker 镜像到容器镜像仓库。
触发条件:
- 推送代码到
main或master分支 - 创建版本标签(如
v1.0.0、v1.2.3) - 手动触发工作流
构建产物:
- 前端镜像:
ghcr.io/znonymous29/wedding-seating-client:latest - 后端镜像:
ghcr.io/znonymous29/wedding-seating-server:latest - 版本标签:
ghcr.io/znonymous29/wedding-seating-client:v1.0.0
1. 创建工作流文件
在项目根目录创建 .github/workflows/docker-build.yml(参考项目示例)。
2. 配置 Secrets
在 GitHub 仓库的 Settings → Secrets and variables → Actions 中添加:
| Secret 名称 | 说明 | 获取方式 |
|---|---|---|
GHCR_TOKEN |
GitHub 容器镜像仓库令牌 | 个人设置 → Developer settings → Personal access tokens → 勾选 write:packages |
DOCKERHUB_USERNAME |
Docker Hub 用户名(可选) | https://hub.docker.com 注册 |
DOCKERHUB_TOKEN |
Docker Hub Access Token(可选) | Docker Hub → Account Settings → Security |
3. 触发构建
# 方式1:推送到主分支
git push origin main
# 方式2:创建版本标签
git tag v1.0.0
git push origin v1.0.0
# 方式3:在 GitHub Actions 页面手动触发如果已经配置了 CI/CD,可以直接拉取预构建镜像快速部署:
# 1. 创建部署目录
mkdir wedding-seating-deploy && cd wedding-seating-deploy
# 2. 下载配置文件(替换为你的 GitHub 用户名)
wget https://raw.githubusercontent.com/znonymous29/wedding-seating/main/docker-compose.prod.yml
wget https://raw.githubusercontent.com/znonymous29/wedding-seating/main/docker.env.example -O .env
# 3. 编辑 .env 文件
nano .env修改镜像地址和关键配置:
# 修改为你的镜像仓库地址
SERVER_IMAGE=ghcr.io/znonymous29/wedding-seating-server:latest
CLIENT_IMAGE=ghcr.io/znonymous29/wedding-seating-client:latest
# 或使用特定版本
# SERVER_IMAGE=ghcr.io/znonymous29/wedding-seating-server:v1.0.0
# CLIENT_IMAGE=ghcr.io/znonymous29/wedding-seating-client:v1.0.0
# 其他必须修改的配置
POSTGRES_PASSWORD=your-secure-password-here
JWT_SECRET=your-jwt-secret-at-least-32-characters
JWT_REFRESH_SECRET=your-refresh-secret-at-least-32-characters
CLIENT_URL=http://your-domain-or-ip:18080
CORS_ORIGIN=http://your-domain-or-ip:18080# 4. 启动服务
docker-compose -f docker-compose.prod.yml up -d
# 5. 查看服务状态
docker-compose -f docker-compose.prod.yml ps
# 6. 查看日志
docker-compose -f docker-compose.prod.yml logs -f当有新版本发布时,更新部署:
# 1. 拉取最新镜像
docker-compose -f docker-compose.prod.yml pull
# 2. 重启服务
docker-compose -f docker-compose.prod.yml up -d
# 3. 清理旧镜像(可选)
docker image prune -fQ: 邀请链接显示 localhost,其他设备无法访问
问题:生成的邀请链接是 http://localhost:18080/invite/...,手机或其他电脑无法打开。
原因:后端环境变量 CLIENT_URL 未正确配置为实际可访问的地址。
解决方案:
-
查看服务器的 IP 地址:
# Windows ipconfig # Linux/Mac ifconfig # 或 ip addr
-
编辑
.env文件,修改CLIENT_URL:# 使用局域网 IP(适合内网使用) CLIENT_URL=http://192.168.1.100:18080 CORS_ORIGIN=http://192.168.1.100:18080 # 使用域名(适合生产环境) CLIENT_URL=https://wedding.example.com CORS_ORIGIN=https://wedding.example.com # 使用公网 IP(适合外网访问) CLIENT_URL=http://123.45.67.89:18080 CORS_ORIGIN=http://123.45.67.89:18080
-
重启后端服务:
docker-compose restart server
-
重新生成邀请链接即可。
Q: Docker 容器启动失败
常见原因和解决方法:
-
端口被占用
# 查看端口占用情况 netstat -ano | findstr :18080 # Windows lsof -i :18080 # Linux/Mac # 修改 .env 中的 CLIENT_PORT CLIENT_PORT=18090
-
数据库连接失败
# 查看数据库日志 docker-compose logs postgres # 确保数据库服务健康 docker-compose ps
-
磁盘空间不足
# 清理未使用的镜像和容器 docker system prune -a -
环境变量配置错误
# 检查 .env 文件格式 cat .env # 重新从示例文件复制 cp docker.env.example .env
Q: 如何更新到最新版本?
使用 Docker Compose:
# 1. 停止当前服务
docker-compose down
# 2. 拉取最新代码
git pull origin main
# 3. 重新构建并启动
docker-compose up -d --build
# 使用预构建镜像时
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d本地开发环境:
# 1. 更新代码
git pull origin main
# 2. 更新依赖
cd client && npm install
cd ../server && npm install
# 3. 更新数据库(如果有 schema 变更)
cd server
npx prisma generate
npx prisma db push
# 4. 重启服务
npm run devQ: 移动端登录后进入不了 Dashboard
问题:手机浏览器登录成功后,页面一直加载或自动跳转回登录页。
原因:早期版本存在 Zustand 状态恢复(hydration)的时序问题。
解决方案:
更新到最新版本(已修复此问题):
git pull origin main
docker-compose down
docker-compose up -d --build临时解决方案(如果不能更新):
- 清除浏览器缓存和 Cookie
- 使用无痕模式登录
- 尝试使用其他浏览器
Q: 无法上传 Excel 文件
问题:导入宾客时上传 Excel 失败,提示错误。
解决方案:
-
检查文件格式
- ✅ 支持:
.xlsx(Excel 2007+) - ❌ 不支持:
.xls(旧版 Excel)、.csv、.ods
- ✅ 支持:
-
检查文件大小
- 文件大小不超过 10MB
- 建议单次导入不超过 1000 条记录
-
检查模板格式
下载系统提供的模板,确保列名和格式正确:
姓名 人数 标签 备注 电话 张三 2 新郎方,领导 VIP 13800138000 李四 1 新娘方,朋友 13900139000 -
检查服务器日志
docker-compose logs server
Q: 自动排座结果不理想
问题:自动排座功能分配的座位不符合预期。
优化建议:
-
完善宾客标签
- 给宾客打上详细标签(新郎方/新娘方、领导/同事/朋友等)
- 标签相同的宾客会优先安排在一起
-
设置排座约束
- 使用"必须同桌"功能:关系亲密的宾客强制同桌
- 使用"不能同桌"功能:避免不适合同桌的宾客相遇
-
手动调整
- 自动排座后可以手动拖拽微调
- 先自动分配,再手动优化关键位置
-
分批处理
- 先安排 VIP 和主桌
- 再使用自动排座处理普通宾客
Q: 多人协作时数据不同步
问题:团队成员操作后,其他人看不到更新。
检查项:
-
网络连接
- 确保 WebSocket 连接正常
- 打开浏览器控制台,查看是否有连接错误
-
防火墙设置
- 检查服务器防火墙是否允许 WebSocket 连接
- 默认使用 3001 端口
-
浏览器兼容性
- 推荐使用 Chrome、Edge、Firefox、Safari 最新版本
- IE 浏览器不支持
-
刷新页面
- 手动刷新页面(F5)
- 检查是否有控制台错误
Q: 如何备份数据?
Docker 部署环境:
# 1. 备份数据库
docker exec wedding-postgres pg_dump -U wedding wedding_seating > backup-$(date +%Y%m%d).sql
# 2. 备份整个数据卷
docker run --rm -v wedding-seating_postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres-data-$(date +%Y%m%d).tar.gz /data
# 3. 定期备份脚本(Linux)
# 创建 crontab 任务,每天凌晨2点自动备份
0 2 * * * docker exec wedding-postgres pg_dump -U wedding wedding_seating > /backups/wedding-backup-$(date +\%Y\%m\%d).sql恢复数据:
# 从 SQL 文件恢复
docker exec -i wedding-postgres psql -U wedding wedding_seating < backup-20231209.sql
# 从数据卷恢复
docker run --rm -v wedding-seating_postgres_data:/data -v $(pwd):/backup alpine sh -c "cd / && tar xzf /backup/postgres-data-20231209.tar.gz"Q: 如何导出数据?
宾客名单导出:
- 在"宾客管理"页面点击"导出"按钮
- 导出为 Excel 文件,包含所有宾客信息和座位安排
场地布局导出:
- 在"场地布局"页面点击"导出图片"按钮
- 导出为高清 PNG 图片,可直接打印
座位表导出:
- 在"座位安排"页面点击"导出座位表"按钮
- 导出包含所有座位分配信息的 Excel 文件
Q: 系统运行缓慢怎么办?
优化建议:
-
数据库优化
# 清理数据库(谨慎操作) docker exec -it wedding-postgres psql -U wedding wedding_seating -c "VACUUM ANALYZE;"
-
清理 Docker 资源
# 清理未使用的镜像和容器 docker system prune -a # 清理日志 truncate -s 0 $(docker inspect --format='{{.LogPath}}' wedding-server)
-
增加资源限制
编辑
docker-compose.yml,增加资源分配:services: server: deploy: resources: limits: cpus: "2" memory: 2G
-
使用反向代理缓存
使用 Nginx 缓存静态资源,减轻后端压力。
Q: 忘记密码怎么办?
目前系统暂未实现找回密码功能。如果忘记密码,可以:
-
重新注册账号(简单方案)
-
数据库直接修改(需要数据库访问权限)
# 生成新密码的哈希值(使用 bcryptjs) node -e "console.log(require('bcryptjs').hashSync('new_password', 10))" # 更新数据库 docker exec -it wedding-postgres psql -U wedding wedding_seating UPDATE "User" SET password = '$2a$10$...' WHERE email = 'your@email.com';
-
等待未来版本
后续版本将添加邮箱找回密码功能。
Q: 如何卸载系统?
完全删除(包括数据):
# 停止并删除所有容器和数据卷
docker-compose down -v
# 删除镜像
docker rmi $(docker images 'wedding-seating*' -q)
# 删除项目目录
cd ..
rm -rf wedding-seating仅停止服务(保留数据):
# 停止服务
docker-compose stop
# 或删除容器但保留数据卷
docker-compose down如果遇到其他问题,欢迎提交 Issue。
- 用户认证和授权系统
- 项目管理和多人协作
- 宾客管理(增删改查、Excel 导入导出)
- 可视化场地布局编辑器
- 拖拽式座位安排
- 智能推荐和自动排座
- 实时数据同步(WebSocket)
- 数据统计和可视化
- Docker 容器化部署
- 响应式设计(支持移动端)
- 邮箱找回密码功能
- 更多统计图表和分析
- 座位方案版本管理
- 导出 PDF 格式座位表
- 微信小程序版本
- 宾客签到功能
- 座位二维码生成
- 邮件/短信邀请通知
- 多语言支持(英文等)
- 主题定制功能
- 座位偏好设置(靠窗、过道等)
- AI 智能推荐优化
欢迎贡献代码、报告 Bug 或提出新功能建议!
-
Fork 本仓库
-
创建特性分支
git checkout -b feature/amazing-feature
-
提交更改
git commit -m 'Add some amazing feature' -
推送到分支
git push origin feature/amazing-feature
-
提交 Pull Request
- 前端:遵循 ESLint 配置,使用 TypeScript 严格模式
- 后端:遵循 Node.js 最佳实践,所有 API 需要类型定义
- 提交信息:使用语义化提交信息(feat/fix/docs/style/refactor/test/chore)
- 测试:新功能需要添加相应测试用例
提交 Bug 时,请包含:
- 操作系统和浏览器版本
- 详细的复现步骤
- 预期行为和实际行为
- 相关截图或错误日志
提交功能建议时,请说明:
- 功能的使用场景和价值
- 详细的功能描述
- 可能的实现方式(如果有)
本项目使用了以下优秀的开源项目:
- React - 用户界面框架
- Ant Design - 企业级 UI 组件库
- Express - Web 应用框架
- Prisma - 下一代 ORM
- Socket.IO - 实时通信引擎
- dnd-kit - 现代化拖拽工具库
- PostgreSQL - 强大的关系型数据库
感谢所有贡献者的付出!
如果这个项目对你有帮助,请给我们一个 Star ⭐
本项目采用 MIT License 开源协议。
MIT License
Copyright (c) 2024 Wedding Seating Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
用 ❤️ 制作 | Made with Love
让婚礼座位安排变得简单而美好





