diff --git a/backend/internal/modules/adminfinance/disbursement_list.go b/backend/internal/modules/adminfinance/disbursement_list.go index 82ab7c9..8b390ed 100644 --- a/backend/internal/modules/adminfinance/disbursement_list.go +++ b/backend/internal/modules/adminfinance/disbursement_list.go @@ -80,6 +80,7 @@ func (r *Repository) disbursementListBaseQuery(ctx context.Context) *gorm.DB { COALESCE(NULLIF(operator.nickname, ''), operator.username, '') AS operator_name, ro.offline_settlement_remark AS remark, '' AS category, + '' AS custom_category_name, '' AS voucher_url, NULL AS voided_at, NULL AS voided_by, @@ -125,6 +126,7 @@ func (r *Repository) disbursementListBaseQuery(ctx context.Context) *gorm.DB { COALESCE(NULLIF(operator.nickname, ''), operator.username, '') AS operator_name, CASE WHEN wr.payment_remark <> '' THEN wr.payment_remark ELSE wr.review_remark END AS remark, '' AS category, + '' AS custom_category_name, '' AS voucher_url, NULL AS voided_at, NULL AS voided_by, @@ -160,6 +162,7 @@ func (r *Repository) disbursementListBaseQuery(ctx context.Context) *gorm.DB { COALESCE(NULLIF(creator.nickname, ''), creator.username, '') AS operator_name, md.remark, md.category, + md.custom_category_name, md.voucher_url, md.voided_at, md.voided_by, @@ -202,37 +205,38 @@ func (r *Repository) applyDisbursementFilters(db *gorm.DB, query DisbursementQue } type disbursementItemRow struct { - SourceType string - SourceID uint64 - BusinessNo string - OrderID uint64 - WithdrawalID uint64 - UserID uint64 - PayeeName string - PayeePhone string - UploaderName string - SourceChannel string - AccountType string - AccountName string - AccountNo string - BankName string - AmountCent int64 - FeeCent int64 - ActualAmountCent int64 - Status string - RawStatus string - BusinessCreatedAt *time.Time - PaidAt *time.Time - OperatorID *uint64 - OperatorName string - Remark string - Category string - VoucherURL string - VoidedAt *time.Time - VoidedBy *uint64 - VoidedByName string - VoidReason string - SourcePayload []byte + SourceType string + SourceID uint64 + BusinessNo string + OrderID uint64 + WithdrawalID uint64 + UserID uint64 + PayeeName string + PayeePhone string + UploaderName string + SourceChannel string + AccountType string + AccountName string + AccountNo string + BankName string + AmountCent int64 + FeeCent int64 + ActualAmountCent int64 + Status string + RawStatus string + BusinessCreatedAt *time.Time + PaidAt *time.Time + OperatorID *uint64 + OperatorName string + Remark string + Category string + CustomCategoryName string + VoucherURL string + VoidedAt *time.Time + VoidedBy *uint64 + VoidedByName string + VoidReason string + SourcePayload []byte } func (r disbursementItemRow) toDTO() DisbursementItemDTO { @@ -246,35 +250,36 @@ func (r disbursementItemRow) toDTO() DisbursementItemDTO { } } return DisbursementItemDTO{ - SourceType: r.SourceType, - SourceID: r.SourceID, - BusinessNo: r.BusinessNo, - OrderID: r.OrderID, - WithdrawalID: r.WithdrawalID, - UserID: r.UserID, - PayeeName: r.PayeeName, - PayeePhone: phone, - UploaderName: r.UploaderName, - SourceChannel: r.SourceChannel, - AccountType: r.AccountType, - AccountName: r.AccountName, - AccountNo: r.AccountNo, - BankName: r.BankName, - AmountCent: r.AmountCent, - FeeCent: r.FeeCent, - ActualAmountCent: r.ActualAmountCent, - Status: r.Status, - RawStatus: r.RawStatus, - BusinessCreatedAt: r.BusinessCreatedAt, - PaidAt: r.PaidAt, - OperatorID: r.OperatorID, - OperatorName: r.OperatorName, - Remark: r.Remark, - Category: r.Category, - VoucherURL: r.VoucherURL, - VoidedAt: r.VoidedAt, - VoidedBy: r.VoidedBy, - VoidedByName: r.VoidedByName, - VoidReason: r.VoidReason, + SourceType: r.SourceType, + SourceID: r.SourceID, + BusinessNo: r.BusinessNo, + OrderID: r.OrderID, + WithdrawalID: r.WithdrawalID, + UserID: r.UserID, + PayeeName: r.PayeeName, + PayeePhone: phone, + UploaderName: r.UploaderName, + SourceChannel: r.SourceChannel, + AccountType: r.AccountType, + AccountName: r.AccountName, + AccountNo: r.AccountNo, + BankName: r.BankName, + AmountCent: r.AmountCent, + FeeCent: r.FeeCent, + ActualAmountCent: r.ActualAmountCent, + Status: r.Status, + RawStatus: r.RawStatus, + BusinessCreatedAt: r.BusinessCreatedAt, + PaidAt: r.PaidAt, + OperatorID: r.OperatorID, + OperatorName: r.OperatorName, + Remark: r.Remark, + Category: r.Category, + CustomCategoryName: r.CustomCategoryName, + VoucherURL: r.VoucherURL, + VoidedAt: r.VoidedAt, + VoidedBy: r.VoidedBy, + VoidedByName: r.VoidedByName, + VoidReason: r.VoidReason, } } diff --git a/backend/internal/modules/adminfinance/disbursement_list_test.go b/backend/internal/modules/adminfinance/disbursement_list_test.go index 842de0f..1b463c9 100644 --- a/backend/internal/modules/adminfinance/disbursement_list_test.go +++ b/backend/internal/modules/adminfinance/disbursement_list_test.go @@ -37,7 +37,7 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T) `CREATE TABLE users (id INTEGER PRIMARY KEY, nickname TEXT, phone TEXT)`, `CREATE TABLE admin_users (id INTEGER PRIMARY KEY, nickname TEXT, username TEXT)`, `CREATE TABLE manual_disbursements ( - id INTEGER PRIMARY KEY, disbursement_no TEXT, category TEXT, payee_name TEXT, + id INTEGER PRIMARY KEY, disbursement_no TEXT, category TEXT, custom_category_name TEXT NOT NULL DEFAULT '', payee_name TEXT, amount_cent INTEGER, paid_at DATETIME, remark TEXT, voucher_url TEXT, status TEXT, created_by INTEGER, voided_by INTEGER, voided_at DATETIME, void_reason TEXT, created_at DATETIME @@ -87,11 +87,11 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T) t.Fatal(err) } if err := db.Exec(`INSERT INTO manual_disbursements - (id, disbursement_no, category, payee_name, amount_cent, paid_at, remark, + (id, disbursement_no, category, custom_category_name, payee_name, amount_cent, paid_at, remark, voucher_url, status, created_by, voided_by, voided_at, void_reason, created_at) VALUES - (20, 'OD202607010001', 'user_compensation', '李四', 2500, ?, '用户补偿', '', 'paid', 7, NULL, NULL, '', ?), - (21, 'OD202607010002', 'other', '测试单位', 6000, ?, '重复录入', '', 'voided', 7, 8, ?, '重复记录', ?)`, + (20, 'OD202607010001', 'custom', '临时活动支出', '李四', 2500, ?, '用户补偿', '', 'paid', 7, NULL, NULL, '', ?), + (21, 'OD202607010002', 'other', '', '测试单位', 6000, ?, '重复录入', '', 'voided', 7, 8, ?, '重复记录', ?)`, at(6), at(5), at(7), at(8), at(5)).Error; err != nil { t.Fatal(err) } @@ -142,7 +142,7 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T) break } } - if manualItem == nil || manualItem.SourceType != "manual_offline" || manualItem.Category != "user_compensation" || manualItem.OperatorName != "财务甲" { + if manualItem == nil || manualItem.SourceType != "manual_offline" || manualItem.Category != "custom" || manualItem.CustomCategoryName != "临时活动支出" || manualItem.OperatorName != "财务甲" { t.Fatalf("其他线下出款信息不正确: %+v", manualItem) } diff --git a/backend/internal/modules/adminfinance/dto.go b/backend/internal/modules/adminfinance/dto.go index aa3981a..26aff42 100644 --- a/backend/internal/modules/adminfinance/dto.go +++ b/backend/internal/modules/adminfinance/dto.go @@ -102,45 +102,47 @@ type DisbursementListSummaryDTO struct { } type DisbursementItemDTO struct { - SourceType string `json:"source_type"` - SourceID uint64 `json:"source_id"` - BusinessNo string `json:"business_no"` - OrderID uint64 `json:"order_id,omitempty"` - WithdrawalID uint64 `json:"withdrawal_id,omitempty"` - UserID uint64 `json:"user_id"` - PayeeName string `json:"payee_name"` - PayeePhone string `json:"payee_phone"` - UploaderName string `json:"uploader_name"` - SourceChannel string `json:"source_channel"` - AccountType string `json:"account_type"` - AccountName string `json:"account_name"` - AccountNo string `json:"account_no"` - BankName string `json:"bank_name"` - AmountCent int64 `json:"amount_cent"` - FeeCent int64 `json:"fee_cent"` - ActualAmountCent int64 `json:"actual_amount_cent"` - Status string `json:"status"` - RawStatus string `json:"raw_status"` - BusinessCreatedAt *time.Time `json:"business_created_at,omitempty"` - PaidAt *time.Time `json:"paid_at,omitempty"` - OperatorID *uint64 `json:"operator_id,omitempty"` - OperatorName string `json:"operator_name"` - Remark string `json:"remark"` - Category string `json:"category"` - VoucherURL string `json:"voucher_url"` - VoidedAt *time.Time `json:"voided_at,omitempty"` - VoidedBy *uint64 `json:"voided_by,omitempty"` - VoidedByName string `json:"voided_by_name"` - VoidReason string `json:"void_reason"` + SourceType string `json:"source_type"` + SourceID uint64 `json:"source_id"` + BusinessNo string `json:"business_no"` + OrderID uint64 `json:"order_id,omitempty"` + WithdrawalID uint64 `json:"withdrawal_id,omitempty"` + UserID uint64 `json:"user_id"` + PayeeName string `json:"payee_name"` + PayeePhone string `json:"payee_phone"` + UploaderName string `json:"uploader_name"` + SourceChannel string `json:"source_channel"` + AccountType string `json:"account_type"` + AccountName string `json:"account_name"` + AccountNo string `json:"account_no"` + BankName string `json:"bank_name"` + AmountCent int64 `json:"amount_cent"` + FeeCent int64 `json:"fee_cent"` + ActualAmountCent int64 `json:"actual_amount_cent"` + Status string `json:"status"` + RawStatus string `json:"raw_status"` + BusinessCreatedAt *time.Time `json:"business_created_at,omitempty"` + PaidAt *time.Time `json:"paid_at,omitempty"` + OperatorID *uint64 `json:"operator_id,omitempty"` + OperatorName string `json:"operator_name"` + Remark string `json:"remark"` + Category string `json:"category"` + CustomCategoryName string `json:"custom_category_name"` + VoucherURL string `json:"voucher_url"` + VoidedAt *time.Time `json:"voided_at,omitempty"` + VoidedBy *uint64 `json:"voided_by,omitempty"` + VoidedByName string `json:"voided_by_name"` + VoidReason string `json:"void_reason"` } type CreateManualDisbursementRequest struct { - Category string `json:"category"` - PayeeName string `json:"payee_name"` - AmountCent int64 `json:"amount_cent"` - PaidAt time.Time `json:"paid_at"` - Remark string `json:"remark"` - VoucherURL string `json:"voucher_url"` + Category string `json:"category"` + CustomCategoryName string `json:"custom_category_name"` + PayeeName string `json:"payee_name"` + AmountCent int64 `json:"amount_cent"` + PaidAt time.Time `json:"paid_at"` + Remark string `json:"remark"` + VoucherURL string `json:"voucher_url"` } type VoidManualDisbursementRequest struct { @@ -148,22 +150,23 @@ type VoidManualDisbursementRequest struct { } type ManualDisbursementDTO struct { - ID uint64 `json:"id"` - DisbursementNo string `json:"disbursement_no"` - Category string `json:"category"` - PayeeName string `json:"payee_name"` - AmountCent int64 `json:"amount_cent"` - PaidAt time.Time `json:"paid_at"` - Remark string `json:"remark"` - VoucherURL string `json:"voucher_url"` - Status string `json:"status"` - CreatedBy uint64 `json:"created_by"` - CreatedByName string `json:"created_by_name"` - VoidedBy *uint64 `json:"voided_by,omitempty"` - VoidedByName string `json:"voided_by_name"` - VoidedAt *time.Time `json:"voided_at,omitempty"` - VoidReason string `json:"void_reason"` - CreatedAt time.Time `json:"created_at"` + ID uint64 `json:"id"` + DisbursementNo string `json:"disbursement_no"` + Category string `json:"category"` + CustomCategoryName string `json:"custom_category_name"` + PayeeName string `json:"payee_name"` + AmountCent int64 `json:"amount_cent"` + PaidAt time.Time `json:"paid_at"` + Remark string `json:"remark"` + VoucherURL string `json:"voucher_url"` + Status string `json:"status"` + CreatedBy uint64 `json:"created_by"` + CreatedByName string `json:"created_by_name"` + VoidedBy *uint64 `json:"voided_by,omitempty"` + VoidedByName string `json:"voided_by_name"` + VoidedAt *time.Time `json:"voided_at,omitempty"` + VoidReason string `json:"void_reason"` + CreatedAt time.Time `json:"created_at"` } type FinanceSummaryDTO struct { diff --git a/backend/internal/modules/adminfinance/manual_disbursement.go b/backend/internal/modules/adminfinance/manual_disbursement.go index d8e954b..1c83c24 100644 --- a/backend/internal/modules/adminfinance/manual_disbursement.go +++ b/backend/internal/modules/adminfinance/manual_disbursement.go @@ -16,21 +16,22 @@ import ( ) type manualDisbursementRecord struct { - ID uint64 - DisbursementNo string - Category string - PayeeName string - AmountCent int64 - PaidAt time.Time - Remark string - VoucherURL string - Status string - CreatedBy uint64 - VoidedBy *uint64 - VoidedAt *time.Time - VoidReason string - CreatedAt time.Time - UpdatedAt time.Time + ID uint64 + DisbursementNo string + Category string + CustomCategoryName string + PayeeName string + AmountCent int64 + PaidAt time.Time + Remark string + VoucherURL string + Status string + CreatedBy uint64 + VoidedBy *uint64 + VoidedAt *time.Time + VoidReason string + CreatedAt time.Time + UpdatedAt time.Time } func (manualDisbursementRecord) TableName() string { @@ -48,15 +49,16 @@ func (r *Repository) CreateManualDisbursement( return nil, err } record := manualDisbursementRecord{ - DisbursementNo: disbursementNo, - Category: req.Category, - PayeeName: req.PayeeName, - AmountCent: req.AmountCent, - PaidAt: req.PaidAt, - Remark: req.Remark, - VoucherURL: req.VoucherURL, - Status: "paid", - CreatedBy: adminID, + DisbursementNo: disbursementNo, + Category: req.Category, + CustomCategoryName: req.CustomCategoryName, + PayeeName: req.PayeeName, + AmountCent: req.AmountCent, + PaidAt: req.PaidAt, + Remark: req.Remark, + VoucherURL: req.VoucherURL, + Status: "paid", + CreatedBy: adminID, } err = r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Create(&record).Error; err != nil { @@ -71,12 +73,13 @@ func (r *Repository) CreateManualDisbursement( BizID: &id, Meta: meta, Detail: map[string]any{ - "disbursement_no": disbursementNo, - "category": req.Category, - "payee_name": req.PayeeName, - "amount_cent": req.AmountCent, - "paid_at": req.PaidAt, - "has_voucher": req.VoucherURL != "", + "disbursement_no": disbursementNo, + "category": req.Category, + "custom_category_name": req.CustomCategoryName, + "payee_name": req.PayeeName, + "amount_cent": req.AmountCent, + "paid_at": req.PaidAt, + "has_voucher": req.VoucherURL != "", }, }) }) @@ -153,42 +156,44 @@ func (r *Repository) findManualDisbursement(ctx context.Context, id uint64) (*Ma return nil, err } return &ManualDisbursementDTO{ - ID: row.ID, - DisbursementNo: row.DisbursementNo, - Category: row.Category, - PayeeName: row.PayeeName, - AmountCent: row.AmountCent, - PaidAt: row.PaidAt, - Remark: row.Remark, - VoucherURL: row.VoucherURL, - Status: row.Status, - CreatedBy: row.CreatedBy, - CreatedByName: row.CreatedByName, - VoidedBy: row.VoidedBy, - VoidedByName: row.VoidedByName, - VoidedAt: row.VoidedAt, - VoidReason: row.VoidReason, - CreatedAt: row.CreatedAt, + ID: row.ID, + DisbursementNo: row.DisbursementNo, + Category: row.Category, + CustomCategoryName: row.CustomCategoryName, + PayeeName: row.PayeeName, + AmountCent: row.AmountCent, + PaidAt: row.PaidAt, + Remark: row.Remark, + VoucherURL: row.VoucherURL, + Status: row.Status, + CreatedBy: row.CreatedBy, + CreatedByName: row.CreatedByName, + VoidedBy: row.VoidedBy, + VoidedByName: row.VoidedByName, + VoidedAt: row.VoidedAt, + VoidReason: row.VoidReason, + CreatedAt: row.CreatedAt, }, nil } type manualDisbursementDetailRow struct { - ID uint64 - DisbursementNo string - Category string - PayeeName string - AmountCent int64 - PaidAt time.Time - Remark string - VoucherURL string - Status string - CreatedBy uint64 - CreatedByName string - VoidedBy *uint64 - VoidedByName string - VoidedAt *time.Time - VoidReason string - CreatedAt time.Time + ID uint64 + DisbursementNo string + Category string + CustomCategoryName string + PayeeName string + AmountCent int64 + PaidAt time.Time + Remark string + VoucherURL string + Status string + CreatedBy uint64 + CreatedByName string + VoidedBy *uint64 + VoidedByName string + VoidedAt *time.Time + VoidReason string + CreatedAt time.Time } func newManualDisbursementNo() (string, error) { diff --git a/backend/internal/modules/adminfinance/manual_disbursement_test.go b/backend/internal/modules/adminfinance/manual_disbursement_test.go index 7f712e1..f9df480 100644 --- a/backend/internal/modules/adminfinance/manual_disbursement_test.go +++ b/backend/internal/modules/adminfinance/manual_disbursement_test.go @@ -21,7 +21,7 @@ func TestManualDisbursementCreateAndVoid(t *testing.T) { statements := []string{ `CREATE TABLE manual_disbursements ( id INTEGER PRIMARY KEY AUTOINCREMENT, disbursement_no TEXT NOT NULL UNIQUE, - category TEXT NOT NULL, payee_name TEXT NOT NULL, amount_cent INTEGER NOT NULL, + category TEXT NOT NULL, custom_category_name TEXT NOT NULL DEFAULT '', payee_name TEXT NOT NULL, amount_cent INTEGER NOT NULL, paid_at DATETIME NOT NULL, remark TEXT NOT NULL, voucher_url TEXT NOT NULL, status TEXT NOT NULL, created_by INTEGER NOT NULL, voided_by INTEGER, voided_at DATETIME, void_reason TEXT NOT NULL DEFAULT '', created_at DATETIME, @@ -47,17 +47,18 @@ func TestManualDisbursementCreateAndVoid(t *testing.T) { repo := NewRepository(db) paidAt := time.Date(2026, 7, 20, 9, 30, 0, 0, timeutil.ShanghaiLocation()) created, err := repo.CreateManualDisbursement(t.Context(), CreateManualDisbursementRequest{ - Category: "operating_expense", - PayeeName: "测试供应商", - AmountCent: 8800, - PaidAt: paidAt, - Remark: "测试运营支出", - VoucherURL: "/api/files/object?key=manual-disbursement%2Fvoucher.webp", + Category: "custom", + CustomCategoryName: "临时活动支出", + PayeeName: "测试供应商", + AmountCent: 8800, + PaidAt: paidAt, + Remark: "测试运营支出", + VoucherURL: "/api/files/object?key=manual-disbursement%2Fvoucher.webp", }, 7, auditlog.Meta{RequestID: "req-create"}) if err != nil { t.Fatalf("创建其他线下出款失败: %v", err) } - if created.ID == 0 || created.DisbursementNo == "" || created.Status != "paid" || created.CreatedByName != "财务甲" { + if created.ID == 0 || created.DisbursementNo == "" || created.Status != "paid" || created.CreatedByName != "财务甲" || created.CustomCategoryName != "临时活动支出" { t.Fatalf("创建结果不正确: %+v", created) } @@ -82,6 +83,13 @@ func TestManualDisbursementCreateAndVoid(t *testing.T) { } func TestManualDisbursementValidation(t *testing.T) { + if !validManualDisbursementCategory("duoduo_deposit_refund") { + t.Fatal("多多退押金分类应为有效分类") + } + if !validManualDisbursementCustomCategoryName("custom", "临时活动支出") || validManualDisbursementCustomCategoryName("custom", "") { + t.Fatal("自定义分类名称校验不正确") + } + service := NewService(&Repository{}) _, err := service.CreateManualDisbursement(t.Context(), CreateManualDisbursementRequest{ Category: "unknown", diff --git a/backend/internal/modules/adminfinance/service.go b/backend/internal/modules/adminfinance/service.go index 888972f..cbd5f48 100644 --- a/backend/internal/modules/adminfinance/service.go +++ b/backend/internal/modules/adminfinance/service.go @@ -74,10 +74,12 @@ func (s *Service) CreateManualDisbursement( return nil, ErrDependencyUnavailable } req.Category = strings.TrimSpace(req.Category) + req.CustomCategoryName = strings.TrimSpace(req.CustomCategoryName) req.PayeeName = strings.TrimSpace(req.PayeeName) req.Remark = strings.TrimSpace(req.Remark) req.VoucherURL = strings.TrimSpace(req.VoucherURL) if !validManualDisbursementCategory(req.Category) || + !validManualDisbursementCustomCategoryName(req.Category, req.CustomCategoryName) || utf8.RuneCountInString(req.PayeeName) < 1 || utf8.RuneCountInString(req.PayeeName) > 100 || req.AmountCent <= 0 || req.PaidAt.IsZero() || utf8.RuneCountInString(req.Remark) < 1 || utf8.RuneCountInString(req.Remark) > 500 || @@ -106,13 +108,20 @@ func (s *Service) VoidManualDisbursement( func validManualDisbursementCategory(category string) bool { switch category { - case "user_compensation", "seller_supplement", "operating_expense", "channel_fee", "other": + case "user_compensation", "seller_supplement", "operating_expense", "channel_fee", "duoduo_deposit_refund", "other", "custom": return true default: return false } } +func validManualDisbursementCustomCategoryName(category, name string) bool { + if category != "custom" { + return name == "" + } + return utf8.RuneCountInString(name) >= 1 && utf8.RuneCountInString(name) <= 50 +} + func validManualVoucherURL(raw string) bool { if raw == "" { return true diff --git a/backend/migrations/000053_manual_disbursement_custom_category.sql b/backend/migrations/000053_manual_disbursement_custom_category.sql new file mode 100644 index 0000000..092fa68 --- /dev/null +++ b/backend/migrations/000053_manual_disbursement_custom_category.sql @@ -0,0 +1,9 @@ +-- +goose Up + +ALTER TABLE manual_disbursements + ADD COLUMN custom_category_name VARCHAR(50) NOT NULL DEFAULT '' COMMENT '自定义出款分类名称'; + +-- +goose Down + +ALTER TABLE manual_disbursements + DROP COLUMN custom_category_name; diff --git a/frontend/src/features/admin/api/adminFinance.ts b/frontend/src/features/admin/api/adminFinance.ts index fb27d32..af0ed3c 100644 --- a/frontend/src/features/admin/api/adminFinance.ts +++ b/frontend/src/features/admin/api/adminFinance.ts @@ -144,6 +144,7 @@ export interface FinanceDisbursementItem { operator_name: string remark: string category: string + custom_category_name: string voucher_url: string voided_at?: string voided_by?: number @@ -153,6 +154,7 @@ export interface FinanceDisbursementItem { export interface CreateManualDisbursementPayload { category: string + custom_category_name?: string payee_name: string amount_cent: number paid_at: string @@ -164,6 +166,7 @@ export interface ManualDisbursement { id: number disbursement_no: string category: string + custom_category_name: string payee_name: string amount_cent: number paid_at: string diff --git a/frontend/src/features/admin/views/AdminFinanceDisbursementsView.vue b/frontend/src/features/admin/views/AdminFinanceDisbursementsView.vue index 232c913..8091178 100644 --- a/frontend/src/features/admin/views/AdminFinanceDisbursementsView.vue +++ b/frontend/src/features/admin/views/AdminFinanceDisbursementsView.vue @@ -42,10 +42,13 @@ const manualCategories = [ { value: 'seller_supplement', label: '卖家补款' }, { value: 'operating_expense', label: '运营支出' }, { value: 'channel_fee', label: '渠道费用' }, + { value: 'duoduo_deposit_refund', label: '多多退押金' }, { value: 'other', label: '其他' }, + { value: 'custom', label: '自定义分类' }, ] const createForm = reactive({ category: '', + custom_category_name: '', payee_name: '', amount_yuan: 0, paid_at: new Date(), @@ -130,6 +133,7 @@ function openCreate() { function resetCreateForm() { createForm.category = '' + createForm.custom_category_name = '' createForm.payee_name = '' createForm.amount_yuan = 0 createForm.paid_at = new Date() @@ -169,10 +173,16 @@ async function submitManualDisbursement() { ElMessage.warning('请填写出款用途') return } + if (createForm.category === 'custom' && !createForm.custom_category_name.trim()) { + ElMessage.warning('请填写自定义分类名称') + return + } createSaving.value = true try { await createManualDisbursement({ category: createForm.category, + custom_category_name: + createForm.category === 'custom' ? createForm.custom_category_name.trim() : undefined, payee_name: createForm.payee_name.trim(), amount_cent: amountCent, paid_at: createForm.paid_at.toISOString(), @@ -283,7 +293,8 @@ function itemStatusLabel(row: FinanceDisbursementItem) { return statusLabel(row.status) } -function categoryLabel(category: string) { +function categoryLabel(category: string, customCategoryName = '') { + if (category === 'custom' && customCategoryName) return customCategoryName return manualCategories.find(item => item.value === category)?.label || category || '-' } @@ -429,7 +440,7 @@ function accountTypeLabel(type: string) { {{ row.payee_phone }} 用户 ID {{ row.user_id }} - {{ categoryLabel(row.category) }} + {{ categoryLabel(row.category, row.custom_category_name) }} 联系方式未登记 上传:{{ row.uploader_name }} @@ -445,7 +456,9 @@ function accountTypeLabel(type: string) { {{ row.bank_name }}
- {{ categoryLabel(row.category) }} + + {{ categoryLabel(row.category, row.custom_category_name) }} + {{ row.voucher_url ? '已上传付款凭证' : '未上传付款凭证' }}
线下约定 @@ -545,6 +558,14 @@ function accountTypeLabel(type: string) { /> + + + @@ -634,7 +655,7 @@ function accountTypeLabel(type: string) { - {{ categoryLabel(selectedManual.category) }} + {{ categoryLabel(selectedManual.category, selectedManual.custom_category_name) }} {{ selectedManual.payee_name }}