No description
  • Go 52.2%
  • Vue 40%
  • JavaScript 4.6%
  • CSS 2.9%
  • Dockerfile 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
xiaoman1221 bf5413af0a feat: 添加 Docker 支持(Dockerfile + docker-compose.yml)
- 多阶段 Dockerfile:node:24-alpine 构建前端 → golang:1.27-alpine 编译纯静态 Go 二进制(SQLite 无 CGO)→ alpine:3.20 运行镜像
- 运行镜像内置前端产物并由后端托管 SPA,包含 CA 证书与 Asia/Shanghai 时区
- docker-compose.yml:一键启动、端口映射、健康检查(wget /api/system/info)、SQLite 与上传文件持久化到命名卷 /data
- .dockerignore:排除 node_modules/dist/数据库/上传文件等,缩小构建上下文
- 已验证:docker build 成功、容器内 API 与 SPA 正常响应、docker compose up 数据落盘
- README 补充 Docker 部署章节(含 JWT_SECRET 生产配置说明)
2026-08-30 06:53:46 +08:00
config feat: 多角色权限、SMTP/短信、云存储与 OauthGo 第三方登录 2026-08-29 23:21:18 +08:00
database feat: 消费明细公开收集链接与附件上传 2026-08-30 04:20:24 +08:00
handlers fix: /api/teams 创建团队报「参数错误」——支持 YYYY-MM-DD 日期并提示具体参数 2026-08-30 04:24:03 +08:00
middleware feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
models feat: 消费明细公开收集链接与附件上传 2026-08-30 04:20:24 +08:00
router feat: 消费明细公开收集链接与附件上传 2026-08-30 04:20:24 +08:00
services feat: 高德地图选点与自定义团型 2026-08-30 04:07:14 +08:00
storage/uploads feat: 多角色权限、SMTP/短信、云存储与 OauthGo 第三方登录 2026-08-29 23:21:18 +08:00
validators feat: 多角色权限、SMTP/短信、云存储与 OauthGo 第三方登录 2026-08-29 23:21:18 +08:00
web feat: 消费明细公开收集链接与附件上传 2026-08-30 04:20:24 +08:00
.dockerignore feat: 添加 Docker 支持(Dockerfile + docker-compose.yml) 2026-08-30 06:53:46 +08:00
.gitignore feat: 多角色权限、SMTP/短信、云存储与 OauthGo 第三方登录 2026-08-29 23:21:18 +08:00
collect_test.go feat: 消费明细公开收集链接与附件上传 2026-08-30 04:20:24 +08:00
dicts_test.go fix: /api/teams 创建团队报「参数错误」——支持 YYYY-MM-DD 日期并提示具体参数 2026-08-30 04:24:03 +08:00
docker-compose.yml feat: 添加 Docker 支持(Dockerfile + docker-compose.yml) 2026-08-30 06:53:46 +08:00
Dockerfile feat: 添加 Docker 支持(Dockerfile + docker-compose.yml) 2026-08-30 06:53:46 +08:00
go.mod feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
go.sum feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
main.go feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
main_test.go feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
passkey_test.go feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
profile_test.go feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
rbac_test.go feat: 账号体系与登录能力升级 2026-08-30 03:52:18 +08:00
README.md feat: 添加 Docker 支持(Dockerfile + docker-compose.yml) 2026-08-30 06:53:46 +08:00

团队档案管理系统(TravelManager)

一个面向团队运营场景的多角色 Web 管理后台:旅行社、合同、团队预订单、消费核算、档案归档全流程管理。内置用户与角色权限体系(管理员 / 旅行社 / 负责人),支持 SMTP 邮件、短信(短信宝 / 阿里云 SNS / Webhook)、多云端存储(本地 / 腾讯云 COS / 又拍云 / 阿里云 OSS / S3 兼容)以及第三方登录(彩虹聚合登录 / OauthGo REST API),白天 / 黑夜 / 自动三档主题。

系统名称、水印、存储、发信等均可通过「系统设置」动态配置,不绑定任何特定地区或景区。

功能特性

  • 用户与角色权限:管理员、旅行社、负责人三种角色,前端菜单与后端接口双重收口,数据严格隔离
  • 旅行社管理:合作旅行社、老板 / 计调联系方式维护,手机号与邮箱格式校验,CSV 导入导出
  • 合同管理:合同拍照 / PDF 上传存档,状态流转与回收站恢复,CSV 导入导出
  • 团队统计:预订单录入、抵达 / 离开日期、带队负责人、消费明细自动核算总花费;团型与消费分类均可自定义,支持高德地图选点记录团队地点
  • 消费收集链接:团队可生成公开收集链接发给他人补录消费(含票据 / 照片附件),可随时开启 / 关闭 / 重置;附件大小与格式在系统设置中统一控制
  • 档案归档:团队附件分类归档(预订单 / 合同 / 票据 / 行程单 / 凭证),Word 简报一键导出
  • 数据仪表盘:按年 / 月统计团型、客源地、团队数与总消费,按角色自动过滤
  • 高德地图选点:在「系统设置」配置高德 Web JS API Key 后,团队录入与详情页支持地图搜索 / 点击选点并自动反查地名
  • 通知接入:SMTP 邮件(STARTTLS / 隐式 SSL)、短信(短信宝 / 阿里云短信签名直连 / 通用 Webhook)
  • 云存储:本地磁盘、腾讯云 COS、又拍云、阿里云 OSS、S3 兼容存储(AWS / MinIO / 华为云 OBS / 七牛云等)五种存储可切换,上传下载自动分发
  • 个人主页:每个用户可在「个人主页」维护姓名 / 昵称 / 手机号 / 邮箱 / 头像,绑定或解绑 QQ / 微信 / 微博等第三方登录、绑定 / 删除通行密钥(Passkey),并修改或首次设置登录密码
  • 注册与找回密码:系统首个用户注册即成为超级管理员;忘记密码时通过绑定邮箱 / 手机号发送验证码自助重置
  • 通行密钥登录:支持 WebAuthn / FIDO2 无密码登录(设备指纹 / 人脸 / 安全密钥),登录页与个人主页均可绑定
  • 第三方登录:支持「彩虹聚合登录」与「OauthGo REST API」两种接入方式,统一对接 QQ / 微信 / 微博等平台,自动注册账号并绑定角色;登录页与个人主页展示的平台由系统设置决定
  • 审计日志:登录、查看、下载、增删改、导入导出全流程留痕
  • 主题系统:白天 / 黑夜 / 跟随系统三档切换,品牌色与设计系统可全局定制

技术栈

后端

  • Go 1.27 + Gin
  • GORM + SQLite(纯 Go 驱动,无需 CGO)
  • JWT(HS256)+ bcrypt
  • 标准库 net/smtp 发信,HTTP 签名直连云存储与短信网关

前端

  • Vue 3 + Vite
  • Element Plus
  • Pinia 状态管理
  • Vue Router

目录结构

TravelManager/
├── main.go                 # 服务入口
├── config/                 # 配置加载(环境变量覆盖)
├── database/               # SQLite 初始化、自动建表、超级管理员保障
├── models/                 # 数据模型(用户 / 旅行社 / 合同 / 团队 / 消费 / 附件 / 日志 / 设置)
├── middleware/             # JWT 认证、角色鉴权、CORS、审计
├── handlers/               # 全部 API handler(含 RBAC 数据作用域)
├── services/               # Word 导出、CSV、SMTP、短信、云存储、第三方登录
├── validators/             # 手机号 / 邮箱自定义校验
├── router/                 # 路由注册
├── web/                    # Vue 3 前端工程
│   └── src/
│       ├── views/          # 登录、仪表盘、旅行社、合同、团队、用户、日志、设置
│       ├── stores/         # 认证 / 系统名 / 主题
│       └── api/            # 接口封装
└── storage/uploads/        # 本地存储目录

快速开始

后端

go run .

默认监听 http://localhost:8080。系统不内置任何账号:首次启动后,第一个注册的用户自动成为超级管理员(注册入口仅在系统尚无用户时开放,之后由管理员统一创建账号)。

前端(开发模式)

cd web
npm install
npm run dev

前端开发服务器默认 http://localhost:5173(Vite 已配置代理到后端)。构建后后端会自动托管 web/dist:

cd web && npm run build
cd .. && go run .

环境变量

变量 默认值 说明
PORT 8080 服务端口
DB_PATH travelmanager.db SQLite 数据库文件
JWT_SECRET travel-manager-dev-secret JWT 签名密钥(生产必改)
UPLOAD_DIR storage/uploads 本地存储根目录

Docker 部署

项目内置 Dockerfile(多阶段构建:前端 → Go 编译 → Alpine 运行镜像)与 docker-compose.yml,一条命令启动:

docker compose up -d --build
  • 访问 http://localhost:8080;SQLite 数据库与上传文件持久化在命名卷 travelmanager-data(挂载于容器 /data)
  • 生产环境务必通过 .env 或环境变量覆盖 JWT_SECRET:
# .env
JWT_SECRET=换成足够长的随机字符串
docker compose up -d          # 应用新密钥后重建
docker compose logs -f        # 查看日志
docker compose down           # 停止(数据保留在卷中)
docker compose down -v        # 停止并删除数据卷

镜像包含 CA 证书与 Asia/Shanghai 时区,可直接访问高德地图、短信、邮件等外部服务。

角色与权限矩阵

能力 管理员 旅行社 负责人
用户管理 / 系统设置 / 操作日志 ✅ ❌ ❌
新增 / 删除旅行社 ✅ ❌ ❌
查看旅行社 全部 仅本社 仅本人带队关联
合同管理 全部 仅本社 仅本人带队关联(只读)
团队录入 / 修改 / 归档 全部 仅本社 仅本人带队团队
团队删除 ✅ ✅(仅本社) ❌
消费录入 / 修改 ✅ ✅(仅本社) ✅(仅本人带队)
附件上传 / 下载 ✅ ✅(仅本社) ✅(仅本人带队)
CSV 导入 ✅ ✅(仅本社,导入旅行社除外) ❌
CSV 导出 全部 仅本社 仅本人带队
统计仪表盘 全部 仅本社 仅本人带队

超级管理员:系统首个注册用户自动获得(无内置账号),拥有全部权限;不可通过接口创建、提权、降级、停用或删除,防止误操作导致系统失守。

负责人角色的数据范围由其账号「手机号 / 邮箱」与团队档案中的「带队负责人手机号 / 邮箱」匹配决定;第三方登录自动注册的账号默认负责人角色,管理员需为其补充手机号 / 邮箱以完成团队绑定。

用户管理

  • 管理员在「用户管理」页新增 / 编辑 / 停用 / 删除用户,可为旅行社角色绑定具体旅行社
  • 新增用户时校验用户名唯一、密码 ≥ 6 位、手机号(11 位或座机)与邮箱格式
  • 管理员可重置任意用户密码;用户可在「个人主页」维护个人资料、上传头像、绑定 / 解绑第三方登录、绑定 / 删除通行密钥,并修改密码(第三方账号首次设置密码无需原密码)
  • 忘记密码:登录页「忘记密码?」→ 输入用户名 / 手机号 / 邮箱,向绑定邮箱(SMTP)或手机(短信)发送 6 位验证码 → 校验后设置新密码
  • 禁止删除 / 停用 / 降级自己的账号,防止误操作导致管理员失联
  • 超级管理员为保留角色,任何接口均不可创建、分配、降级、停用或删除该角色;系统存在用户后注册入口关闭,账号由管理员统一创建

通知接入

SMTP 邮件

在「系统设置 → SMTP 邮件发信」配置后保存,可发送测试邮件验证。

配置项 说明
SMTP 服务器 / 端口 如 smtp.example.com、25 / 465 / 587
用户名 / 密码 发信账号与密码(或授权码)
发件人地址 默认取用户名
加密方式 STARTTLS(587)/ SSL(465)/ 无加密(25)

短信(SNS)

「系统设置 → 短信发送」支持四种模式:

模式 说明
关闭 不发送
短信宝 HTTP GET 直发 http://api.smsbao.com/sms,配置账号 / 密码,内容为「前缀 + 验证码」
阿里云短信 使用 RPC 签名(HMAC-SHA1)直连 dysmsapi.aliyuncs.com 的 SendSms 接口
Webhook 向自定义网关 POST JSON(含 phone、sign_name、template_code、template_params)

短信宝在设置中「账号」对应 AccessKey 字段、「密码」对应 AccessSecret 字段(接口用其 MD5 值),「短信内容前缀」对应 SignName 字段;接口返回 0 表示发送成功,否则为错误码。 阿里云短信需配置 AccessKey / AccessSecret、签名名称与模板 Code;测试短信固定验证码 123456。

云存储

「系统设置 → 文件存储」支持五种类型,上传后文件路径 / 访问 URL 自动写入档案,下载时自动分发:

类型 配置 说明
本地存储 无需配置 保存至 UPLOAD_DIR
腾讯云 COS SecretId / SecretKey / Bucket / Region q-signature 签名直传
又拍云 服务名 / 操作员 / 操作员密码 / 访问域名 REST API Upyun 签名直传
阿里云 OSS Bucket / Endpoint / AccessKey ID / Secret OSS V1 签名直传
S3 兼容存储 Bucket / Endpoint / Region / AccessKey / SecretKey / 访问域名 / Path-Style AWS Signature V4 签名直传,兼容 AWS S3、MinIO、华为云 OBS、七牛云、Cloudflare R2、百度 BOS 等

当前云存储与短信网关均以原生 HTTP 签名实现,不依赖云厂商 SDK(离线环境亦可编译运行)。如需使用官方 SDK(分片上传、断点续传等高级能力),可在有网环境引入官方 Go SDK 替换 services/storage.go 与 services/sms.go 中的对应实现。

第三方登录

支持两种接入方式,均使用同一套 connect.php 兼容协议,仅在「网关地址」上不同:

  • 彩虹聚合登录:官方聚合登录网关,注册应用后获得 AppID / AppKey
  • OauthGo REST API:自建兼容网关(参考 https://github.com/xiaoman1221/OauthGo),部署后统一对接 QQ、微信、微博等平台

部署与配置

  1. 在「系统设置 → 第三方登录」选择接入方式(彩虹聚合登录 / OauthGo REST API)
  2. 在对应平台创建应用,获得 AppID 与 AppKey
  3. 在平台应用配置中添加本系统的回调地址白名单: https://your-domain/api/auth/oauth/callback
  4. 在本系统「系统设置 → 第三方登录」填写:
配置项 说明
启用第三方登录 开启后登录页显示第三方登录入口
登录平台 勾选 QQ / 微信 / 微博等平台,登录页与个人主页据此展示入口
接入方式 彩虹聚合登录 / OauthGo REST API(协议一致,仅网关地址不同)
AppID / AppKey 应用凭据
网关地址 彩虹聚合登录如 https://api.1v.fit;OauthGo REST API 如 https://o.1v.fit
回调地址 系统根据当前域名自动拼接(https://当前域名/api/auth/oauth/callback),不可手动配置;请将页面展示的地址加入平台回调白名单

协议流程

  1. 用户点击第三方登录 → 本系统请求 GET {网关}/connect.php?act=login&appid=..&appkey=..&type=qq|wechat|..&redirect_uri=.. 获取跳转地址
  2. 平台授权后回调 redirect_uri?state=..&code=..&sign=..
  3. 本系统用一次性 code 请求 GET {网关}/connect.php?act=callback&appid=..&appkey=..&type=..&code=.. 换取用户信息(social_uid、nickname、faceimg 等)
  4. 按 provider + social_uid 自动注册或登录(新账号默认「负责人」角色;系统尚无用户时,首个自动注册账号为超级管理员),签发站内 JWT 并回跳前端

账号绑定

  • 已登录用户在「个人主页 → 第三方登录绑定」可为当前账号绑定多个平台(生成一次性票据后跳转授权,回调自动归属到当前账号)
  • 绑定后可用对应平台快捷登录;解绑受保护:无登录密码且仅剩一种登录方式时需先设置密码再解绑
  • 第三方登录自动注册的账号无密码,可在个人主页「设置密码」后使用账号密码登录

API 一览

模块 方法 & 路径 权限
系统 GET /api/system/info 公开
系统字典 GET /api/system/dicts(团型、消费分类、高德 Key) 登录
登录 POST /api/auth/login 公开
注册 POST /api/auth/register 公开(仅系统无用户时,首个注册用户为超级管理员)
找回密码 POST /api/auth/forgot-password、POST /api/auth/reset-password 公开
通行密钥登录 GET /api/auth/passkey/begin-login、POST /api/auth/passkey/complete-login 公开
第三方登录 GET /api/auth/oauth/authorize?type=qq 公开
第三方登录 GET /api/auth/oauth/callback?type=..&code=.. 公开
当前用户 GET /api/auth/me、POST /api/auth/logout 登录
个人主页 PUT /api/users/me、POST /api/users/me/avatar、PUT /api/users/me/password 登录
第三方绑定 POST /api/users/me/oauth/ticket、DELETE /api/users/me/oauth/:provider 登录
通行密钥 GET /api/passkeys、POST /api/passkeys/begin-register、POST /api/passkeys/complete-register、DELETE /api/passkeys/:id 登录
用户管理 GET/POST /api/users、PUT/DELETE /api/users/:id 管理员
角色字典 GET /api/users/roles 管理员
重置密码 POST /api/users/:id/reset-password 管理员
旅行社 GET/POST /api/agents、GET/PUT/DELETE /api/agents/:id 管理员(查看按角色过滤)
合同 GET/POST /api/contracts、GET/PUT/DELETE /api/contracts/:id、POST /api/contracts/:id/restore 按角色
团队 GET/POST /api/teams、GET/PUT/DELETE /api/teams/:id、POST /api/teams/:id/archive 按角色
消费 POST /api/teams/:id/expenses、PUT/DELETE /api/teams/:id/expenses/:eid 按角色
消费附件 POST /api/teams/:id/expenses/:eid/attachments、GET .../download、DELETE ... 按角色
消费收集 PUT /api/teams/:id/collect 按角色
公开收集 GET /api/public/collect/:token、POST /api/public/collect/:token/expenses 公开(凭令牌)
附件 POST /api/teams/:id/attachments、GET /api/teams/:id/attachments/:aid/download 按角色
导出 GET /api/teams/:id/export(Word)、GET /api/{agents,contracts,teams}/export(CSV) 按角色
导入 POST /api/{agents,contracts,teams}/import 管理员 / 旅行社
统计 GET /api/stats/summary?year=..&month=.. 按角色
设置 GET/PUT /api/settings、POST /api/settings/test-mail、POST /api/settings/test-sms 管理员
日志 GET /api/logs 管理员

响应统一为 {"code": 0, "message": "ok", "data": ...};业务错误返回对应 HTTP 状态码与 message。

CSV 导入导出

导入文件需为 UTF-8 编码(建议带 BOM),表头见导出文件的列名;系统按表头中文名匹配,自动跳过手机号 / 邮箱不合法的行并返回错误明细。团队导入支持日期(YYYY-MM-DD)、状态中文(预订中 / 接待中 / 已归档)与旅行社名称自动匹配。

测试

export PATH="$HOME/sdk/go1.27.0/bin:$PATH"
export GOPROXY=off GOSUMDB=off GOFLAGS=-mod=mod
go test ./...

测试覆盖:登录与会话、团队 / 消费 / 统计 / 导出全流程、RBAC 权限隔离(角色越权 403、数据范围过滤、停用账号拦截)、设置持久化、短信(短信宝 Mock 网关)、第三方登录全链路(内存 Mock 网关)。

已知限制与后续计划

  • 云存储与短信使用原生 HTTP 签名实现,未接入云厂商官方 SDK(分片 / 断点续传等高级能力可在有网环境引入后替换)
  • 第三方登录回调中的 sign 参数暂未做本地二次校验,依赖一次性 code 与 HTTPS 保证安全
  • 用户头像与 OAuth 头像未同步至页面展示,可后续补充
  • 通行密钥(WebAuthn)依赖浏览器安全上下文:需通过 HTTPS 或 localhost 访问;RPID 取当前访问域名,更换域名后需重新绑定
  • 短信模板参数目前以 JSON 字符串透传,按需扩展站内通知场景(如密码重置、团队归档提醒)