feat(pickup): 增加第三方单号补录功能并优化列表提号备注展示
- 后端支持补录/修改第三方单号接口 PUT /api/v1/admin/pickups/:id/third-party-order-no,记录流转事件与审计日志 - 前端线下提号主列表在第三方单号列后展示提号备注列 - 前端列表操作列及提号详情页增加补录/修改第三方单号操作入口与弹窗 - 通过 scripts/check.sh 全量门禁校验
This commit is contained in:
@@ -44,6 +44,8 @@ var (
|
|||||||
ErrFinancialAdjustmentCannotSettle = errors.New("financial adjustment cannot be settled")
|
ErrFinancialAdjustmentCannotSettle = errors.New("financial adjustment cannot be settled")
|
||||||
ErrPickupShopNotFound = errors.New("pickup shop not found")
|
ErrPickupShopNotFound = errors.New("pickup shop not found")
|
||||||
ErrPickupShopNameExists = errors.New("pickup shop name already exists")
|
ErrPickupShopNameExists = errors.New("pickup shop name already exists")
|
||||||
|
ErrPickupCancelled = errors.New("pickup is cancelled")
|
||||||
|
ErrInvalidThirdPartyOrderNo = errors.New("invalid third party order no")
|
||||||
)
|
)
|
||||||
|
|
||||||
type PickupDTO struct {
|
type PickupDTO struct {
|
||||||
@@ -134,6 +136,10 @@ type UpdateProfitRequest struct {
|
|||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateThirdPartyOrderNoRequest struct {
|
||||||
|
ThirdPartyOrderNo string `json:"third_party_order_no" binding:"required,max=128"`
|
||||||
|
}
|
||||||
|
|
||||||
// FinancialAdjustmentRequest 按目标金额创建完成后的差额流水,至少提供一个金额。
|
// FinancialAdjustmentRequest 按目标金额创建完成后的差额流水,至少提供一个金额。
|
||||||
type FinancialAdjustmentRequest struct {
|
type FinancialAdjustmentRequest struct {
|
||||||
ProfitAmountCent *int64 `json:"profit_amount_cent"`
|
ProfitAmountCent *int64 `json:"profit_amount_cent"`
|
||||||
|
|||||||
@@ -112,6 +112,30 @@ func (h *Handler) UpdateProfit(c *gin.Context) {
|
|||||||
response.OK(c, item)
|
response.OK(c, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateThirdPartyOrderNo 补录或修改第三方单号(管理员)
|
||||||
|
func (h *Handler) UpdateThirdPartyOrderNo(c *gin.Context) {
|
||||||
|
adminID, ok := currentAdminID(c)
|
||||||
|
if !ok {
|
||||||
|
response.Unauthorized(c, "缺少管理员上下文")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, ok := parseID(c)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req UpdateThirdPartyOrderNoRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.BadRequest(c, "第三方单号不能为空且长度不能超过128位")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item, err := h.service.UpdateThirdPartyOrderNo(c.Request.Context(), id, req, adminID, auditMeta(c))
|
||||||
|
if err != nil {
|
||||||
|
writePickupError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OK(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFinancialAdjustment 为已完成提号创建利润或打款调整。
|
// CreateFinancialAdjustment 为已完成提号创建利润或打款调整。
|
||||||
func (h *Handler) CreateFinancialAdjustment(c *gin.Context) {
|
func (h *Handler) CreateFinancialAdjustment(c *gin.Context) {
|
||||||
adminID, ok := currentAdminID(c)
|
adminID, ok := currentAdminID(c)
|
||||||
@@ -305,6 +329,10 @@ func writePickupError(c *gin.Context, err error) {
|
|||||||
response.Error(c, http.StatusNotFound, "pickup_shop_not_found", "店铺不存在")
|
response.Error(c, http.StatusNotFound, "pickup_shop_not_found", "店铺不存在")
|
||||||
case errors.Is(err, ErrPickupShopNameExists):
|
case errors.Is(err, ErrPickupShopNameExists):
|
||||||
response.Error(c, http.StatusConflict, "pickup_shop_name_exists", "店铺名称已存在")
|
response.Error(c, http.StatusConflict, "pickup_shop_name_exists", "店铺名称已存在")
|
||||||
|
case errors.Is(err, ErrPickupCancelled):
|
||||||
|
response.BadRequest(c, "提号订单已取消,不能补录单号")
|
||||||
|
case errors.Is(err, ErrInvalidThirdPartyOrderNo):
|
||||||
|
response.BadRequest(c, "第三方单号不能为空且长度不能超过128位")
|
||||||
default:
|
default:
|
||||||
response.Error(c, http.StatusInternalServerError, "pickup_error", err.Error())
|
response.Error(c, http.StatusInternalServerError, "pickup_error", err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -465,6 +465,61 @@ func (r *Repository) UpdateProfit(ctx context.Context, pickupID uint64, req Upda
|
|||||||
return r.FindByID(ctx, pickupID)
|
return r.FindByID(ctx, pickupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateThirdPartyOrderNo 补录或修改提号单第三方单号。
|
||||||
|
func (r *Repository) UpdateThirdPartyOrderNo(ctx context.Context, pickupID uint64, req UpdateThirdPartyOrderNoRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
|
||||||
|
if r == nil || r.db == nil {
|
||||||
|
return nil, ErrDependencyUnavailable
|
||||||
|
}
|
||||||
|
newThirdPartyOrderNo := strings.TrimSpace(req.ThirdPartyOrderNo)
|
||||||
|
if newThirdPartyOrderNo == "" || len([]rune(newThirdPartyOrderNo)) > 128 {
|
||||||
|
return nil, ErrInvalidThirdPartyOrderNo
|
||||||
|
}
|
||||||
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
|
var pickup model.AdminPickup
|
||||||
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&pickup, pickupID).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return ErrPickupNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pickup.Status == StatusCancelled {
|
||||||
|
return ErrPickupCancelled
|
||||||
|
}
|
||||||
|
before := pickupState(pickup)
|
||||||
|
|
||||||
|
oldThirdPartyOrderNo := pickup.ThirdPartyOrderNo
|
||||||
|
pickup.ThirdPartyOrderNo = newThirdPartyOrderNo
|
||||||
|
if err := tx.Model(&pickup).Update("third_party_order_no", pickup.ThirdPartyOrderNo).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := appendPickupEvent(tx, pickup, "pickup_third_party_order_no_updated", adminID, "补录/修改第三方单号。", "", map[string]any{
|
||||||
|
"old_third_party_order_no": oldThirdPartyOrderNo,
|
||||||
|
"third_party_order_no": pickup.ThirdPartyOrderNo,
|
||||||
|
}, before); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bid := pickup.ID
|
||||||
|
return auditlog.Append(tx, auditlog.Entry{
|
||||||
|
ActorType: "admin",
|
||||||
|
ActorID: adminID,
|
||||||
|
Action: "pickup_third_party_order_no_update",
|
||||||
|
BizType: "admin_pickup",
|
||||||
|
BizID: &bid,
|
||||||
|
Meta: meta,
|
||||||
|
Detail: map[string]any{
|
||||||
|
"pickup_no": pickup.PickupNo,
|
||||||
|
"old_third_party_order_no": oldThirdPartyOrderNo,
|
||||||
|
"new_third_party_order_no": pickup.ThirdPartyOrderNo,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r.FindByID(ctx, pickupID)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFinancialAdjustment 为已完成提号追加财务差额,不改写完成时的原始金额。
|
// CreateFinancialAdjustment 为已完成提号追加财务差额,不改写完成时的原始金额。
|
||||||
func (r *Repository) CreateFinancialAdjustment(ctx context.Context, pickupID uint64, req FinancialAdjustmentRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
|
func (r *Repository) CreateFinancialAdjustment(ctx context.Context, pickupID uint64, req FinancialAdjustmentRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
|
||||||
if r == nil || r.db == nil {
|
if r == nil || r.db == nil {
|
||||||
|
|||||||
@@ -1019,3 +1019,61 @@ func TestRepositoryHistoricalShopStatsAndMapping(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRepositoryUpdateThirdPartyOrderNo(t *testing.T) {
|
||||||
|
t.Run("成功补录第三方单号并记录审计", func(t *testing.T) {
|
||||||
|
repo, db := newPickupTestRepo(t)
|
||||||
|
pickup := seedPickup(t, db, StatusPickingUp)
|
||||||
|
|
||||||
|
item, err := repo.UpdateThirdPartyOrderNo(t.Context(), pickup.ID, UpdateThirdPartyOrderNoRequest{
|
||||||
|
ThirdPartyOrderNo: "TB-20261009-8888",
|
||||||
|
}, 99, auditlog.Meta{RequestID: "req-third-party-order-no"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UpdateThirdPartyOrderNo() error = %v", err)
|
||||||
|
}
|
||||||
|
if item.ThirdPartyOrderNo != "TB-20261009-8888" {
|
||||||
|
t.Fatalf("item.ThirdPartyOrderNo = %q, want TB-20261009-8888", item.ThirdPartyOrderNo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stored model.AdminPickup
|
||||||
|
if err := db.First(&stored, pickup.ID).Error; err != nil {
|
||||||
|
t.Fatalf("查询提号失败: %v", err)
|
||||||
|
}
|
||||||
|
if stored.ThirdPartyOrderNo != "TB-20261009-8888" {
|
||||||
|
t.Fatalf("stored.ThirdPartyOrderNo = %q, want TB-20261009-8888", stored.ThirdPartyOrderNo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证审计日志
|
||||||
|
var audit model.AuditLog
|
||||||
|
if err := db.Where("action = ?", "pickup_third_party_order_no_update").First(&audit).Error; err != nil {
|
||||||
|
t.Fatalf("查询审计日志失败: %v", err)
|
||||||
|
}
|
||||||
|
var detail map[string]any
|
||||||
|
if err := json.Unmarshal(audit.Detail, &detail); err != nil {
|
||||||
|
t.Fatalf("解析审计日志失败: %v", err)
|
||||||
|
}
|
||||||
|
if detail["new_third_party_order_no"] != "TB-20261009-8888" {
|
||||||
|
t.Fatalf("detail[new_third_party_order_no] = %v, want TB-20261009-8888", detail["new_third_party_order_no"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空单号拒绝
|
||||||
|
_, err = repo.UpdateThirdPartyOrderNo(t.Context(), pickup.ID, UpdateThirdPartyOrderNoRequest{
|
||||||
|
ThirdPartyOrderNo: " ",
|
||||||
|
}, 99, auditlog.Meta{})
|
||||||
|
if !errors.Is(err, ErrInvalidThirdPartyOrderNo) {
|
||||||
|
t.Fatalf("UpdateThirdPartyOrderNo() with blank error = %v, want ErrInvalidThirdPartyOrderNo", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("已取消提号单拒绝补录", func(t *testing.T) {
|
||||||
|
repo, db := newPickupTestRepo(t)
|
||||||
|
cancelledPickup := seedPickup(t, db, StatusCancelled)
|
||||||
|
|
||||||
|
_, err := repo.UpdateThirdPartyOrderNo(t.Context(), cancelledPickup.ID, UpdateThirdPartyOrderNoRequest{
|
||||||
|
ThirdPartyOrderNo: "TB-CANCELLED-999",
|
||||||
|
}, 99, auditlog.Meta{})
|
||||||
|
if !errors.Is(err, ErrPickupCancelled) {
|
||||||
|
t.Fatalf("UpdateThirdPartyOrderNo() on cancelled error = %v, want ErrPickupCancelled", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,19 @@ func (s *Service) UpdateProfit(ctx context.Context, pickupID uint64, req UpdateP
|
|||||||
return s.repo.UpdateProfit(ctx, pickupID, req, adminID, meta)
|
return s.repo.UpdateProfit(ctx, pickupID, req, adminID, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateThirdPartyOrderNo(ctx context.Context, pickupID uint64, req UpdateThirdPartyOrderNoRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
|
||||||
|
if s.repo == nil {
|
||||||
|
return nil, ErrDependencyUnavailable
|
||||||
|
}
|
||||||
|
if pickupID == 0 {
|
||||||
|
return nil, ErrPickupNotFound
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(req.ThirdPartyOrderNo) == "" {
|
||||||
|
return nil, ErrInvalidThirdPartyOrderNo
|
||||||
|
}
|
||||||
|
return s.repo.UpdateThirdPartyOrderNo(ctx, pickupID, req, adminID, meta)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) CreateFinancialAdjustment(ctx context.Context, pickupID uint64, req FinancialAdjustmentRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
|
func (s *Service) CreateFinancialAdjustment(ctx context.Context, pickupID uint64, req FinancialAdjustmentRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
|
|||||||
@@ -774,6 +774,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
|
|||||||
adminRoutes.POST("/pickups/:id/complete", requirePerm("order:pickup"), pickupHandler.Complete)
|
adminRoutes.POST("/pickups/:id/complete", requirePerm("order:pickup"), pickupHandler.Complete)
|
||||||
adminRoutes.POST("/pickups/:id/offline-settlement", requirePerm("order:pickup"), pickupHandler.MarkOfflineSettlement)
|
adminRoutes.POST("/pickups/:id/offline-settlement", requirePerm("order:pickup"), pickupHandler.MarkOfflineSettlement)
|
||||||
adminRoutes.PUT("/pickups/:id/profit", requirePerm("order:pickup"), pickupHandler.UpdateProfit)
|
adminRoutes.PUT("/pickups/:id/profit", requirePerm("order:pickup"), pickupHandler.UpdateProfit)
|
||||||
|
adminRoutes.PUT("/pickups/:id/third-party-order-no", requirePerm("order:pickup"), pickupHandler.UpdateThirdPartyOrderNo)
|
||||||
adminRoutes.POST("/pickups/:id/cancel", requirePerm("order:pickup"), pickupHandler.Cancel)
|
adminRoutes.POST("/pickups/:id/cancel", requirePerm("order:pickup"), pickupHandler.Cancel)
|
||||||
adminRoutes.POST("/pickup-financial-adjustments/:id/settle", requirePerm("order:pickup"), pickupHandler.SettleFinancialAdjustment)
|
adminRoutes.POST("/pickup-financial-adjustments/:id/settle", requirePerm("order:pickup"), pickupHandler.SettleFinancialAdjustment)
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ export interface AdminPickupProfitUpdateRequest {
|
|||||||
reason?: string
|
reason?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AdminPickupThirdPartyOrderNoUpdateRequest {
|
||||||
|
third_party_order_no: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface AdminPickupOfflineSettlementRequest {
|
export interface AdminPickupOfflineSettlementRequest {
|
||||||
remark?: string
|
remark?: string
|
||||||
}
|
}
|
||||||
@@ -308,6 +312,17 @@ export async function updateAdminPickupProfit(id: number, req: AdminPickupProfit
|
|||||||
return data.data
|
return data.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateAdminPickupThirdPartyOrderNo(
|
||||||
|
id: number,
|
||||||
|
req: AdminPickupThirdPartyOrderNoUpdateRequest
|
||||||
|
) {
|
||||||
|
const { data } = await apiClient.put<ApiResponse<AdminPickup>>(
|
||||||
|
`/admin/pickups/${id}/third-party-order-no`,
|
||||||
|
req
|
||||||
|
)
|
||||||
|
return data.data
|
||||||
|
}
|
||||||
|
|
||||||
export async function createAdminPickupFinancialAdjustment(
|
export async function createAdminPickupFinancialAdjustment(
|
||||||
id: number,
|
id: number,
|
||||||
req: AdminPickupFinancialAdjustmentRequest
|
req: AdminPickupFinancialAdjustmentRequest
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
createAdminPickupFinancialAdjustment,
|
createAdminPickupFinancialAdjustment,
|
||||||
settleAdminPickupFinancialAdjustment,
|
settleAdminPickupFinancialAdjustment,
|
||||||
updateAdminPickupProfit,
|
updateAdminPickupProfit,
|
||||||
|
updateAdminPickupThirdPartyOrderNo,
|
||||||
type AdminPickup,
|
type AdminPickup,
|
||||||
type AdminPickupFinancialAdjustment,
|
type AdminPickupFinancialAdjustment,
|
||||||
type AdminPickupProcessEvent,
|
type AdminPickupProcessEvent,
|
||||||
@@ -44,16 +45,20 @@ const financialAdjustments = ref<AdminPickupFinancialAdjustment[]>([])
|
|||||||
const processEvents = ref<AdminPickupProcessEvent[]>([])
|
const processEvents = ref<AdminPickupProcessEvent[]>([])
|
||||||
const profitDialogVisible = ref(false)
|
const profitDialogVisible = ref(false)
|
||||||
const financialAdjustmentDialogVisible = ref(false)
|
const financialAdjustmentDialogVisible = ref(false)
|
||||||
|
const thirdPartyOrderNoDialogVisible = ref(false)
|
||||||
const profitSaving = ref(false)
|
const profitSaving = ref(false)
|
||||||
const financialAdjustmentSaving = ref(false)
|
const financialAdjustmentSaving = ref(false)
|
||||||
|
const thirdPartyOrderNoSaving = ref(false)
|
||||||
const profitForm = reactive({ profit_amount: 0, reason: '' })
|
const profitForm = reactive({ profit_amount: 0, reason: '' })
|
||||||
const financialAdjustmentForm = reactive({ profit_amount: 0, settle_amount: 0, reason: '' })
|
const financialAdjustmentForm = reactive({ profit_amount: 0, settle_amount: 0, reason: '' })
|
||||||
|
const thirdPartyOrderNoForm = reactive({ third_party_order_no: '' })
|
||||||
|
|
||||||
const listingCode = computed(() =>
|
const listingCode = computed(() =>
|
||||||
pickup.value ? formatListingNo(pickup.value.listing_no, pickup.value.listing_id) : '-'
|
pickup.value ? formatListingNo(pickup.value.listing_no, pickup.value.listing_id) : '-'
|
||||||
)
|
)
|
||||||
const canEditProfit = computed(() => pickup.value?.status === 'picking_up')
|
const canEditProfit = computed(() => pickup.value?.status === 'picking_up')
|
||||||
const canCreateFinancialAdjustment = computed(() => pickup.value?.status === 'completed')
|
const canCreateFinancialAdjustment = computed(() => pickup.value?.status === 'completed')
|
||||||
|
const canUpdateThirdPartyOrderNo = computed(() => pickup.value?.status !== 'cancelled')
|
||||||
const snapshot = computed(() => normalizeRecord(pickup.value?.account_snapshot))
|
const snapshot = computed(() => normalizeRecord(pickup.value?.account_snapshot))
|
||||||
const assetSummary = computed(() => normalizeRecord(snapshot.value?.asset_summary))
|
const assetSummary = computed(() => normalizeRecord(snapshot.value?.asset_summary))
|
||||||
const priceBreakdown = computed(() => normalizeRecord(assetSummary.value?.price_breakdown))
|
const priceBreakdown = computed(() => normalizeRecord(assetSummary.value?.price_breakdown))
|
||||||
@@ -221,6 +226,35 @@ async function handleUpdateProfit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openThirdPartyOrderNoDialog() {
|
||||||
|
if (!pickup.value) return
|
||||||
|
thirdPartyOrderNoForm.third_party_order_no = pickup.value.third_party_order_no || ''
|
||||||
|
thirdPartyOrderNoDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSaveThirdPartyOrderNo() {
|
||||||
|
if (!pickup.value) return
|
||||||
|
const orderNo = thirdPartyOrderNoForm.third_party_order_no.trim()
|
||||||
|
if (!orderNo) {
|
||||||
|
ElMessage.warning('请输入第三方单号')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
thirdPartyOrderNoSaving.value = true
|
||||||
|
try {
|
||||||
|
const updated = await updateAdminPickupThirdPartyOrderNo(pickup.value.id, {
|
||||||
|
third_party_order_no: orderNo,
|
||||||
|
})
|
||||||
|
pickup.value = updated
|
||||||
|
processEvents.value = await fetchAdminPickupProcessEvents(pickup.value.id)
|
||||||
|
thirdPartyOrderNoDialogVisible.value = false
|
||||||
|
ElMessage.success('第三方单号已更新')
|
||||||
|
} catch (e: unknown) {
|
||||||
|
ElMessage.error(errorMessage(e) || '保存失败')
|
||||||
|
} finally {
|
||||||
|
thirdPartyOrderNoSaving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function statusType(status: string) {
|
function statusType(status: string) {
|
||||||
if (status === 'picking_up') return 'warning'
|
if (status === 'picking_up') return 'warning'
|
||||||
if (status === 'completed') return 'success'
|
if (status === 'completed') return 'success'
|
||||||
@@ -359,6 +393,15 @@ function readSnapshotResources(summary: Record<string, unknown> | null): Snapsho
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbar-actions">
|
<div class="toolbar-actions">
|
||||||
|
<el-button
|
||||||
|
v-if="canUpdateThirdPartyOrderNo"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
:icon="EditPen"
|
||||||
|
@click="openThirdPartyOrderNoDialog"
|
||||||
|
>
|
||||||
|
{{ pickup.third_party_order_no ? '修改单号' : '补录单号' }}
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canEditProfit"
|
v-if="canEditProfit"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -726,6 +769,41 @@ function readSnapshotResources(summary: Record<string, unknown> | null): Snapsho
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 补录/修改第三方单号 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="thirdPartyOrderNoDialogVisible"
|
||||||
|
:title="pickup?.third_party_order_no ? '修改第三方单号' : '补录第三方单号'"
|
||||||
|
width="460px"
|
||||||
|
>
|
||||||
|
<el-form :model="thirdPartyOrderNoForm" label-width="110px">
|
||||||
|
<el-form-item label="提号单号">
|
||||||
|
<span class="text-muted">{{ pickup?.pickup_no }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="当前单号">
|
||||||
|
<span>{{ pickup?.third_party_order_no || '(未录入)' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="第三方单号" required>
|
||||||
|
<el-input
|
||||||
|
v-model="thirdPartyOrderNoForm.third_party_order_no"
|
||||||
|
placeholder="请输入淘宝/拼多多/外部订单号"
|
||||||
|
maxlength="128"
|
||||||
|
show-word-limit
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="thirdPartyOrderNoDialogVisible = false">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:loading="thirdPartyOrderNoSaving"
|
||||||
|
@click="handleSaveThirdPartyOrderNo"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
fetchAdminPickupShopOptions,
|
fetchAdminPickupShopOptions,
|
||||||
fetchAvailableListings,
|
fetchAvailableListings,
|
||||||
updateAdminPickupProfit,
|
updateAdminPickupProfit,
|
||||||
|
updateAdminPickupThirdPartyOrderNo,
|
||||||
type AdminPickup,
|
type AdminPickup,
|
||||||
type AvailableListing,
|
type AvailableListing,
|
||||||
type AvailableListingSourceType,
|
type AvailableListingSourceType,
|
||||||
@@ -48,11 +49,14 @@ const createDialogVisible = ref(false)
|
|||||||
const completeDialogVisible = ref(false)
|
const completeDialogVisible = ref(false)
|
||||||
const profitDialogVisible = ref(false)
|
const profitDialogVisible = ref(false)
|
||||||
const financialAdjustmentDialogVisible = ref(false)
|
const financialAdjustmentDialogVisible = ref(false)
|
||||||
|
const thirdPartyOrderNoDialogVisible = ref(false)
|
||||||
const shopMgrVisible = ref(false)
|
const shopMgrVisible = ref(false)
|
||||||
const activePickupId = ref(0)
|
const activePickupId = ref(0)
|
||||||
const activePickup = ref<AdminPickup | null>(null)
|
const activePickup = ref<AdminPickup | null>(null)
|
||||||
const profitSaving = ref(false)
|
const profitSaving = ref(false)
|
||||||
const financialAdjustmentSaving = ref(false)
|
const financialAdjustmentSaving = ref(false)
|
||||||
|
const thirdPartyOrderNoSaving = ref(false)
|
||||||
|
const thirdPartyOrderNoForm = reactive({ third_party_order_no: '' })
|
||||||
|
|
||||||
const createForm = reactive({
|
const createForm = reactive({
|
||||||
listing_id: null as number | null,
|
listing_id: null as number | null,
|
||||||
@@ -280,6 +284,41 @@ async function handleConfirmOfflineSettlement(row: AdminPickup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openThirdPartyOrderNoDialog(row: AdminPickup) {
|
||||||
|
activePickupId.value = row.id
|
||||||
|
activePickup.value = row
|
||||||
|
thirdPartyOrderNoForm.third_party_order_no = row.third_party_order_no || ''
|
||||||
|
thirdPartyOrderNoDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSaveThirdPartyOrderNo() {
|
||||||
|
const orderNo = thirdPartyOrderNoForm.third_party_order_no.trim()
|
||||||
|
if (!orderNo) {
|
||||||
|
ElMessage.warning('请输入第三方单号')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!activePickupId.value) return
|
||||||
|
thirdPartyOrderNoSaving.value = true
|
||||||
|
try {
|
||||||
|
const updated = await updateAdminPickupThirdPartyOrderNo(activePickupId.value, {
|
||||||
|
third_party_order_no: orderNo,
|
||||||
|
})
|
||||||
|
ElMessage.success('第三方单号已更新')
|
||||||
|
thirdPartyOrderNoDialogVisible.value = false
|
||||||
|
if (activePickup.value) {
|
||||||
|
activePickup.value.third_party_order_no = updated.third_party_order_no
|
||||||
|
}
|
||||||
|
const target = items.value.find(item => item.id === activePickupId.value)
|
||||||
|
if (target) {
|
||||||
|
target.third_party_order_no = updated.third_party_order_no
|
||||||
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
ElMessage.error(errorMessage(e) || '保存失败')
|
||||||
|
} finally {
|
||||||
|
thirdPartyOrderNoSaving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openProfitDialog(row: AdminPickup) {
|
function openProfitDialog(row: AdminPickup) {
|
||||||
activePickupId.value = row.id
|
activePickupId.value = row.id
|
||||||
profitForm.profit_amount = centToYuan(row.profit_amount_cent)
|
profitForm.profit_amount = centToYuan(row.profit_amount_cent)
|
||||||
@@ -605,6 +644,12 @@ function listingOptionLabel(item: AvailableListing) {
|
|||||||
<span v-else class="text-muted">-</span>
|
<span v-else class="text-muted">-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="提号备注" min-width="140" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.remark">{{ row.remark }}</span>
|
||||||
|
<span v-else class="text-muted">-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="店铺名称" min-width="130">
|
<el-table-column label="店铺名称" min-width="130">
|
||||||
<template #default="{ row }">{{ row.shop_name || '-' }}</template>
|
<template #default="{ row }">{{ row.shop_name || '-' }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -652,12 +697,22 @@ function listingOptionLabel(item: AvailableListing) {
|
|||||||
<el-table-column label="创建时间" width="170">
|
<el-table-column label="创建时间" width="170">
|
||||||
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="340" fixed="right">
|
<el-table-column label="操作" width="380" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<RouterLink :to="adminPath(`pickup/${row.id}`)">
|
<RouterLink :to="adminPath(`pickup/${row.id}`)">
|
||||||
<el-button size="small">详情</el-button>
|
<el-button size="small">详情</el-button>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
<el-button
|
||||||
|
v-if="row.status !== 'cancelled'"
|
||||||
|
:type="row.third_party_order_no ? '' : 'warning'"
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
:icon="EditPen"
|
||||||
|
@click="openThirdPartyOrderNoDialog(row)"
|
||||||
|
>
|
||||||
|
{{ row.third_party_order_no ? '改单号' : '补录单号' }}
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="row.status === 'picking_up'"
|
v-if="row.status === 'picking_up'"
|
||||||
type="success"
|
type="success"
|
||||||
@@ -1057,6 +1112,41 @@ function listingOptionLabel(item: AvailableListing) {
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 补录/修改第三方单号 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="thirdPartyOrderNoDialogVisible"
|
||||||
|
:title="activePickup?.third_party_order_no ? '修改第三方单号' : '补录第三方单号'"
|
||||||
|
width="460px"
|
||||||
|
>
|
||||||
|
<el-form :model="thirdPartyOrderNoForm" label-width="110px">
|
||||||
|
<el-form-item label="提号单号">
|
||||||
|
<span class="text-muted">{{ activePickup?.pickup_no }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="当前单号">
|
||||||
|
<span>{{ activePickup?.third_party_order_no || '(未录入)' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="第三方单号" required>
|
||||||
|
<el-input
|
||||||
|
v-model="thirdPartyOrderNoForm.third_party_order_no"
|
||||||
|
placeholder="请输入淘宝/拼多多/外部订单号"
|
||||||
|
maxlength="128"
|
||||||
|
show-word-limit
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="thirdPartyOrderNoDialogVisible = false">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:loading="thirdPartyOrderNoSaving"
|
||||||
|
@click="handleSaveThirdPartyOrderNo"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user