做统一认证登录
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// 接入应用类型
|
||||
const (
|
||||
AuthAppTypeWeb = 1 // 有后端的 Web 应用(可安全保存 secret)
|
||||
AuthAppTypeSPA = 2 // 单页应用(只能走 PKCE,不存 secret)
|
||||
AuthAppTypeNative = 3 // 原生 APP / uniapp
|
||||
AuthAppTypeMiniProg = 4 // 小程序
|
||||
)
|
||||
|
||||
// 领域隔离:租户域与平台域使用不同 realm,避免平台账号登录租户应用
|
||||
const (
|
||||
AuthRealmTenant = "tenant"
|
||||
AuthRealmPlatform = "platform"
|
||||
)
|
||||
|
||||
// AuthClient 接入应用(OIDC Client):yz_auth_client
|
||||
// 以后每开发一个新软件,只需在这里注册一条即可接入统一认证。
|
||||
type AuthClient struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
ClientID string `orm:"column(client_id);size(64)" json:"client_id"`
|
||||
ClientSecret *string `orm:"column(client_secret);size(128);null" json:"-"`
|
||||
AppCode string `orm:"column(app_code);size(32)" json:"app_code"`
|
||||
Name string `orm:"column(name);size(128)" json:"name"`
|
||||
AppType int8 `orm:"column(app_type);default(1)" json:"app_type"`
|
||||
RedirectURIs *string `orm:"column(redirect_uris);type(text);null" json:"redirect_uris"`
|
||||
PostLogoutURIs *string `orm:"column(post_logout_uris);type(text);null" json:"post_logout_uris"`
|
||||
BackchannelLogoutURI *string `orm:"column(backchannel_logout_uri);size(500);null" json:"backchannel_logout_uri"`
|
||||
GrantTypes string `orm:"column(grant_types);size(255)" json:"grant_types"`
|
||||
Scope *string `orm:"column(scope);size(255);null" json:"scope"`
|
||||
AccessTTL int `orm:"column(access_ttl);default(1800)" json:"access_ttl"`
|
||||
RefreshTTL int `orm:"column(refresh_ttl);default(2592000)" json:"refresh_ttl"`
|
||||
Realm string `orm:"column(realm);size(16);default(tenant)" json:"realm"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
}
|
||||
|
||||
func (m *AuthClient) TableName() string {
|
||||
return "yz_auth_client"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// 身份状态
|
||||
const (
|
||||
AuthIdentityStatusEnabled = 1 // 启用
|
||||
AuthIdentityStatusDisabled = 0 // 禁用
|
||||
AuthIdentityStatusLocked = 2 // 锁定(连续失败过多)
|
||||
)
|
||||
|
||||
// AuthIdentity 统一身份(自然人):yz_auth_identity
|
||||
//
|
||||
// 统一认证中心的核心表。密码上提到这一层,一个自然人一份密码,
|
||||
// 通过 yz_auth_tenant_user 绑定到多家企业(一人可在多家企业任职)。
|
||||
//
|
||||
// password_hash 存储 PHC 格式($argon2id$v=19$m=...,t=...,p=...$salt$hash),
|
||||
// 盐与参数内联,无需独立 salt 列;历史数据为 salt$sha256(legacy),
|
||||
// 首次登录成功时自动重新哈希为 argon2id。
|
||||
type AuthIdentity struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
UnionID string `orm:"column(union_id);size(32)" json:"union_id"`
|
||||
Mobile *string `orm:"column(mobile);size(20);null" json:"mobile"`
|
||||
Email *string `orm:"column(email);size(128);null" json:"email"`
|
||||
PasswordAlgo string `orm:"column(password_algo);size(16);default(argon2id)" json:"password_algo"`
|
||||
PasswordHash *string `orm:"column(password_hash);size(255);null" json:"-"`
|
||||
PasswordVer int `orm:"column(password_ver);default(1)" json:"password_ver"`
|
||||
Nickname *string `orm:"column(nickname);size(64);null" json:"nickname"`
|
||||
Avatar *string `orm:"column(avatar);size(500);null" json:"avatar"`
|
||||
MfaEnabled int8 `orm:"column(mfa_enabled);default(0)" json:"mfa_enabled"`
|
||||
MfaSecret *string `orm:"column(mfa_secret);size(128);null" json:"-"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
FailCount int `orm:"column(fail_count);default(0)" json:"fail_count"`
|
||||
LockedUntil *time.Time `orm:"column(locked_until);type(datetime);null" json:"locked_until"`
|
||||
LastLoginAt *time.Time `orm:"column(last_login_at);type(datetime);null" json:"last_login_at"`
|
||||
LastLoginIP *string `orm:"column(last_login_ip);size(45);null" json:"last_login_ip"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *AuthIdentity) TableName() string {
|
||||
return "yz_auth_identity"
|
||||
}
|
||||
|
||||
// 第三方登录 provider 常量
|
||||
const (
|
||||
IdPWechat = "wechat"
|
||||
IdPDingTalk = "dingtalk"
|
||||
IdPFeishu = "feishu"
|
||||
IdPQQ = "qq"
|
||||
IdPGitHub = "github"
|
||||
IdPGoogle = "google"
|
||||
)
|
||||
|
||||
// AuthIdentityThird 第三方身份绑定:yz_auth_identity_third
|
||||
// 同一身份可绑定多个第三方账号;同一 provider 的 open_id 全局唯一。
|
||||
type AuthIdentityThird struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
IdentityID uint64 `orm:"column(identity_id)" json:"identity_id"`
|
||||
Provider string `orm:"column(provider);size(32)" json:"provider"`
|
||||
OpenID string `orm:"column(open_id);size(128)" json:"open_id"`
|
||||
UnionID *string `orm:"column(union_id);size(128);null" json:"union_id"`
|
||||
Nickname *string `orm:"column(nickname);size(128);null" json:"nickname"`
|
||||
Avatar *string `orm:"column(avatar);size(500);null" json:"avatar"`
|
||||
Raw *string `orm:"column(raw);type(text);null" json:"raw"`
|
||||
BindTime time.Time `orm:"column(bind_time);auto_now_add;type(datetime)" json:"bind_time"`
|
||||
}
|
||||
|
||||
func (m *AuthIdentityThird) TableName() string {
|
||||
return "yz_auth_identity_third"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// AuthLoginLog 统一登录日志:yz_auth_login_log
|
||||
// 认证中心上线后逐步替代 yz_system_login_log,补充 client_id / amr 字段。
|
||||
type AuthLoginLog struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid *uint64 `orm:"column(tid);null" json:"tid"`
|
||||
IdentityID *uint64 `orm:"column(identity_id);null" json:"identity_id"`
|
||||
Account string `orm:"column(account);size(64);default('')" json:"account"`
|
||||
UserName string `orm:"column(user_name);size(64);default('')" json:"user_name"`
|
||||
TenantName string `orm:"column(tenant_name);size(64);default('')" json:"tenant_name"`
|
||||
ClientID string `orm:"column(client_id);size(64);default('')" json:"client_id"`
|
||||
LoginType string `orm:"column(login_type);size(20);default(password)" json:"login_type"`
|
||||
Amr *string `orm:"column(amr);size(64);null" json:"amr"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
Message string `orm:"column(message);size(255);default('')" json:"message"`
|
||||
IP string `orm:"column(ip);size(45);default('')" json:"ip"`
|
||||
UserAgent string `orm:"column(user_agent);size(500);default('')" json:"user_agent"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *AuthLoginLog) TableName() string {
|
||||
return "yz_auth_login_log"
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// 会话吊销原因
|
||||
const (
|
||||
RevokeReasonLogout = "logout" // 用户主动登出
|
||||
RevokeReasonKicked = "kicked" // 被新登录踢下线(1号1机)
|
||||
RevokeReasonAdmin = "admin" // 管理员强制下线
|
||||
RevokeReasonExpired = "expired" // 过期清理
|
||||
)
|
||||
|
||||
// AuthSession 登录会话:yz_auth_session
|
||||
// 用于「1号1机」并发控制、在线设备列表、强制下线。
|
||||
type AuthSession struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Sid string `orm:"column(sid);size(64)" json:"sid"`
|
||||
IdentityID uint64 `orm:"column(identity_id)" json:"identity_id"`
|
||||
Tid uint64 `orm:"column(tid);default(0)" json:"tid"`
|
||||
ClientID string `orm:"column(client_id);size(64);default('')" json:"client_id"`
|
||||
DeviceID *string `orm:"column(device_id);size(64);null" json:"device_id"`
|
||||
DeviceName *string `orm:"column(device_name);size(128);null" json:"device_name"`
|
||||
IP *string `orm:"column(ip);size(45);null" json:"ip"`
|
||||
UserAgent *string `orm:"column(user_agent);size(500);null" json:"user_agent"`
|
||||
LoginType string `orm:"column(login_type);size(20);default(password)" json:"login_type"`
|
||||
Amr *string `orm:"column(amr);size(64);null" json:"amr"`
|
||||
LoginAt time.Time `orm:"column(login_at);type(datetime)" json:"login_at"`
|
||||
LastAccessAt time.Time `orm:"column(last_access_at);type(datetime)" json:"last_access_at"`
|
||||
ExpiresAt time.Time `orm:"column(expires_at);type(datetime)" json:"expires_at"`
|
||||
Revoked int8 `orm:"column(revoked);default(0)" json:"revoked"`
|
||||
RevokeReason *string `orm:"column(revoke_reason);size(64);null" json:"revoke_reason"`
|
||||
RevokeAt *time.Time `orm:"column(revoke_at);type(datetime);null" json:"revoke_at"`
|
||||
}
|
||||
|
||||
func (m *AuthSession) TableName() string {
|
||||
return "yz_auth_session"
|
||||
}
|
||||
|
||||
// AuthRefreshToken 刷新令牌:yz_auth_refresh_token
|
||||
// 明文仅在颁发时返回一次,库中只存哈希;轮换时通过 family_id 检测重放。
|
||||
type AuthRefreshToken struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TokenHash string `orm:"column(token_hash);size(128)" json:"token_hash"`
|
||||
IdentityID uint64 `orm:"column(identity_id)" json:"identity_id"`
|
||||
Tid uint64 `orm:"column(tid);default(0)" json:"tid"`
|
||||
ClientID string `orm:"column(client_id);size(64);default('')" json:"client_id"`
|
||||
Sid string `orm:"column(sid);size(64);default('')" json:"sid"`
|
||||
FamilyID string `orm:"column(family_id);size(64)" json:"family_id"`
|
||||
RotatedFrom *string `orm:"column(rotated_from);size(128);null" json:"rotated_from"`
|
||||
Used int8 `orm:"column(used);default(0)" json:"used"`
|
||||
Revoked int8 `orm:"column(revoked);default(0)" json:"revoked"`
|
||||
ExpiresAt time.Time `orm:"column(expires_at);type(datetime)" json:"expires_at"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *AuthRefreshToken) TableName() string {
|
||||
return "yz_auth_refresh_token"
|
||||
}
|
||||
|
||||
// AuthCode 授权码:yz_auth_code
|
||||
// 一次性、60 秒有效,配合 PKCE(S256)使用。
|
||||
type AuthCode struct {
|
||||
CodeHash string `orm:"column(code_hash);size(128);pk" json:"code_hash"`
|
||||
ClientID string `orm:"column(client_id);size(64)" json:"client_id"`
|
||||
IdentityID uint64 `orm:"column(identity_id)" json:"identity_id"`
|
||||
Tid uint64 `orm:"column(tid);default(0)" json:"tid"`
|
||||
RedirectURI string `orm:"column(redirect_uri);size(500)" json:"redirect_uri"`
|
||||
CodeChallenge string `orm:"column(code_challenge);size(128)" json:"code_challenge"`
|
||||
CodeChallengeMethod string `orm:"column(code_challenge_method);size(10);default(S256)" json:"code_challenge_method"`
|
||||
Scope *string `orm:"column(scope);size(255);null" json:"scope"`
|
||||
Nonce *string `orm:"column(nonce);size(128);null" json:"nonce"`
|
||||
Used int8 `orm:"column(used);default(0)" json:"used"`
|
||||
ExpiresAt time.Time `orm:"column(expires_at);type(datetime)" json:"expires_at"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *AuthCode) TableName() string {
|
||||
return "yz_auth_code"
|
||||
}
|
||||
|
||||
// AuthTokenBlacklist 令牌吊销表:yz_auth_token_blacklist
|
||||
// 记录已登出/被踢下线的 access token 的 jti,过期后可定期清理。
|
||||
type AuthTokenBlacklist struct {
|
||||
Jti string `orm:"column(jti);size(64);pk" json:"jti"`
|
||||
IdentityID uint64 `orm:"column(identity_id);default(0)" json:"identity_id"`
|
||||
Sid *string `orm:"column(sid);size(64);null" json:"sid"`
|
||||
Reason *string `orm:"column(reason);size(64);null" json:"reason"`
|
||||
ExpiresAt time.Time `orm:"column(expires_at);type(datetime)" json:"expires_at"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *AuthTokenBlacklist) TableName() string {
|
||||
return "yz_auth_token_blacklist"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// 租户自带身份源 provider
|
||||
const (
|
||||
TenantIdPDingTalk = "dingtalk"
|
||||
TenantIdPFeishu = "feishu"
|
||||
TenantIdPWeWork = "wework"
|
||||
TenantIdPOIDC = "oidc"
|
||||
TenantIdPSAML = "saml"
|
||||
)
|
||||
|
||||
// AuthTenantIdp 租户自带身份源:yz_auth_tenant_idp
|
||||
// 企业客户可配置自己的钉钉/飞书/企业微信或标准 OIDC/SAML 上游,
|
||||
// 登录时按 tid 路由到对应身份源(第10条需求)。
|
||||
type AuthTenantIdp struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid uint64 `orm:"column(tid)" json:"tid"`
|
||||
Provider string `orm:"column(provider);size(32)" json:"provider"`
|
||||
Name *string `orm:"column(name);size(128);null" json:"name"`
|
||||
AppID *string `orm:"column(app_id);size(128);null" json:"app_id"`
|
||||
AppSecret *string `orm:"column(app_secret);size(512);null" json:"-"`
|
||||
Issuer *string `orm:"column(issuer);size(500);null" json:"issuer"`
|
||||
AuthURL *string `orm:"column(auth_url);size(500);null" json:"auth_url"`
|
||||
TokenURL *string `orm:"column(token_url);size(500);null" json:"token_url"`
|
||||
UserinfoURL *string `orm:"column(userinfo_url);size(500);null" json:"userinfo_url"`
|
||||
JwksURL *string `orm:"column(jwks_url);size(500);null" json:"jwks_url"`
|
||||
Scopes *string `orm:"column(scopes);size(255);null" json:"scopes"`
|
||||
AttrMap *string `orm:"column(attr_map);type(text);null" json:"attr_map"`
|
||||
ProxyURL *string `orm:"column(proxy_url);size(500);null" json:"proxy_url"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
}
|
||||
|
||||
func (m *AuthTenantIdp) TableName() string {
|
||||
return "yz_auth_tenant_idp"
|
||||
}
|
||||
|
||||
// 并发超限策略
|
||||
const (
|
||||
KickStrategyKickOld = 1 // 踢掉旧会话(默认)
|
||||
KickStrategyReject = 2 // 拒绝新登录
|
||||
)
|
||||
|
||||
// AuthTenantAuthConfig 租户登录策略:yz_auth_tenant_auth_config
|
||||
// 每个租户可自定义验证码方式、密码强度、会话时长与并发设备数。
|
||||
type AuthTenantAuthConfig struct {
|
||||
Tid uint64 `orm:"column(tid);pk" json:"tid"`
|
||||
VerifyType string `orm:"column(verify_type);size(20);default(captcha)" json:"verify_type"`
|
||||
OpenVerify int8 `orm:"column(open_verify);default(1)" json:"open_verify"`
|
||||
PwdMinLen int `orm:"column(pwd_min_len);default(8)" json:"pwd_min_len"`
|
||||
PwdComplexity int8 `orm:"column(pwd_complexity);default(0)" json:"pwd_complexity"`
|
||||
SessionTTL int `orm:"column(session_ttl);default(7200)" json:"session_ttl"`
|
||||
MaxSession int `orm:"column(max_session);default(1)" json:"max_session"`
|
||||
KickStrategy int8 `orm:"column(kick_strategy);default(1)" json:"kick_strategy"`
|
||||
MfaRequired int8 `orm:"column(mfa_required);default(0)" json:"mfa_required"`
|
||||
IPWhitelist *string `orm:"column(ip_whitelist);type(text);null" json:"ip_whitelist"`
|
||||
AllowThird *string `orm:"column(allow_third);size(255);null" json:"allow_third"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
}
|
||||
|
||||
func (m *AuthTenantAuthConfig) TableName() string {
|
||||
return "yz_auth_tenant_auth_config"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// AuthTenantUser 身份-企业绑定:yz_auth_tenant_user
|
||||
//
|
||||
// 一个 AuthIdentity 可有多条绑定(在多家企业任职),各企业内
|
||||
// 独立维护姓名、部门、角色与启用状态;密码不属于这一层。
|
||||
type AuthTenantUser struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid uint64 `orm:"column(tid)" json:"tid"`
|
||||
IdentityID uint64 `orm:"column(identity_id)" json:"identity_id"`
|
||||
Account *string `orm:"column(account);size(64);null" json:"account"`
|
||||
Name *string `orm:"column(name);size(64);null" json:"name"`
|
||||
Phone *string `orm:"column(phone);size(20);null" json:"phone"`
|
||||
Email *string `orm:"column(email);size(128);null" json:"email"`
|
||||
GroupID uint64 `orm:"column(group_id);default(0)" json:"group_id"`
|
||||
OrgID uint64 `orm:"column(org_id);default(0)" json:"org_id"`
|
||||
IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *AuthTenantUser) TableName() string {
|
||||
return "yz_auth_tenant_user"
|
||||
}
|
||||
+15
-2
@@ -97,6 +97,8 @@ func Init(_ string) {
|
||||
new(TenantCrmContract),
|
||||
new(TenantCrmPayback),
|
||||
new(TenantCrmPaybackRecord),
|
||||
// 平台更新通知(docs/sql/platform_upgrade.sql)
|
||||
new(PlatformUpgradeNotice),
|
||||
new(ErpAccountSet),
|
||||
new(ErpNormalSetting),
|
||||
new(ErpCompanyContact),
|
||||
@@ -176,6 +178,19 @@ func Init(_ string) {
|
||||
new(WechatMpConfig),
|
||||
new(WechatMpFollower),
|
||||
new(WechatMpVerifyCode),
|
||||
|
||||
// 统一认证中心(UAC):docs/sql/create_auth_tables.sql,人工执行建表
|
||||
new(AuthIdentity),
|
||||
new(AuthIdentityThird),
|
||||
new(AuthTenantUser),
|
||||
new(AuthClient),
|
||||
new(AuthSession),
|
||||
new(AuthRefreshToken),
|
||||
new(AuthCode),
|
||||
new(AuthTokenBlacklist),
|
||||
new(AuthTenantIdp),
|
||||
new(AuthTenantAuthConfig),
|
||||
new(AuthLoginLog),
|
||||
)
|
||||
|
||||
// 创建全局 Ormer
|
||||
@@ -192,5 +207,3 @@ func Init(_ string) {
|
||||
// 新建与调整走 SQL:docs/sql/update_role_system.sql,代码不做自动补建。
|
||||
Orm = orm.NewOrm()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// PlatformUpgradeNotice 平台更新通知记录表:yz_platform_upgrade_notice
|
||||
// 用于展示平台近期更新内容,支持按时间排序展示
|
||||
type PlatformUpgradeNotice struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"` // 租户 ID,0 表示全局
|
||||
UpdateDate string `orm:"column(update_date);size(20)" json:"update_date"` // 更新日期 YYYY-MM-DD
|
||||
Title string `orm:"column(title);size(255)" json:"title"` // 更新标题
|
||||
Content string `orm:"column(content);type(text)" json:"content"` // 更新内容详情
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"` // 排序权重,越大越靠前
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 状态:0-隐藏 1-显示
|
||||
CreateUserID string `orm:"column(create_user_id);size(64)" json:"create_user_id"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);auto_now;type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *PlatformUpgradeNotice) TableName() string {
|
||||
return "yz_platform_upgrade_notice"
|
||||
}
|
||||
Reference in New Issue
Block a user