package service import ( "database/sql" "fmt" "strings" "cmautobuy/admin/model" "cmautobuy/admin/repository" ) // InnerCodeStatusOption 是页面状态筛选项。 type InnerCodeStatusOption struct { Value string Text string } var innerCodeStatusOptions = []InnerCodeStatusOption{ {"", "全部状态"}, {string(model.InnerCodePending), "待匹配"}, {string(model.InnerCodeReady), "可回写"}, {string(model.InnerCodeQueued), "排队中"}, {string(model.InnerCodeApplying), "回写中"}, {string(model.InnerCodeUpdated), "已回写"}, {string(model.InnerCodeAlreadyFilled), "已存在"}, {string(model.InnerCodeSkipped), "已跳过"}, {string(model.InnerCodeFailed), "失败"}, {string(model.InnerCodeNeedsCheck), "需核对"}, } // 删除只改本地数据库,可覆盖最大单页。回写已改为后台队列,不再限制选择 20 条。 const InnerCodeDeleteBatchLimit = 100 // InnerCodeRowView 是正式页面的一行。 type InnerCodeRowView struct { ID int64 BusinessDate string OrderNumber string Stall string SpecRaw string SybSpec string InnerCode string RemoteInnerCode string Status string StatusText string StatusClass string ResultMessage string UpdatedAt string CanMatch bool CanApply bool HasRemoteOldCode bool CanRecheck bool } // InnerCodeListPage 是列表、分页和底栏统计。 type InnerCodeListPage struct { Rows []InnerCodeRowView Total int Page int TotalPages int Status string Keyword string Date string Counts repository.InnerCodeStatusCounts IsFiltered bool } // InnerCodeStatusOptions 返回稳定顺序的筛选项副本。 func InnerCodeStatusOptions() []InnerCodeStatusOption { return append([]InnerCodeStatusOption(nil), innerCodeStatusOptions...) } // ListInnerCodePage 使用默认页容量返回档口入库码列表。 func ListInnerCodePage(db *sql.DB, businessDate, status, keyword string, requestedPage int) (*InnerCodeListPage, error) { return ListInnerCodePageWithPageSize(db, businessDate, status, keyword, requestedPage, DefaultPageSize) } // ListInnerCodePageWithPageSize 校验筛选并按白名单页容量执行 SQL 分页。 func ListInnerCodePageWithPageSize(db *sql.DB, businessDate, status, keyword string, requestedPage, pageSize int) (*InnerCodeListPage, error) { pageSize = NormalizePageSize(pageSize) status = strings.TrimSpace(status) if !validInnerCodeStatusFilter(status) { status = "" } keyword = strings.TrimSpace(keyword) filter := repository.InnerCodeListFilter{BusinessDate: businessDate, Status: status, Keyword: keyword} total, err := repository.CountInnerCodeRecords(db, filter) if err != nil { return nil, err } totalPages := TotalPages(total, pageSize) page := ClampPage(requestedPage, totalPages) records, err := repository.ListInnerCodeRecords(db, filter, pageSize, (page-1)*pageSize) if err != nil { return nil, err } counts, err := repository.CountInnerCodeStatuses(db, businessDate) if err != nil { return nil, err } result := &InnerCodeListPage{Total: total, Page: page, TotalPages: totalPages, Status: status, Keyword: keyword, Date: businessDate, Counts: counts, IsFiltered: status != "" || keyword != ""} result.Rows = make([]InnerCodeRowView, 0, len(records)) for _, record := range records { result.Rows = append(result.Rows, innerCodeRowView(record)) } return result, nil } func validInnerCodeStatusFilter(status string) bool { for _, option := range innerCodeStatusOptions { if option.Value == status { return true } } return false } func innerCodeRowView(record model.InnerCodeRecord) InnerCodeRowView { statusText := map[model.InnerCodeStatus]string{ model.InnerCodePending: "待匹配", model.InnerCodeReady: "可回写", model.InnerCodeQueued: "排队中", model.InnerCodeApplying: "回写中", model.InnerCodeUpdated: "已回写", model.InnerCodeAlreadyFilled: "已存在", model.InnerCodeSkipped: "已跳过", model.InnerCodeFailed: "失败", model.InnerCodeNeedsCheck: "需核对", }[record.Status] if statusText == "" { statusText = "未知" } canMatch := record.Status == model.InnerCodePending || record.Status == model.InnerCodeReady || record.Status == model.InnerCodeSkipped || record.Status == model.InnerCodeFailed canApply := record.Status == model.InnerCodeReady return InnerCodeRowView{ ID: record.ID, BusinessDate: record.BusinessDate, OrderNumber: record.OrderNumber, Stall: displayInnerCodeValue(record.Stall), SpecRaw: displayInnerCodeValue(record.SpecRaw), SybSpec: displayInnerCodeValue(record.SybSpec), InnerCode: record.InnerCode, RemoteInnerCode: displayInnerCodeValue(record.RemoteInnerCode), Status: string(record.Status), StatusText: statusText, StatusClass: "inner-code-status-" + string(record.Status), ResultMessage: displayInnerCodeValue(record.ResultMessage), UpdatedAt: formatLocalTime(record.UpdatedAt), CanMatch: canMatch, CanApply: canApply, HasRemoteOldCode: canApply && record.RemoteInnerCode != "", CanRecheck: record.Status == model.InnerCodeNeedsCheck, } } func displayInnerCodeValue(value string) string { if strings.TrimSpace(value) == "" { return "—" } return value } // InnerCodeStatusMessage 生成底栏可读统计。 func InnerCodeStatusMessage(page *InnerCodeListPage) string { return fmt.Sprintf("共 %d 条,可回写 %d 条,排队中 %d 条,回写中 %d 条,需核对 %d 条;当前筛选 %d 条", page.Counts.Total, page.Counts.Ready, page.Counts.Queued, page.Counts.Applying, page.Counts.NeedsCheck, page.Total) }