516 lines
18 KiB
Go
516 lines
18 KiB
Go
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" // 发货推送事件名
|
||
|
||
XPayRefundNotifyEvent = "xpay_refund_notify" // 退款结果推送事件名
|
||
)
|
||
|
||
// 退款单状态(member_orders.refund_status,独立于订单状态 status)
|
||
const (
|
||
RefundStatusNone = 0 // 未发起退款
|
||
RefundStatusProcessing = 1 // 退款中(已调用平台退款接口,等待回调/查单确认)
|
||
RefundStatusSuccess = 2 // 退款成功(含手工退款登记)
|
||
RefundStatusFailed = 3 // 退款失败(可重新发起)
|
||
)
|
||
|
||
// ============================================================================
|
||
// 软件开发服务域(迭代-2026-09-29)
|
||
// ============================================================================
|
||
|
||
// 表名(服务商品 / 上传附件登记 / 服务介绍页模块 / 作品案例 / 报价申请 / 站内信 / 开发项目)
|
||
const (
|
||
TableGoods = "goods"
|
||
TableAttachments = "attachments"
|
||
TableServiceBlocks = "service_blocks"
|
||
TableServiceWorks = "service_works"
|
||
TableServiceQuotes = "service_quotes"
|
||
TableUserMessages = "user_messages"
|
||
TableServiceProjects = "service_projects"
|
||
TableProjectStages = "service_project_stages"
|
||
TableProjectNodes = "service_project_nodes"
|
||
TableProjectFiles = "service_project_files"
|
||
)
|
||
|
||
// 服务介绍页模块类型(service_blocks.kind,预设排版布局)
|
||
const (
|
||
ServiceBlockHero = "hero" // 头图横幅:大标题(支持 **高亮**)+ 标语
|
||
ServiceBlockRich = "rich" // 富文本:Markdown 图文混排
|
||
ServiceBlockImageText = "image_text" // 图文:图 + 说明文字
|
||
ServiceBlockImageList = "image_list" // 图片列表:多图网格(点击预览)
|
||
ServiceBlockFlow = "flow" // 服务流程:时间轴,每行「标题|描述」
|
||
ServiceBlockChecklist = "checklist" // 交付清单:勾选卡片,每行一项
|
||
ServiceBlockPrice = "price" // 价格卡:每行「名称|描述|价格」
|
||
ServiceBlockDeveloper = "developer" // 开发者简介:头像 + 名字 + 介绍
|
||
ServiceBlockWorks = "works" // 作品模块入口(进作品列表)
|
||
ServiceBlockGoods = "goods" // 服务与价格清单入口(进服务列表)
|
||
)
|
||
|
||
// 报价申请状态(service_quotes.status)
|
||
const (
|
||
QuoteStatusPending = 0 // 待处理
|
||
QuoteStatusQuoted = 1 // 已报价
|
||
QuoteStatusDone = 2 // 已成交
|
||
QuoteStatusClosed = 3 // 已关闭
|
||
)
|
||
|
||
// QuoteStatusNameOf 报价状态 → 展示名
|
||
func QuoteStatusNameOf(s int) string {
|
||
switch s {
|
||
case QuoteStatusPending:
|
||
return "待处理"
|
||
case QuoteStatusQuoted:
|
||
return "已报价"
|
||
case QuoteStatusDone:
|
||
return "已成交"
|
||
case QuoteStatusClosed:
|
||
return "已关闭"
|
||
}
|
||
return "未知"
|
||
}
|
||
|
||
// 站内信类型(user_messages.type)
|
||
const (
|
||
MsgTypeOrderDelivered = "order_delivered" // 会员开通 / 次数包到账(订单生效)
|
||
MsgTypeQuoteSubmitted = "quote_submitted" // 报价申请已提交(回执)
|
||
MsgTypeQuoteHandled = "quote_handled" // 报价处理结果(已报价/成交/关闭)
|
||
MsgTypeFeedbackReplied = "feedback_replied" // 反馈收到官方回复
|
||
MsgTypeProjectUpdate = "project_update" // 开发项目进度更新(阶段/交付物/绑定/交付)
|
||
MsgTypeSystem = "system" // 系统通知
|
||
)
|
||
|
||
// 开发项目状态(service_projects.status)
|
||
const (
|
||
ProjectStatusRunning = 1 // 进行中
|
||
ProjectStatusDone = 2 // 已交付
|
||
ProjectStatusClosed = 3 // 已关闭
|
||
)
|
||
|
||
// ProjectStatusNameOf 项目状态 → 展示名
|
||
func ProjectStatusNameOf(s int) string {
|
||
switch s {
|
||
case ProjectStatusRunning:
|
||
return "进行中"
|
||
case ProjectStatusDone:
|
||
return "已交付"
|
||
case ProjectStatusClosed:
|
||
return "已关闭"
|
||
}
|
||
return "未知"
|
||
}
|
||
|
||
// 项目阶段状态(service_project_stages.status)
|
||
const (
|
||
StageStatusPending = 0 // 未开始
|
||
StageStatusDoing = 1 // 进行中
|
||
StageStatusDone = 2 // 已完成
|
||
)
|
||
|
||
// 项目分期触发节点(service_project_pays.trigger)
|
||
const (
|
||
PayTriggerStart = "start" // 开工前(定金)
|
||
PayTriggerMidDemo = "mid_demo" // 中期演示确认后
|
||
PayTriggerOnlineBefore = "online_before" // 上线前(尾款)
|
||
PayTriggerOnlineAfter = "online_after" // 上线后(尾款)
|
||
)
|
||
|
||
// PayTriggerNameOf 分期触发节点 → 展示名
|
||
func PayTriggerNameOf(t string) string {
|
||
switch t {
|
||
case PayTriggerStart:
|
||
return "开工前(定金)"
|
||
case PayTriggerMidDemo:
|
||
return "中期演示确认后"
|
||
case PayTriggerOnlineBefore:
|
||
return "上线前"
|
||
case PayTriggerOnlineAfter:
|
||
return "上线后"
|
||
}
|
||
return t
|
||
}
|
||
|
||
// 项目分期状态(service_project_pays.status)
|
||
const (
|
||
PayStatusPending = 0 // 待支付
|
||
PayStatusPaid = 1 // 已支付
|
||
)
|
||
|
||
// 表名追加(开发项目四期:维护模板 / 付款分期模板 / 项目分期)
|
||
const (
|
||
TableMaintainPlans = "service_maintain_plans"
|
||
TablePayPlans = "service_pay_plans"
|
||
TableProjectPays = "service_project_pays"
|
||
)
|
||
|
||
// StageStatusNameOf 阶段状态 → 展示名
|
||
func StageStatusNameOf(s int) string {
|
||
switch s {
|
||
case StageStatusDoing:
|
||
return "进行中"
|
||
case StageStatusDone:
|
||
return "已完成"
|
||
}
|
||
return "未开始"
|
||
}
|
||
|
||
// 软件开发服务分类(goods.category)
|
||
const (
|
||
GoodsCategoryWebsite = 1 // 网站开发系列
|
||
GoodsCategoryMiniProgram = 2 // 小程序开发系列
|
||
GoodsCategoryApp = 3 // App 开发系列
|
||
GoodsCategoryDesktop = 4 // 桌面程序开发系列
|
||
)
|
||
|
||
// GoodsCategoryNameOf 分类值 → 展示名(未知值回落「其他」)
|
||
func GoodsCategoryNameOf(cat int) string {
|
||
switch cat {
|
||
case GoodsCategoryWebsite:
|
||
return "网站开发"
|
||
case GoodsCategoryMiniProgram:
|
||
return "小程序开发"
|
||
case GoodsCategoryApp:
|
||
return "App 开发"
|
||
case GoodsCategoryDesktop:
|
||
return "桌面程序开发"
|
||
}
|
||
return "其他"
|
||
}
|
||
|
||
// 附件上传场景(attachments.scene)
|
||
const (
|
||
AttachmentSceneAvatar = "avatar" // 用户头像(小程序端上传)
|
||
AttachmentSceneCover = "cover" // 服务封面(管理端上传)
|
||
AttachmentSceneAttachment = "attachment" // 通用附件(管理端上传)
|
||
)
|
||
|
||
// 站点 settings 键
|
||
const (
|
||
SettingSiteBaseUrl = "site.base_url" // 图片等静态资源的对外拼接前缀;留空 = 按请求 Host 动态拼接
|
||
SettingHomeFeatureCovers = "home.feature.covers" // 首页便捷功能卡背景图(JSON:featureKey → 相对路径),经 /app/config 下发
|
||
)
|