| 基础URL | https://photobooth.show |
| 认证方式 | Session / Cookie 认证(PHPSESSID) |
| 字符编码 | UTF-8 |
| 内容格式 | JSON |
/auth/doLogin
用户登录接口,支持用户名或邮箱登录。登录成功后服务端会设置 PHPSESSID Cookie,后续请求需携带此 Cookie 进行身份认证。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
username | string | 是 | 用户名或邮箱 |
password | string | 是 | 明文密码 |
POST /auth/doLogin
Content-Type: application/x-www-form-urlencoded
username=admin&password=123456
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 1 成功,0 失败 |
msg | string | 提示信息 |
登录成功:
{
"code": 1,
"msg": "登录成功"
}
用户名或密码错误:
{
"code": 0,
"msg": "用户名或密码错误"
}
账号已被禁用:
{
"code": 0,
"msg": "账号已被禁用"
}
/auth/doRegister
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
username | string | 是 | 用户名(唯一) |
email | string | 是 | 邮箱(唯一) |
password | string | 是 | 密码 |
repassword | string | 是 | 确认密码(需与 password 一致) |
// 注册成功
{"code": 1, "msg": "注册成功,请登录"}
// 两次密码不一致
{"code": 0, "msg": "两次密码不一致"}
// 用户名已存在
{"code": 0, "msg": "用户名已存在"}
// 邮箱已被注册
{"code": 0, "msg": "邮箱已被注册"}
/auth/logout
清除服务端会话,客户端也需清除本地 Cookie。
登录成功后服务端在 Set-Cookie 响应头返回 PHPSESSID,Android 客户端需使用 CookieJar(如 OkHttp 的 PersistentCookieJar)自动管理 Cookie,后续所有请求都需携带此 Cookie 才能通过认证。
// build.gradle (app)
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
val cookieJar = PersistentCookieJar(
SetCookieCache(),
SharedPrefsCookiePersistor(context)
)
val client = OkHttpClient.Builder()
.cookieJar(cookieJar)
.build()
// 登录请求
val formBody = FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build()
val request = Request.Builder()
.url("https://photobooth.show/auth/doLogin")
.post(formBody)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
val body = JSONObject(response.body?.string() ?: "{}")
val code = body.getInt("code")
val msg = body.getString("msg")
// Cookie 已由 CookieJar 自动保存,后续请求自动附带
}
override fun onFailure(call: Call, e: IOException) {
// 网络异常处理
}
})
Android 端拍照机需要将活动数据同步到服务器,以下接口用于数据上传与同步。推荐在每次拍照结束后自动调用上传接口。
/api/uploadEvent
将 Android 端创建的活动上传到服务器。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 活动名称 |
template_path | string | 否 | 模板路径,多个用逗号拼接 |
countdown_seconds | int | 否 | 倒计时秒数,默认 5 |
is_paid | int | 否 | 是否付费(0/1),默认 0 |
time_slots | string/array | 否 | 时间段 JSON 数组(见下方说明) |
[
{
"slot_date": "2026-07-03",
"start_time": "09:00",
"end_time": "18:00"
}
]
POST /api/uploadEvent
Content-Type: application/json
{
"name": "暑期嘉年华",
"template_path": "tpl_summer.png,tpl_fun.png",
"countdown_seconds": 5,
"is_paid": 0,
"time_slots": [
{"slot_date": "2026-07-10", "start_time": "09:00", "end_time": "12:00"},
{"slot_date": "2026-07-10", "start_time": "14:00", "end_time": "18:00"}
]
}
{
"code": 1,
"msg": "活动上传成功",
"data": {
"event_id": 1
}
}
/api/uploadRecord
上传一次完整的拍摄记录,包含拍摄时间段和照片。照片通过 photos[] multipart 文件字段上传。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
event_id | int | 是 | 关联的活动 ID |
start_time | string | 是 | 开始拍摄时间(yyyy-MM-dd HH:mm:ss) |
end_time | string | 否 | 结束拍摄时间(yyyy-MM-dd HH:mm:ss) |
print_count | int | 否 | 累计打印张数 |
photos[] | file[] | 否 | 照片文件数组 |
POST /api/uploadRecord
Content-Type: multipart/form-data; boundary=----boundary
--boundary
Content-Disposition: form-data; name="event_id"
1
--boundary
Content-Disposition: form-data; name="start_time"
2026-07-10 10:00:00
--boundary
Content-Disposition: form-data; name="end_time"
2026-07-10 10:30:00
--boundary
Content-Disposition: form-data; name="print_count"
3
--boundary
Content-Disposition: form-data; name="photos[]"; filename="photo1.jpg"
Content-Type: image/jpeg
(binary data)
--boundary
Content-Disposition: form-data; name="photos[]"; filename="photo2.jpg"
Content-Type: image/jpeg
(binary data)
--boundary--
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("event_id", eventId.toString())
.addFormDataPart("start_time", startTime)
.addFormDataPart("end_time", endTime ?: "")
.addFormDataPart("print_count", printCount.toString())
photoFiles.forEach { file ->
requestBody.addFormDataPart(
"photos[]",
file.name,
file.asRequestBody("image/jpeg".toMediaType())
)
}
val request = Request.Builder()
.url("https://photobooth.show/api/uploadRecord")
.post(requestBody.build())
.build()
{
"code": 1,
"msg": "拍摄记录上传成功",
"data": {
"record_id": 1,
"photo_count": 2
}
}
/api/uploadPhoto
通过 multipart/form-data 上传单张照片文件到已有拍摄记录。适用于先创建记录再逐张上传照片的场景。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
record_id | int | 是 | 拍摄记录 ID |
photo | file | 是 | 照片文件 |
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("record_id", recordId.toString())
.addFormDataPart("photo", file.name, file.asRequestBody("image/jpeg".toMediaType()))
.build()
val request = Request.Builder()
.url("https://photobooth.show/api/uploadPhoto")
.post(requestBody)
.build()
{
"code": 1,
"msg": "上传成功",
"data": {
"photo_url": "/uploads/photos/abc123.jpg"
}
}
/api/uploadPhotos
通过 multipart/form-data 一次性上传多张照片到已有拍摄记录。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
record_id | int | 是 | 拍摄记录 ID |
photos[] | file[] | 是 | 照片文件数组,可传多个 |
val builder = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("record_id", recordId.toString())
photoFiles.forEach { file ->
builder.addFormDataPart(
"photos[]",
file.name,
file.asRequestBody("image/jpeg".toMediaType())
)
}
val request = Request.Builder()
.url("https://photobooth.show/api/uploadPhotos")
.post(builder.build())
.build()
{
"code": 1,
"msg": "上传成功",
"data": {
"uploaded": 3,
"photos": [
"/uploads/photos/abc.jpg",
"/uploads/photos/def.jpg",
"/uploads/photos/ghi.jpg"
]
}
}
/api/syncRecords
获取指定活动的所有拍摄记录及照片列表,用于 Android 端数据恢复。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
event_id | int | 是 | 活动 ID |
{
"code": 1,
"data": [
{
"id": 1,
"event_id": 1,
"start_time": "2026-07-10 10:00:00",
"end_time": "2026-07-10 10:30:00",
"print_count": 3,
"photo_count": 2,
"photos": [
{"photo_url": "/uploads/photos/001.jpg"},
{"photo_url": "/uploads/photos/002.jpg"}
]
}
]
}
/api/getEvents
获取服务器上所有启用状态的活动列表,含时间段信息。
/api/getEventDetail?id=1
获取单个活动的完整信息,包含时间段、拍摄记录及照片。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | int | 是 | 活动 ID |
/api/getShareUrl
为指定拍摄记录生成分享链接。首次调用自动生成唯一 token,后续调用返回相同链接(幂等)。分享页面可查看该记录的所有照片及活动信息。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
record_id | int | 是 | 拍摄记录 ID |
{
"code": 1,
"msg": "获取成功",
"data": {
"share_url": "https://photobooth.show/share/55dd90208f9244b53d10eba5952544be",
"share_token": "55dd90208f9244b53d10eba5952544be"
}
}
生成的 share_url 可直接在浏览器中打开,展示该拍摄记录的所有照片及活动信息,无需登录即可查看。
Android 端本地存储结构与服务器数据库一致,便于双向同步。
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 主键 |
name | string | 活动名称 |
template_path | string | 模板路径,多个用逗号拼接 |
countdown_seconds | int | 倒计时秒数 |
is_paid | int | 是否付费(0/1) |
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 主键 |
event_id | int | 关联 events.id |
slot_date | date | 日期(yyyy-MM-dd) |
start_time | time | 开始时间(HH:mm) |
end_time | time | 结束时间(HH:mm) |
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 主键 |
event_id | int | 关联 events.id |
start_time | datetime | 开始拍摄时间 |
end_time | datetime | 结束拍摄时间 |
print_count | int | 累计打印张数 |
photo_count | int | 照片数量 |
sync_status | tinyint | 同步状态 |
share_token | string | 分享链接 token(唯一) |
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 主键 |
record_id | int | 关联 records.id |
photo_url | string | 照片 URL |
thumbnail_url | string | 缩略图 URL |
/auth/do_login(下划线),但服务端路由定义为 /auth/doLogin(驼峰)。Android 端请使用驼峰路径 /auth/doLogin,如 404 请联系后端确认。photos[] 字段上传,上传后保存在 /uploads/photos/ 目录,文件名使用 md5(microtime + 原文件名).原扩展名 生成。