Files
qitongxue-api/api/admin/v1/event.go
2026-09-29 10:57:01 +08:00

428 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package v1
import "github.com/gogf/gf/v2/frame/g"
// ============================================================================
// 管理端「年会座次」域(企业 / 员工 / 活动 / 桌 / 座)
// 依据:架构-2026-09-18 §5.2 A1–A17、§5.3 骨架。
// 导入两段式(A6–A8)与小程序码(A18)、查座审计(A19)由 T09/T10 实现。
// ============================================================================
// ===== 企业 =====
type EnterpriseItem struct {
Id int64 `json:"id"`
Name string `json:"name"`
Contact string `json:"contact"`
Remark string `json:"remark"`
Status int `json:"status"`
EmpCount int64 `json:"emp_count"` // 员工数
}
type EnterpriseListReq struct {
g.Meta `path:"/event/enterprise/list" method:"get" tags:"event" summary:"企业列表"`
Keyword string `json:"keyword"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
type EnterpriseListRes struct {
List []EnterpriseItem `json:"list"`
Total int `json:"total"`
}
type EnterpriseSaveReq struct {
g.Meta `path:"/event/enterprise/save" method:"post" tags:"event" summary:"保存企业"`
Id int64 `json:"id"`
Name string `v:"required|length:1,128#企业名称不能为空" json:"name"`
Contact string `json:"contact"`
Remark string `json:"remark"`
Status int `json:"status"`
}
type EnterpriseSaveRes struct {
Id int64 `json:"id"`
}
// ===== 员工 =====
type EmployeeItem struct {
Id int64 `json:"id"`
Name string `json:"name"`
Phone string `json:"phone"`
Dept string `json:"dept"`
Remark string `json:"remark"`
Status int `json:"status"`
InEvent bool `json:"in_event"` // 是否已在当前活动候场名单
ExcludeAssign int `json:"exclude_assign"` // 1=不参与排座(仅 in_event 时有意义)
}
type EmployeeListReq struct {
g.Meta `path:"/event/employee/list" method:"get" tags:"event" summary:"员工库列表"`
EnterpriseId int64 `json:"enterprise_id"`
EventId int64 `json:"event_id"`
Keyword string `json:"keyword"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
type EmployeeListRes struct {
List []EmployeeItem `json:"list"`
Total int `json:"total"`
}
// EmployeeSaveReq 手工加人(临时人员)。EventId > 0 时同时纳入该活动候场名单。
type EmployeeSaveReq struct {
g.Meta `path:"/event/employee/save" method:"post" tags:"event" summary:"新增/修改员工"`
Id int64 `json:"id"`
EnterpriseId int64 `v:"required#请选择企业" json:"enterprise_id"`
EventId int64 `json:"event_id"`
Name string `v:"required|length:1,64#姓名不能为空" json:"name"`
Phone string `v:"required|length:6,20#手机号格式不正确" json:"phone"`
Dept string `json:"dept"`
Remark string `json:"remark"`
}
type EmployeeSaveRes struct {
Id int64 `json:"id"`
}
type EmployeeStatusReq struct {
g.Meta `path:"/event/employee/status" method:"post" tags:"event" summary:"员工启停"`
Id int64 `v:"required" json:"id"`
Status int `v:"in:0,1#状态取值非法" json:"status"`
}
type EmployeeStatusRes struct{}
// EmployeeBatchReq 批量操作员工(T15):action=status(启停)/ delete(软删除,可恢复)。
// 部分成功语义见 BatchFailure。
type EmployeeBatchReq struct {
g.Meta `path:"/event/employee/batch" method:"post" tags:"event" summary:"批量操作员工"`
Ids []int64 `v:"required|min-length:1#请选择要操作的员工" json:"ids"`
Action string `v:"required|in:status,delete#动作非法" json:"action"`
Status int `v:"in:0,1#状态取值非法" json:"status"`
}
type EmployeeBatchRes struct {
Success int `json:"success"`
Failed int `json:"failed"`
Failures []BatchFailure `json:"failures"`
}
// ParticipantExcludeReq 批量设置「不参与排座」(N4)。仅对已在候场名单(in_event)的员工生效。
type ParticipantExcludeReq struct {
g.Meta `path:"/event/participant/exclude" method:"post" tags:"event" summary:"批量设置员工不参与排座"`
EventId int64 `v:"required" json:"event_id"`
EmployeeIds []int64 `v:"required|min-length:1#请选择员工" json:"employee_ids"`
ExcludeAssign int `v:"in:0,1#取值非法" json:"exclude_assign"`
}
type ParticipantExcludeRes struct {
Success int `json:"success"` // 实际更新的候场记录数
}
// ===== 活动 =====
type EventItem struct {
Id int64 `json:"id"`
EnterpriseId int64 `json:"enterprise_id"`
EnterpriseName string `json:"enterprise_name"`
Title string `json:"title"`
Venue string `json:"venue"`
EventTime string `json:"event_time"`
Status string `json:"status"`
LayoutVersion int `json:"layout_version"`
CodeUrl string `json:"code_url"`
TableCount int64 `json:"table_count"`
}
type EventListReq struct {
g.Meta `path:"/event/admin/list" method:"get" tags:"event" summary:"活动列表"`
EnterpriseId int64 `json:"enterprise_id"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
type EventListRes struct {
List []EventItem `json:"list"`
Total int `json:"total"`
}
type EventSaveReq struct {
g.Meta `path:"/event/admin/save" method:"post" tags:"event" summary:"保存活动"`
Id int64 `json:"id"`
EnterpriseId int64 `v:"required#请选择企业" json:"enterprise_id"`
Title string `v:"required|length:1,128#活动主题不能为空" json:"title"`
Venue string `json:"venue"`
EventTime string `json:"event_time"`
}
type EventSaveRes struct {
Id int64 `json:"id"`
}
type EventStatusReq struct {
g.Meta `path:"/event/admin/status" method:"post" tags:"event" summary:"发布/结束活动"`
EventId int64 `v:"required" json:"event_id"`
Status string `v:"required|in:draft,published,ended#状态取值非法" json:"status"`
}
type EventStatusRes struct{}
// ===== 设计器全量(活动详情)=====
type SeatOut struct {
Id int64 `json:"id"`
SeatNo int `json:"seat_no"`
IsManual bool `json:"is_manual"`
EmployeeId int64 `json:"employee_id"`
EmployeeName string `json:"employee_name"`
}
type TableOut struct {
Id int64 `json:"id"`
TableNo string `json:"table_no"`
Name string `json:"name"`
X int `json:"x"`
Y int `json:"y"`
Capacity int `json:"capacity"`
Rotation int `json:"rotation"`
TableType int `json:"table_type"` // 桌型:0普通 1主桌 2签到台 3媒体席 4备用桌 9其他
Remark string `json:"remark"` // 桌备注
ExcludeAuto int `json:"exclude_auto"` // 1=不参与自动排序
Seats []SeatOut `json:"seats"`
}
// UnassignedItem 未分配池成员(在候场名单但未绑定座位)
type UnassignedItem struct {
EmployeeId int64 `json:"employee_id"`
Name string `json:"name"`
Phone string `json:"phone"`
Dept string `json:"dept"`
}
type EventDetailReq struct {
g.Meta `path:"/event/admin/detail" method:"get" tags:"event" summary:"活动设计器全量"`
EventId int64 `v:"required" json:"event_id"`
}
type EventDetailRes struct {
Id int64 `json:"id"`
EnterpriseId int64 `json:"enterprise_id"`
Title string `json:"title"`
Venue string `json:"venue"`
EventTime string `json:"event_time"`
Status string `json:"status"`
LayoutVersion int `json:"layout_version"`
HallLayout string `json:"hall_layout"`
Tables []TableOut `json:"tables"`
ParticipantCount int `json:"participant_count"`
SeatCount int `json:"seat_count"`
Unassigned []UnassignedItem `json:"unassigned"`
}
// ===== 布局保存(CAS)=====
// TableIn 布局内的一张桌(capacity 变更会联动座位)
type TableIn struct {
Id int64 `json:"id"`
TableNo string `json:"table_no"`
Name string `json:"name"`
X int `json:"x"`
Y int `json:"y"`
Capacity int `json:"capacity"`
Rotation int `json:"rotation"`
TableType int `json:"table_type"`
Remark string `json:"remark"`
ExcludeAuto int `json:"exclude_auto"`
}
// EventLayoutSaveReq 带 layout_version 提交 → 服务端 CAS 更新,冲突返回 4009。
// 说明:LayoutVersion 允许为 0(首次保存版本即 0),故不用 required 校验,逻辑内校验 < 0。
type EventLayoutSaveReq struct {
g.Meta `path:"/event/admin/layout/save" method:"post" tags:"event" summary:"保存大厅布局"`
EventId int64 `v:"required" json:"event_id"`
LayoutVersion int `v:"min:0#缺少布局版本号" json:"layout_version"`
HallLayout string `json:"hall_layout"`
Tables []TableIn `json:"tables"`
}
type EventLayoutSaveRes struct {
LayoutVersion int `json:"layout_version"`
}
// ===== 桌 =====
// TableSaveReq 建/改桌(改人数联动补/删座)。
// 特殊桌(签到台/媒体席/备用桌)允许 0 座,故 capacity 下限为 0。
type TableSaveReq struct {
g.Meta `path:"/event/admin/table/save" method:"post" tags:"event" summary:"保存桌(含人数联动座位)"`
EventId int64 `v:"required" json:"event_id"`
Id int64 `json:"id"`
TableNo string `json:"table_no"`
Name string `json:"name"`
X int `json:"x"`
Y int `json:"y"`
Capacity int `v:"min:0|max:50#每桌人数需在 0~50 之间" json:"capacity"` // 特殊桌允许 0 座
Rotation int `json:"rotation"`
TableType int `v:"min:0|max:9#桌型取值非法" json:"table_type"`
Remark string `v:"length:0,50#备注最多 50 字" json:"remark"`
ExcludeAuto int `v:"in:0,1#取值非法" json:"exclude_auto"`
}
type TableSaveRes struct {
TableId int64 `json:"table_id"`
AddedSeats int `json:"added_seats"` // 补出的座位数
RemovedSeats int `json:"removed_seats"` // 移除的座位数
MovedToUnassigned int `json:"moved_to_unassigned"` // 因减座而移入未分配池的人数
}
type TableDeleteReq struct {
g.Meta `path:"/event/admin/table/delete" method:"post" tags:"event" summary:"删除桌"`
EventId int64 `v:"required" json:"event_id"`
TableId int64 `v:"required" json:"table_id"`
}
type TableDeleteRes struct {
MovedToUnassigned int `json:"moved_to_unassigned"` // 该桌原有员工数(删桌后全部进入未分配池)
}
// ===== 座位 =====
// SeatSaveReq 改号 / 绑定 / 解绑。
//
// SeatNo > 0 时改号(置 is_manual=1);
// EmployeeId 非 nil 时改绑定:指向 0 表示解绑,>0 表示绑定该员工。
type SeatSaveReq struct {
g.Meta `path:"/event/admin/seat/save" method:"post" tags:"event" summary:"改座位号/绑定/解绑"`
EventId int64 `v:"required" json:"event_id"`
SeatId int64 `v:"required" json:"seat_id"`
SeatNo int `json:"seat_no"`
EmployeeId *int64 `json:"employee_id"`
}
type SeatSaveRes struct{}
// SeatAutoReq mode: fill=增量补位(保留手工);reorder=全部重排(覆盖手工,需二次确认)
type SeatAutoReq struct {
g.Meta `path:"/event/admin/seat/auto" method:"post" tags:"event" summary:"自动排座"`
EventId int64 `v:"required" json:"event_id"`
Mode string `v:"required|in:fill,reorder#模式取值非法" json:"mode"`
}
type SeatAutoRes struct {
Assigned int `json:"assigned"` // 本次新分配人数
Unassigned int `json:"unassigned"` // 仍未分配人数
ManualOverridden int `json:"manual_overridden"` // 被覆盖/清空的手工座位数(reorder 才有意义)
Excluded int `json:"excluded"` // 本次「不参与排座」的员工人数
}
// ===== 员工导入(两段式:预览不落库 → 冲突裁决 → 确认入库)=====
// ImportRow 一行解析后的员工数据(由管理端 SheetJS 解析后提交;后端不解析文件)
type ImportRow struct {
Name string `json:"name"`
Phone string `json:"phone"`
Dept string `json:"dept"`
Remark string `json:"remark"`
}
type ImportPreviewRowOut struct {
Idx int `json:"idx"`
Type string `json:"type"` // new / update / conflict / error
Name string `json:"name"`
Phone string `json:"phone"` // 原样回显,前端展示可自行脱敏
Dept string `json:"dept"`
Message string `json:"message"` // 分类原因(如"手机号缺失""同名不同号")
}
// ImportPreviewReq 预览入参:已解析好的结构化行数组(非 multipart 文件)
type ImportPreviewReq struct {
g.Meta `path:"/event/employee/import-preview" method:"post" tags:"event" summary:"导入预览(不落库)"`
EnterpriseId int64 `v:"required#请选择企业" json:"enterprise_id"`
EventId int64 `json:"event_id"`
FileName string `json:"file_name"`
Rows []ImportRow `v:"required|min-length:1#文件没有有效数据" json:"rows"`
}
type ImportPreviewRes struct {
ImportLogId int64 `json:"import_log_id"` // 确认时回传;服务端据此从库读回快照
Total int `json:"total"`
Inserted int `json:"inserted"`
Updated int `json:"updated"`
Skipped int `json:"skipped"`
Conflict int `json:"conflict"`
Rows []ImportPreviewRowOut `json:"rows"`
}
// ImportDecision action: merge(视为同一人·更新手机号) / create(视为另一个人新增) / ignore
type ImportDecision struct {
Idx int `json:"idx"`
Action string `v:"required|in:merge,create,ignore#裁决动作非法" json:"action"`
}
type ImportConfirmReq struct {
g.Meta `path:"/event/employee/import-confirm" method:"post" tags:"event" summary:"确认导入"`
ImportLogId int64 `v:"required#导入标识缺失" json:"import_log_id"`
Decisions []ImportDecision `json:"decisions"`
}
type ImportConfirmRes struct {
Inserted int `json:"inserted"`
Updated int `json:"updated"`
Skipped int `json:"skipped"`
}
type ImportLogItem struct {
Id int64 `json:"id"`
EnterpriseId int64 `json:"enterprise_id"`
EventId int64 `json:"event_id"`
FileName string `json:"file_name"`
Status string `json:"status"`
Total int `json:"total"`
Inserted int `json:"inserted"`
Updated int `json:"updated"`
Skipped int `json:"skipped"`
Conflict int `json:"conflict"`
Operator string `json:"operator"`
CreatedAt string `json:"created_at"`
}
type ImportLogListReq struct {
g.Meta `path:"/event/import/log/list" method:"get" tags:"event" summary:"导入历史"`
EnterpriseId int64 `json:"enterprise_id"`
EventId int64 `json:"event_id"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
type ImportLogListRes struct {
List []ImportLogItem `json:"list"`
Total int `json:"total"`
}
// ===== 活动小程序码(A18)=====
// EventQrcodeReq 生成活动小程序码(scene 只承载 event_id)
type EventQrcodeReq struct {
g.Meta `path:"/event/admin/qrcode" method:"post" tags:"event" summary:"生成活动小程序码"`
EventId int64 `v:"required" json:"event_id"`
}
type EventQrcodeRes struct {
CodeUrl string `json:"code_url"`
}
// ===== 查座审计(A19,架构 §5.2 遗漏项补录)=====
// QueryLogItem 查座审计列表项。
//
// PhoneMasked 落库时已脱敏(138****0000),原样返回,不再二次脱敏;
// OpenidMasked 由服务端输出时脱敏(前 6 位 + ***),openid 为空时为空串;
// Result 0 失败 / 1 成功。
type QueryLogItem struct {
Id int64 `json:"id"`
EventId int64 `json:"event_id"`
EventTitle string `json:"event_title"`
Ip string `json:"ip"`
PhoneMasked string `json:"phone_masked"`
OpenidMasked string `json:"openid_masked"`
Result int `json:"result"`
CreatedAt string `json:"created_at"`
}
// EventQueryLogReq 查座审计查询条件:EventId=0 表示全部活动;Result=-1 表示全部结果。
type EventQueryLogReq struct {
g.Meta `path:"/event/query/log/list" method:"get" tags:"event" summary:"查座审计列表"`
EventId int64 `json:"event_id"` // 0 = 全部
Result int `json:"result"` // -1 全部 / 0 失败 / 1 成功
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
type EventQueryLogRes struct {
List []QueryLogItem `json:"list"`
Total int `json:"total"`
}