feat(pickup): 线下提号支持扩展字段店铺管理CRUD及时间筛选

- 线下提号创建表单扩展:增加「操作人」、「第三方单号」、「下单金额」、「押金金额」字段,重构弹窗布局为紧凑双列/三列金额卡片排布,消除过度垂直滚动并默认预填操作人
- 店铺管理 CRUD:新增 pickup_shops 配置表与配套 API,支持在提号页面直接管理店铺(增删改查、启用/禁用、筛选),下拉选项自动优先加载活跃配置店铺并兼顾历史店铺
- 列表时间范围筛选:增加精确到秒的「日期+时间」时间范围选择器,支持快捷时段与后端时间范围过滤
- 生产环境数据核查:只读提取线上全部 61 项历史提号店铺名称与单量分布,完整整理沉淀至实施文档供后续映射规则参考
- 验证方式:执行并通过全套端到端代码门禁(scripts/check.sh:SQL约束、go vet、go build、MySQL真实测试库单元测试及覆盖率、vue大小检查、prettier、eslint、vue-tsc及vite构建)
This commit is contained in:
yml2213
2026-10-09 12:46:15 +08:00
parent 6b74e07e70
commit 9d9adfbd5e
16 changed files with 1571 additions and 75 deletions
@@ -301,11 +301,88 @@ func writePickupError(c *gin.Context, err error) {
response.Error(c, http.StatusNotFound, "pickup_financial_adjustment_not_found", "财务调整记录不存在")
case errors.Is(err, ErrFinancialAdjustmentCannotSettle):
response.BadRequest(c, "当前调整不可确认处理")
case errors.Is(err, ErrPickupShopNotFound):
response.Error(c, http.StatusNotFound, "pickup_shop_not_found", "店铺不存在")
case errors.Is(err, ErrPickupShopNameExists):
response.Error(c, http.StatusConflict, "pickup_shop_name_exists", "店铺名称已存在")
default:
response.Error(c, http.StatusInternalServerError, "pickup_error", err.Error())
}
}
// ListShops 获取店铺配置列表(管理员)
func (h *Handler) ListShops(c *gin.Context) {
query := parsePickupShopQuery(c)
items, err := h.service.ListShops(c.Request.Context(), query)
if err != nil {
writePickupError(c, err)
return
}
response.OK(c, items)
}
// CreateShop 创建店铺配置(管理员)
func (h *Handler) CreateShop(c *gin.Context) {
adminID, ok := currentAdminID(c)
if !ok {
response.Unauthorized(c, "缺少管理员上下文")
return
}
var req CreatePickupShopRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "店铺参数格式不正确")
return
}
item, err := h.service.CreateShop(c.Request.Context(), req, adminID, auditMeta(c))
if err != nil {
writePickupError(c, err)
return
}
response.OK(c, item)
}
// UpdateShop 更新店铺配置(管理员)
func (h *Handler) UpdateShop(c *gin.Context) {
adminID, ok := currentAdminID(c)
if !ok {
response.Unauthorized(c, "缺少管理员上下文")
return
}
id, ok := parseID(c)
if !ok {
return
}
var req UpdatePickupShopRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "店铺参数格式不正确")
return
}
item, err := h.service.UpdateShop(c.Request.Context(), id, req, adminID, auditMeta(c))
if err != nil {
writePickupError(c, err)
return
}
response.OK(c, item)
}
// DeleteShop 删除店铺配置(管理员)
func (h *Handler) DeleteShop(c *gin.Context) {
adminID, ok := currentAdminID(c)
if !ok {
response.Unauthorized(c, "缺少管理员上下文")
return
}
id, ok := parseID(c)
if !ok {
return
}
if err := h.service.DeleteShop(c.Request.Context(), id, adminID, auditMeta(c)); err != nil {
writePickupError(c, err)
return
}
response.OK(c, gin.H{"deleted": true})
}
func auditMeta(c *gin.Context) auditlog.Meta {
return auditlog.Meta{
IP: c.ClientIP(),