统一单入口 Go 工程与前端依赖目录,增加后台供应商配置、候选审核、计划预算、成交冲正、持仓复盘和站内通知。接入策略版本、Python 回测、可配置 A 股公开行情及 zap 文件轮转日志,补充迁移、契约与验证。
This commit is contained in:
@@ -21,7 +21,15 @@ type LoginLimiter interface {
|
||||
Login(context.Context, string, string) (bool, error)
|
||||
}
|
||||
type IdentityOptions struct {
|
||||
Market *service.MarketService
|
||||
Backtests *service.BacktestService
|
||||
Auth *service.AuthService
|
||||
Providers *service.ProviderService
|
||||
Candidates *service.CandidateService
|
||||
Plans *service.TradePlanService
|
||||
Fills *service.TradeFillService
|
||||
Notifications *service.NotificationService
|
||||
Strategies *service.StrategyService
|
||||
Accounts *service.AccountService
|
||||
Limiter LoginLimiter
|
||||
DevelopmentLogin bool
|
||||
@@ -209,7 +217,11 @@ func sameOrigin(r *http.Request) bool {
|
||||
}
|
||||
|
||||
func decode(c *gin.Context, value any) bool {
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 16<<10)
|
||||
return decodeLimit(c, value, 16<<10)
|
||||
}
|
||||
|
||||
func decodeLimit(c *gin.Context, value any, limit int64) bool {
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, limit)
|
||||
if !strings.HasPrefix(strings.ToLower(c.GetHeader("Content-Type")), "application/json") {
|
||||
failure(c, http.StatusUnsupportedMediaType, "INVALID_CONTENT_TYPE", "请使用 application/json。", false)
|
||||
return false
|
||||
@@ -237,13 +249,25 @@ func failure(c *gin.Context, status int, code, message string, retryable bool) {
|
||||
func fail(c *gin.Context, err error) {
|
||||
switch {
|
||||
case errors.Is(err, apperror.ErrInvalidInput):
|
||||
failure(c, http.StatusUnprocessableEntity, "INVALID_INPUT", "请检查输入内容;资金最多两位小数,密码为 12–72 字节。", false)
|
||||
failure(c, http.StatusUnprocessableEntity, "INVALID_INPUT", "请检查输入字段、必填项与格式。", false)
|
||||
case errors.Is(err, apperror.ErrUnauthenticated):
|
||||
failure(c, http.StatusUnauthorized, "UNAUTHENTICATED", "登录信息无效或会话已过期。", false)
|
||||
case errors.Is(err, apperror.ErrForbidden):
|
||||
failure(c, http.StatusForbidden, "FORBIDDEN", "无权执行此操作。", false)
|
||||
case errors.Is(err, apperror.ErrInsufficientCash):
|
||||
failure(c, http.StatusConflict, "INSUFFICIENT_CASH", "可用现金不足,请检查其他计划保留的预算。", false)
|
||||
case errors.Is(err, apperror.ErrInsufficientQuantity):
|
||||
failure(c, http.StatusConflict, "INSUFFICIENT_SELLABLE_QUANTITY", "可卖数量不足;请检查模拟可卖时间与剩余持仓。", false)
|
||||
case errors.Is(err, apperror.ErrCandidateUnavailable):
|
||||
failure(c, http.StatusConflict, "CANDIDATE_UNAVAILABLE", "候选已失效或版本已更新,请重新查看依据。", false)
|
||||
case errors.Is(err, apperror.ErrPreviewExpired):
|
||||
failure(c, http.StatusConflict, "PREVIEW_EXPIRED", "预算预览已过期,请重新预览后确认。", false)
|
||||
case errors.Is(err, apperror.ErrChronology):
|
||||
failure(c, http.StatusConflict, "FILL_CHRONOLOGY", "请按成交发生时间顺序录入;更早记录需先纠正后续成交。", false)
|
||||
case errors.Is(err, apperror.ErrDependentFill):
|
||||
failure(c, http.StatusConflict, "DEPENDENT_FILL", "后续成交依赖此记录,请先冲正最新成交。", false)
|
||||
case errors.Is(err, apperror.ErrConflict):
|
||||
failure(c, http.StatusConflict, "CONFLICT", "该登录名或账户类型已存在。", false)
|
||||
failure(c, http.StatusConflict, "CONFLICT", "记录已存在或版本已更新,请刷新后重试。", false)
|
||||
case errors.Is(err, apperror.ErrNotFound):
|
||||
failure(c, http.StatusNotFound, "NOT_FOUND", "记录不存在。", false)
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user