Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
template: testify
force-file-write: true
formatter: goimports
packages:
github.com/CsJsss/CS2Ledger/pkg/platform: {}
36 changes: 36 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/CsJsss/CS2Ledger/pkg/model"
"github.com/CsJsss/CS2Ledger/pkg/platform"
"github.com/CsJsss/CS2Ledger/pkg/service"
"github.com/CsJsss/CS2Ledger/pkg/service/bill"
"github.com/CsJsss/CS2Ledger/pkg/service/inventory"
"github.com/CsJsss/CS2Ledger/pkg/service/market"
"github.com/CsJsss/CS2Ledger/pkg/service/pnl"
Expand Down Expand Up @@ -189,6 +190,9 @@ func (a *App) GetDashboardSummary() (*DashboardSummary, error) {
ds.CompletedTrades += summary.TotalTrades
ds.RealizedPl += summary.TotalNetPl
}
// Rental income from bill records: 租金 + 续租 - 服务费
rentalIncome, _ := a.svc.Bill().SumRentalIncome(acc.ID)
ds.TotalRentalIncome += rentalIncome
}
return ds, nil
}
Expand All @@ -197,6 +201,38 @@ func (a *App) GetRentalHistory(accountID uint, assetID string) ([]model.RentalRe
return a.svc.Rental().ListByAsset(accountID, assetID)
}

func (a *App) GetBillRecords(accountID uint, page, pageSize int, typeID int, platform string, startTime, endTime int64) (*bill.PaginatedBills, error) {
return a.svc.Bill().List(accountID, page, pageSize, bill.BillFilter{
TypeID: typeID,
Platform: platform,
StartTime: startTime,
EndTime: endTime,
})
}

// DailyBillPoint is pre-aggregated daily bill totals for charts.
type DailyBillPoint struct {
Date string `json:"date"` // "2006-01-02"
TypeID int `json:"typeId"`
ThisMoney int64 `json:"thisMoney"`
}

// GetBillChartData returns daily-aggregated bill data for chart rendering.
func (a *App) GetBillChartData(accountID uint, startTime, endTime int64) ([]DailyBillPoint, error) {
rows, err := a.svc.Bill().ChartData(accountID, bill.BillFilter{
StartTime: startTime,
EndTime: endTime,
})
if err != nil {
return nil, err
}
points := make([]DailyBillPoint, len(rows))
for i, r := range rows {
points[i] = DailyBillPoint{Date: r.Date, TypeID: r.TypeID, ThisMoney: r.ThisMoney}
}
return points, nil
}

type UserSettings struct {
PriceSource string `json:"priceSource"`
PriceCacheTTL int `json:"priceCacheTtl"`
Expand Down
80 changes: 80 additions & 0 deletions cmd/platform-cli/cli/billhistory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package cli

import (
"context"
"fmt"
"os"
"text/tabwriter"
"time"

"github.com/CsJsss/CS2Ledger/pkg/platform"
"github.com/spf13/cobra"
)

var billhistoryCmd = &cobra.Command{
Use: "billhistory <platform>",
Short: "Fetch bill / fund flow history from a platform",
Args: cobra.ExactArgs(1),
ValidArgs: validPlatforms,
RunE: runBillHistory,
}

func init() {
billhistoryCmd.Flags().Int("limit", 10, "Max records to show")
billhistoryCmd.Flags().Int64("since", 0, "Unix millisecond timestamp (0 = all)")
billhistoryCmd.Flags().Bool("raw", false, "Output raw JSON")
billhistoryCmd.Flags().Int("page", 0, "Single page to fetch (0 = all pages)")
billhistoryCmd.Flags().Int("pageSize", 0, "Page size (0 = default 20)")
}

func runBillHistory(cmd *cobra.Command, args []string) error {
platformName := args[0]
token, err := resolveToken(cmd, platformName)
if err != nil {
return err
}
client, err := createClient(platformName, token)
if err != nil {
return err
}

limit, _ := cmd.Flags().GetInt("limit")
since, _ := cmd.Flags().GetInt64("since")
raw, _ := cmd.Flags().GetBool("raw")
page, _ := cmd.Flags().GetInt("page")
pageSize, _ := cmd.Flags().GetInt("pageSize")

opts := []platform.QueryOption{platform.WithSince(since), platform.WithLimit(limit)}
if page > 0 {
opts = append(opts, platform.WithPage(page))
}
if pageSize > 0 {
opts = append(opts, platform.WithPageSize(pageSize))
}

bills, err := client.GetBillHistory(context.Background(), opts...)
if err != nil {
return err
}
if raw {
printBillsRaw(bills)
} else {
printBillsTable(bills)
}
return nil
}

func printBillsTable(bills []platform.BillRecord) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
_, _ = fmt.Fprintln(w, "TYPE\tTYPE ID\tMONEY\tORDER NO\tTIME")
for _, b := range bills {
_, _ = fmt.Fprintf(w, "%s\t%d\t%.2f\t%s\t%s\n",
b.TypeName,
b.TypeID,
float64(b.ThisMoney)/100.0,
b.OrderNo,
time.UnixMilli(b.AddTime).Format(time.DateTime),
)
}
_ = w.Flush()
}
8 changes: 8 additions & 0 deletions cmd/platform-cli/cli/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import (
"github.com/CsJsss/CS2Ledger/pkg/platform"
)

func printBillsRaw(bills []platform.BillRecord) {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(bills); err != nil {
fmt.Fprintf(os.Stderr, "encode: %v\n", err)
}
}

func printTradesRaw(trades []platform.TradeRecord) {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
Expand Down
1 change: 1 addition & 0 deletions cmd/platform-cli/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func init() {
rootCmd.AddCommand(balanceCmd)
rootCmd.AddCommand(buyhistoryCmd)
rootCmd.AddCommand(sellhistoryCmd)
rootCmd.AddCommand(billhistoryCmd)
}

func Execute() {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import InventoryPage from './pages/InventoryPage';
import InventoryDetailPage from './pages/InventoryDetailPage';
import CompletedTradesPage from './pages/CompletedTradesPage';
import PnLPage from './pages/PnLPage';
import BillPage from './pages/BillPage';
import AccountsPage from './pages/AccountsPage';
import SettingsPage from './pages/SettingsPage';

Expand All @@ -19,6 +20,7 @@ export default function App() {
<Route path="trades" element={<Navigate to="/trades/completed" replace />} />
<Route path="trades/completed" element={<CompletedTradesPage />} />
<Route path="pnl" element={<PnLPage />} />
<Route path="bill" element={<BillPage />} />
<Route path="accounts" element={<AccountsPage />} />
<Route path="settings" element={<SettingsPage />} />
</Route>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const navItems = [
{ to: '/inventory', label: '持仓', icon: <InventoryIcon fontSize="small" /> },
{ to: '/trades/completed', label: '交易记录', icon: <ReceiptIcon fontSize="small" /> },
{ to: '/pnl', label: '盈亏', icon: <TrendingUpIcon fontSize="small" /> },
{ to: '/bill', label: '资金流水', icon: <ReceiptIcon fontSize="small" /> },
{ to: '/accounts', label: '账户管理', icon: <AccountBalanceIcon fontSize="small" /> },
{ to: '/settings', label: '设置', icon: <SettingsIcon fontSize="small" /> },
];
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/hooks/useBillRecords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useQuery } from '@tanstack/react-query';
import { GetBillRecords, GetBillChartData } from '../lib/wails';

interface UseBillRecordsOpts {
page?: number;
pageSize?: number;
typeId?: number;
platform?: string;
startTime?: number;
endTime?: number;
}

export function useBillRecords(accountId: number | null, opts?: UseBillRecordsOpts) {
const page = opts?.page ?? 1;
const pageSize = opts?.pageSize ?? 20;
const typeId = opts?.typeId ?? 0;
const platform = opts?.platform ?? '';
const startTime = opts?.startTime ?? 0;
const endTime = opts?.endTime ?? 0;

return useQuery({
queryKey: ['billRecords', accountId ?? 0, page, pageSize, typeId, platform, startTime, endTime],
queryFn: () =>
GetBillRecords(accountId ?? 0, page, pageSize, typeId, platform, startTime, endTime),
staleTime: 2 * 60 * 1000,
placeholderData: (prev) => prev,
});
}

/** Pre-aggregated daily bill data for chart rendering. */
export function useBillChartData(accountId: number | null, startTime?: number, endTime?: number) {
return useQuery({
queryKey: ['billChartData', accountId ?? 0, startTime ?? 0, endTime ?? 0],
queryFn: () => GetBillChartData(accountId ?? 0, startTime ?? 0, endTime ?? 0),
staleTime: 2 * 60 * 1000,
});
}
4 changes: 4 additions & 0 deletions frontend/src/lib/wails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
GetMonthlyBreakdown,
GetDashboardSummary,
GetRentalHistory,
GetBillRecords,
GetBillChartData,
GetMarketPrices,
GetSettings,
UpdateSettings,
Expand All @@ -36,6 +38,8 @@ export {
GetMonthlyBreakdown,
GetDashboardSummary,
GetRentalHistory,
GetBillRecords,
GetBillChartData,
GetMarketPrices,
GetSettings,
UpdateSettings,
Expand Down
Loading
Loading