feat: 增加档口入库码独立页面 (#233)

This commit is contained in:
chengma
2026-08-15 08:59:40 +08:00
parent 9961f0f538
commit 7665fd93ed
10 changed files with 739 additions and 4 deletions
+143
View File
@@ -0,0 +1,143 @@
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.InnerCodeApplying), "回写中"},
{string(model.InnerCodeUpdated), "已回写"},
{string(model.InnerCodeAlreadyFilled), "已存在"},
{string(model.InnerCodeSkipped), "已跳过"},
{string(model.InnerCodeFailed), "失败"},
{string(model.InnerCodeNeedsCheck), "需核对"},
}
// 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
CanSelect 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 校验筛选并返回统一 20 条 SQL 分页结果。
func ListInnerCodePage(db *sql.DB, businessDate, status, keyword string, requestedPage int) (*InnerCodeListPage, error) {
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)
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.InnerCodeApplying: "回写中", model.InnerCodeUpdated: "已回写",
model.InnerCodeAlreadyFilled: "已存在", model.InnerCodeSkipped: "已跳过",
model.InnerCodeFailed: "失败", model.InnerCodeNeedsCheck: "需核对",
}[record.Status]
if statusText == "" {
statusText = "未知"
}
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),
CanSelect: record.Status == model.InnerCodeReady,
HasRemoteOldCode: record.Status == model.InnerCodeReady && 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 条",
page.Counts.Total, page.Counts.Ready, page.Counts.NeedsCheck, page.Total)
}
+30
View File
@@ -0,0 +1,30 @@
package service
import (
"testing"
"cmautobuy/admin/model"
)
func TestInnerCodeRowView_只有可回写记录可选择(t *testing.T) {
for _, status := range []model.InnerCodeStatus{
model.InnerCodePending, model.InnerCodeReady, model.InnerCodeApplying,
model.InnerCodeUpdated, model.InnerCodeAlreadyFilled, model.InnerCodeSkipped,
model.InnerCodeFailed, model.InnerCodeNeedsCheck,
} {
view := innerCodeRowView(model.InnerCodeRecord{Status: status, RemoteInnerCode: "OLD"})
if view.CanSelect != (status == model.InnerCodeReady) {
t.Errorf("status=%s CanSelect=%v", status, view.CanSelect)
}
if view.CanRecheck != (status == model.InnerCodeNeedsCheck) {
t.Errorf("status=%s CanRecheck=%v", status, view.CanRecheck)
}
}
}
func TestInnerCodeStatusOptions_覆盖所有状态(t *testing.T) {
options := InnerCodeStatusOptions()
if len(options) != 9 || options[0].Value != "" {
t.Fatalf("状态筛选项不完整: %+v", options)
}
}