Files
qitongxue-api/internal/consts/consts.go
2026-09-29 10:57:01 +08:00

331 lines
12 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 consts
// JWT audience
const (
AudUser = "user"
AudAdmin = "admin"
)
// 请求上下文变量(中间件 SetCtxVar)
const (
CtxUserId = "userId"
CtxLevelKey = "levelKey"
CtxAdminId = "adminId"
// 管理员审计上下文(AdminPerm 中间件写入,WriteAudit 读取)
CtxAdminRole = "adminRole"
CtxAdminAccount = "adminAccount"
CtxAdminName = "adminName"
)
// 管理员角色(admin_users.role_value)
const (
AdminRoleSuper = "super" // 超管:全部权限
AdminRoleOperator = "operator" // 运营:内容读写,不含管理员管理与审计
AdminRoleReadonly = "readonly" // 只读:仅可查看
)
// 管理员状态(admin_users.status)
const (
AdminStatusDisabled = 0
AdminStatusEnabled = 1
)
// 审计结果(admin_audit_logs.result)
const (
AuditResultFail = 0 // 失败
AuditResultSuccess = 1 // 成功
)
// 业务错误码(响应 code 字段)
const (
CodeLocked = 4001 // 模块未授权(等级锁定)
CodeQuotaExhausted = 4002 // 额度用尽(免费/会员/付费额度都已耗尽)
CodeNoteLimit = 4003 // 笔记数量超上限(免费版最多 50 条)
CodeNoteNotFound = 4004 // 笔记不存在/无权
CodeEventUnavailable = 4005 // 活动不存在或未发布
CodeSeatRateLimited = 4006 // 查座频率超限
CodeSeatCooling = 4007 // 查座连续失败冷却中
CodeImportConflict = 4008 // 导入存在未处理冲突
CodeLayoutConflict = 4009 // 布局版本冲突(CAS 失败)
CodePayFail = 4101 // 下单/支付参数异常
)
// 默认等级:会员到期后回落的目标等级
const DefaultLevelKey = "v1"
// 表名
const (
TableUsers = "users"
TableModules = "modules"
TableLevels = "levels"
TableTools = "tools"
TableUsageLogs = "tool_usage_logs"
TableWorkbench = "user_workbench"
TableAdminUsers = "admin_users"
TableAdminAuditLog = "admin_audit_logs"
TableFeedbacks = "feedbacks"
TableMemberPlans = "member_plans"
TableMemberOrders = "member_orders"
TableQuotaPacks = "quota_packs"
TableUserToolQuota = "user_tool_quota"
TableQuotaUsage = "user_quota_usage"
TableSettings = "settings"
TableNotes = "notes"
// 年会域(T08 建前 6 张;T09/T10 分别追加 event_import_logs / event_seat_queries)
TableEnterprises = "enterprises"
TableEmployees = "employees"
TableAnnualEvents = "annual_events"
TableEventParticipants = "event_participants"
TableEventTables = "event_tables"
TableEventSeats = "event_seats"
TableEventImportLogs = "event_import_logs"
TableEventSeatQueries = "event_seat_queries"
)
// 年会活动状态(annual_events.status,字符串枚举;仅 published 可查座)
const (
EventStatusDraft = "draft"
EventStatusPublished = "published"
EventStatusEnded = "ended"
)
// 自动排座模式(/event/admin/seat/auto 的 mode)
const (
SeatModeFill = "fill" // 增量补位:保留手工号,只填未分配员工到空位
SeatModeReorder = "reorder" // 全部重排:覆盖含手工号在内的编号并清空 is_manual
)
// 桌型(event_tables.table_type,N4)
//
// 0 普通桌 / 1 主桌 / 2 签到台 / 3 媒体席 / 4 备用桌 / 9 其他。
// 类型默认联动(前端 N4-10,后端中立存储;老数据缺列回退 0):
//
// 签到台/媒体席/备用桌 → capacity=0 + exclude_auto=1
// 普通桌 → capacity=10 + exclude_auto=0
// 主桌 → capacity=10 + exclude_auto=1
const (
TableTypeNormal = 0 // 普通桌
TableTypeMain = 1 // 主桌
TableTypeCheckin = 2 // 签到台
TableTypeMedia = 3 // 媒体席
TableTypeSpare = 4 // 备用桌
TableTypeOther = 9 // 其他
)
// 员工导入:行分类(预览 type,见 §8.4)
const (
ImportTypeNew = "new" // 新号码 → 新增
ImportTypeUpdate = "update" // 同手机号 → 视为同一人,更新
ImportTypeConflict = "conflict" // 同名不同号 → 需人工裁决
ImportTypeError = "error" // 缺手机号/格式非法 → 跳过(计入 skipped)
)
// 员工导入:冲突裁决动作(decisions.action,见 §8.4)
const (
ImportActionMerge = "merge" // 视为同一人·更新手机号
ImportActionCreate = "create" // 视为另一个人新增
ImportActionIgnore = "ignore" // 忽略
)
// 导入记录状态(event_import_logs.status,见 §8.4)
const (
ImportStatusDraft = "draft" // 预览中
ImportStatusCommitted = "committed" // 已入库
ImportStatusCancelled = "cancelled" // 已取消
)
// 导入行数上限(超出给明确提示;可用 settings 覆盖)
const (
SettingImportRowLimit = "event_import_row_limit" // settings 键
// DefaultImportRowLimit 单次导入行数上限兜底值
DefaultImportRowLimit = 2000
)
// 查座限流/冷却阈值(settings 键 + 缺省值;无 Redis,以 event_seat_queries 时间窗为准)
const (
SettingSeatRateLimitPerMin = "event.seat.rateLimitPerMin" // ≥N 次/分钟 → 4006
SettingSeatRateLimitPerHour = "event.seat.rateLimitPerHour" // ≥N 次/小时 → 4006
SettingSeatFailCooldownMinutes = "event.seat.failCooldownMinutes" // 冷却时长(分钟)
SettingSeatFailThreshold = "event.seat.failThreshold" // 连续失败达到该值触发冷却
DefaultSeatRateLimitPerMin = 5 // PRD-02 §4.2.3 建议值
DefaultSeatRateLimitPerHour = 20 // 建议值
DefaultSeatFailCooldownMinutes = 10 // 建议值
DefaultSeatFailThreshold = 5 // 建议值
)
// 查座审计结果枚举(event_seat_queries.result,架构 §3.2.9)
const (
SeatResultFail = 0 // 失败(未命中/未分配)
SeatResultSuccess = 1 // 成功(命中并返回本人桌座)
SeatResultAll = -1 // 审计列表筛选用:全部结果(仅用于入参,不落库)
)
// 笔记额度与提醒状态
const (
// NoteFreeLimit 免费用户活跃笔记数上限(总量上限,非每月重置)
NoteFreeLimit = 50
// notes.remind_status 状态枚举
NoteRemindNone = 0 // 未设置
NoteRemindPending = 1 // 待提醒
NoteRemindSent = 2 // 已提醒
NoteRemindFailed = 3 // 发送失败(含未发送·授权不足 / 模板未配置)
NoteRemindExpired = 4 // 已过期
)
// 笔记提醒过期设置(settings 表)
const (
SettingNoteRemindExpireHours = "note_remind_expire_hours" // 待提醒超过该小时数仍未发送则置「已过期」
)
// DefaultNoteRemindExpireHours 提醒过期兜底值:settings 未配置时使用。
const DefaultNoteRemindExpireHours = 24
// 订单类型:同一个下单/发货链路承载「会员」与「次数包」两种商品
const (
OrderTypeMember = 1 // 会员套餐(延长等级有效期)
OrderTypeQuota = 2 // 次数包(增加某工具的付费额度余额)
)
// ============================================================================
// 商业化域:优惠码 / 优惠券(迭代-2026-09-20)
// ============================================================================
// 表名(优惠码 / 券模板 / 用户持有券)
const (
TablePromoCodes = "promo_codes"
TableCoupons = "coupons"
TableUserCoupons = "user_coupons"
)
// 业务错误码:优惠凭证域
//
// 编号接续 4001–4009 / 4010–4014 段(架构 §4.5 统一裁定,解决两份 PRD 的冲突)。
const (
CodePromoInvalid = 4010 // 优惠码无效/过期/达上限/超单人限用/不适用;或同时传 promo_code 与 user_coupon_id
CodeCouponUnavailable = 4011 // 券不可用/已用/过期/作废;免单券并发占用失败
CodeLevelInvalid = 4012 // 等级不存在或已停用
CodePromoRateLimited = 4013 // 同一用户 1 分钟内优惠码错误次数超限
CodeProductPriceMismatch = 4014 // 服务端自检:settings 道具价格与 goodsPrice 预期不一致
)
// 业务错误码(续 4015–4018 段)
//
// 4015 属 T01(订单两步式):订单不存在 / 不属于当前用户 / 状态不允许该操作。
// 4016/4017(T02 头像上传)见紧随其后的独立区块;4018 属 T04(座次自动排座前置条件)。
const (
CodeOrderInvalid = 4015 // 订单不存在 / 不属于当前用户 / 状态不允许该操作(已支付、已关闭)
CodeSeatAutoInvalid = 4018 // 自动排座前置条件不满足(无可参与排座的桌)——fail-closed,message 列出被排除的桌
)
// 头像上传错误码(T02 / N3)
//
// 4017 上传失败**必须给可读中文提示**(如「头像上传失败,请重试」)且**原头像不变、不静默失败**(U1)。
const (
CodeUploadInvalid = 4016 // 上传校验失败:体积超限(>5MB)/ 格式不支持 —— 前端不发起上传
CodeUploadFailed = 4017 // 上传存储失败(服务端写盘 / 目录异常)—— 可读中文提示,原头像不变
)
// 券型(coupons.coupon_type / user_coupons.coupon_type)
//
// 1 免单券(走支付)/ 2 展示券(仅展示)。**新建默认 2**(fail-closed)。
const (
CouponTypeFreebie = 1
CouponTypeDisplay = 2
)
// 券面语义 kind(coupons.kind / user_coupons.kind):1 满减 / 2 免单
const (
CouponKindCut = 1
CouponKindFreebie = 2
)
// 用户券状态(user_coupons.status)
const (
UserCouponStatusUnused = 0 // 未使用
UserCouponStatusUsed = 1 // 已使用(占用或核销)
UserCouponStatusExpired = 2 // 已过期
UserCouponStatusVoid = 3 // 已作废
)
// 用户券来源(user_coupons.source)
const (
UserCouponSourceAdmin = 1 // 后台发放
UserCouponSourceClaim = 2 // 活动领取
UserCouponSourceSystem = 3 // 系统赠送
)
// 用户券占用/核销人(user_coupons.used_by)
const (
UserCouponUsedBySystem = "system" // 订单占用
UserCouponUsedByAdmin = "admin" // 人工核销
)
// 订单使用凭证类型(member_orders.promo_kind)
const (
PromoKindNone = 0 // 未使用凭证
PromoKindCode = 1 // 优惠码
PromoKindCoupon = 2 // 免单券
)
// 适用范围(promo_codes.scope / coupons.scope):0 全部 / 1 指定会员套餐 / 2 指定次数包
const (
PromoScopeAll = 0
PromoScopePlan = 1
PromoScopePack = 2
)
// 优惠凭证域 settings 键(后台可配,不硬编码进 config.yaml)
const (
SettingFreebieProductId = "pay.freebie.product_id" // 免单道具 ID
SettingFreebiePriceCents = "pay.freebie.price_cents" // 免单道具价格(分)
SettingPromoFailLimitPerMin = "promo.fail.limitPerMin" // 同一用户 1 分钟错误上限
SettingCouponLockTtlSeconds = "coupon.lock.ttlSeconds" // 免单券占用自动释放时长(秒)
)
// 优惠凭证域 settings 兜底值(settings 未配置时使用)
const (
DefaultFreebieProductId = "admin_1"
DefaultFreebiePriceCents = 1
DefaultPromoFailLimitPerMin = 6
DefaultCouponLockTtlSeconds = 900
)
// 额度来源(扣减时实际命中的池)
const (
QuotaSourceFree = "free" // 免费额度
QuotaSourceMember = "member" // 会员额度
QuotaSourcePaid = "paid" // 付费额度(次数包)
QuotaSourceNone = "none" // 已耗尽
)
// 额度设置键(settings 表)
const (
SettingQuotaPeriodDays = "quota_period_days" // 全局默认额度重置周期(天)
)
// DefaultQuotaPeriodDays 额度周期兜底值:settings 与 config 都未配置时使用。
// 后台「额度设置」可改,用户维度与会员套餐维度可各自覆盖。
const DefaultQuotaPeriodDays = 7
// 会员订单状态
const (
OrderStatusPending = 0 // 待支付
OrderStatusDelivered = 1 // 已支付并发货(会员权益已生效)
OrderStatusRefunded = 2 // 已退款
OrderStatusClosed = 3 // 已关闭(超时未支付)
)
// 虚拟支付环境与支付渠道
const (
XPayEnvProd = 0 // env 固定填 0(现网)
XPayCurrency = "CNY" // 币种固定 CNY
XPayMode = "short_series_goods" // 道具直购
PayChannelWx = "wxpay" // 微信虚拟支付(Android 等)
PayChannelIOS = "apple" // Apple IAP
XPayNotifyEvent = "xpay_goods_deliver_notify" // 发货推送事件名
)