feat(bill):优化计费功能

This commit is contained in:
qian committed 2026-05-22 23:29:22 +08:00
1 parent 386b596fb5
commit 5b7085f3b7
7 files changed
+7 -115

No files matched your search

-1
View File
@@ -31,7 +31,6 @@ type ITenantV1 interface {
TenantSessionList(ctx context.Context, req *v1.TenantSessionListReq) (res *v1.TenantSessionListRes, err error)
TenantRevokeSession(ctx context.Context, req *v1.TenantRevokeSessionReq) (res *v1.TenantRevokeSessionRes, err error)
TenantUsageLogs(ctx context.Context, req *v1.TenantUsageLogsReq) (res *v1.TenantUsageLogsRes, err error)
TenantBillingRecords(ctx context.Context, req *v1.TenantBillingRecordsReq) (res *v1.TenantBillingRecordsRes, err error)
TenantUsageLogsExport(ctx context.Context, req *v1.TenantUsageLogsExportReq) (res *v1.TenantUsageLogsExportRes, err error)
TenantRequestClosure(ctx context.Context, req *v1.TenantRequestClosureReq) (res *v1.TenantRequestClosureRes, err error)
TenantCancelClosure(ctx context.Context, req *v1.TenantCancelClosureReq) (res *v1.TenantCancelClosureRes, err error)
-13
View File
@@ -23,19 +23,6 @@ type TenantUsageLogsRes struct {
PageSize int `json:"page_size"`
}
type TenantBillingRecordsReq struct {
g.Meta `path:"/billing-records" method:"get" mime:"json" tags:"租户控制台-用量" summary:"账单记录"`
Page int `json:"page" in:"query" d:"1"`
PageSize int `json:"page_size" in:"query" d:"20"`
}
type TenantBillingRecordsRes struct {
List []map[string]any `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// TenantUsageLogsExportReq 导出用量日志请求
type TenantUsageLogsExportReq struct {
g.Meta `path:"/usage-logs/export" method:"get" mime:"json" tags:"租户控制台-用量" summary:"导出用量日志"`
@@ -1,12 +0,0 @@
package tenant
import (
"context"
"github.com/qianfree/team-api/api/tenant/v1"
"github.com/qianfree/team-api/internal/service"
)
func (c *ControllerV1) TenantBillingRecords(ctx context.Context, req *v1.TenantBillingRecordsReq) (res *v1.TenantBillingRecordsRes, err error) {
return service.Tenant().BillingRecords(ctx, req)
}
-84
View File
@@ -147,90 +147,6 @@ func (s *sTenant) WalletTransactions(ctx context.Context, req *v1.TenantWalletTr
}, nil
}
// BillingRecords 获取租户计费记录
func (s *sTenant) BillingRecords(ctx context.Context, req *v1.TenantBillingRecordsReq) (*v1.TenantBillingRecordsRes, error) {
tenantID := ctxTenantID(ctx)
userID := ctxUserID(ctx)
role := ctxUserRole(ctx)
page, pageSize := common.NormalizePagination(req.Page, req.PageSize)
query := dao.BilRecords.Ctx(ctx).
Where("bil_records.tenant_id", tenantID)
// member 角色只能查看自己的账单记录
if role == "member" {
query = query.Where("bil_records.user_id", userID)
}
type billingRecordRow struct {
Id int64 `json:"id"`
ModelName string `json:"model_name"`
RelayMode string `json:"relay_mode"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
InputPrice float64 `json:"input_price"`
OutputPrice float64 `json:"output_price"`
TotalCost float64 `json:"total_cost"`
Currency string `json:"currency"`
Status string `json:"status"`
SettledAt *gtime.Time `json:"settled_at"`
CreatedAt *gtime.Time `json:"created_at"`
RequestId string `json:"request_id"`
UserId int64 `json:"user_id"`
Username string `json:"username"`
ProjectId int64 `json:"project_id"`
ProjectName string `json:"project_name"`
ApiKeyId int64 `json:"api_key_id"`
ApiKeyName string `json:"api_key_name"`
}
var records []billingRecordRow
var err error
var total int
err = query.Fields("bil_records.id, bil_records.model_name, bil_records.relay_mode, bil_records.input_tokens, bil_records.output_tokens, bil_records.input_price, bil_records.output_price, bil_records.total_cost, bil_records.currency, bil_records.status, bil_records.settled_at, bil_records.created_at, bil_records.request_id, bil_records.user_id, COALESCE(tu.username, '') AS username, bil_records.api_key_id, COALESCE(ak.name, '') AS api_key_name").
LeftJoin("tnt_users tu", "bil_records.user_id = tu.id AND bil_records.tenant_id = tu.tenant_id").
LeftJoin("api_keys ak", "bil_records.api_key_id = ak.id AND bil_records.tenant_id = ak.tenant_id").
OrderDesc("bil_records.created_at").
Page(page, pageSize).
ScanAndCount(&records, &total, false)
if err != nil {
return nil, err
}
if records == nil {
records = []billingRecordRow{}
}
list := make([]map[string]any, 0, len(records))
for _, r := range records {
list = append(list, map[string]any{
"id": r.Id,
"model_name": r.ModelName,
"relay_mode": r.RelayMode,
"input_tokens": r.InputTokens,
"output_tokens": r.OutputTokens,
"input_price": r.InputPrice,
"output_price": r.OutputPrice,
"total_cost": r.TotalCost,
"currency": r.Currency,
"status": r.Status,
"settled_at": r.SettledAt,
"created_at": r.CreatedAt,
"request_id": r.RequestId,
"user_id": r.UserId,
"username": r.Username,
"api_key_id": r.ApiKeyId,
"api_key_name": r.ApiKeyName,
})
}
return &v1.TenantBillingRecordsRes{
List: list,
Total: total,
Page: page,
PageSize: pageSize,
}, nil
}
// UsageLogs 获取租户用量日志
func (s *sTenant) UsageLogs(ctx context.Context, req *v1.TenantUsageLogsReq) (*v1.TenantUsageLogsRes, error) {
tenantID := ctxTenantID(ctx)
-2
View File
@@ -57,8 +57,6 @@ type (
Wallet(ctx context.Context, req *v1.TenantWalletReq) (*v1.TenantWalletRes, error)
// WalletTransactions 获取租户钱包流水
WalletTransactions(ctx context.Context, req *v1.TenantWalletTransactionsReq) (*v1.TenantWalletTransactionsRes, error)
// BillingRecords 获取租户计费记录
BillingRecords(ctx context.Context, req *v1.TenantBillingRecordsReq) (*v1.TenantBillingRecordsRes, error)
// UsageLogs 获取租户用量日志
UsageLogs(ctx context.Context, req *v1.TenantUsageLogsReq) (*v1.TenantUsageLogsRes, error)
// ExportUsageLogs exports the tenant usage logs as CSV or Excel.
+2 -2
View File
@@ -139,8 +139,8 @@ const tenantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/finance/TransactionsPage.vue'),
meta: { title: '交易记录', icon: 'document', sort: 41, roles: ['owner', 'admin'] },
},
{
path: 'orders',
{
path: 'orders',
name: 'TenantOrders',
component: () => import('@/views/finance/OrdersPage.vue'),
meta: { title: '订单记录', icon: 'receipt', sort: 42, roles: ['owner', 'admin'] },
@@ -772,7 +772,7 @@ onMounted(() => {
</div>
<!-- 结算明细 -->
<div v-if="detailLog.pre_deduct_amount > 0 || detailLog.refund_amount > 0 || detailLog.supplement_amount > 0">
<div v-if="detailLog.pre_deduct_amount > 0 || detailLog.refund_amount > 0 || detailLog.supplement_amount > 0 || detailLog.settled_at">
<h4 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2">
<Icon name="refresh" size="sm" class="text-primary-500" />
结算明细
@@ -790,6 +790,10 @@ onMounted(() => {
<span class="text-gray-500">补扣金额</span>
<span class="text-amber-600">{{ formatCost(detailLog.supplement_amount) }}</span>
</div>
<div v-if="detailLog.settled_at" class="flex items-center justify-between">
<span class="text-gray-500">结算时间</span>
<span>{{ formatTime(detailLog.settled_at) }}</span>
</div>
</div>
</div>