From 65965c409f9273fe99ab66f34a9b50f14da18e4a Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 28 May 2026 00:56:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=97=A5=E5=BF=97=E6=8C=81=E4=B9=85?= =?UTF-8?q?=E5=8C=96=E5=AD=98=E5=82=A8=E5=88=B0=E6=96=87=E4=BB=B6+?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E5=90=8E=E5=8F=B0=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?/=E6=B8=85=E7=A9=BA=E6=97=A5=E5=BF=97=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/cmd/server/main.go | 1 + backend/internal/api/handlers/log.go | 74 ++++++ backend/internal/api/routes/routes.go | 5 + backend/internal/utils/logger.go | 94 ++++++++ frontend/src/api/index.ts | 4 + frontend/src/layouts/AdminLayout.vue | 7 +- frontend/src/router/index.ts | 1 + frontend/src/views/Install.vue | 2 - frontend/src/views/admin/Logs.vue | 261 ++++++++++++++++++++++ frontend/src/views/user/Lotteries.vue | 2 +- frontend/src/views/user/ProductDetail.vue | 2 +- logs.txt | 244 +++----------------- 12 files changed, 473 insertions(+), 224 deletions(-) create mode 100644 backend/internal/api/handlers/log.go create mode 100644 backend/internal/utils/logger.go create mode 100644 frontend/src/views/admin/Logs.vue diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 576f375..e23b0bc 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -14,6 +14,7 @@ func main() { config.Load() utils.InitDB() + utils.InitLogger() utils.AutoMigrate() if config.AppConfig.Server.Mode == "release" { diff --git a/backend/internal/api/handlers/log.go b/backend/internal/api/handlers/log.go new file mode 100644 index 0000000..f477db3 --- /dev/null +++ b/backend/internal/api/handlers/log.go @@ -0,0 +1,74 @@ +package handlers + +import ( + "fmt" + "net/http" + "strconv" + + "sale/internal/utils" + + "github.com/gin-gonic/gin" +) + +type LogHandler struct{} + +func NewLogHandler() *LogHandler { + return &LogHandler{} +} + +func (h *LogHandler) GetLogs(c *gin.Context) { + lines := 500 + if l := c.Query("lines"); l != "" { + if v, err := strconv.Atoi(l); err == nil && v > 0 { + lines = v + } + } + + logs, err := utils.GetLogs(lines) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read logs"}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": logs}) +} + +func (h *LogHandler) ClearLogs(c *gin.Context) { + if err := utils.ClearLogs(); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to clear logs"}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "Logs cleared successfully"}) +} + +func (h *LogHandler) GetLogInfo(c *gin.Context) { + size, err := utils.GetLogSize() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get log info"}) + return + } + + modTime, err := utils.GetLogModTime() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get log info"}) + return + } + + var sizeStr string + if size >= 1024*1024 { + sizeStr = fmt.Sprintf("%.2f MB", float64(size)/(1024*1024)) + } else if size >= 1024 { + sizeStr = fmt.Sprintf("%.2f KB", float64(size)/1024) + } else { + sizeStr = fmt.Sprintf("%d B", size) + } + + c.JSON(http.StatusOK, gin.H{ + "data": gin.H{ + "size": size, + "size_str": sizeStr, + "mod_time": modTime, + }, + }) +} diff --git a/backend/internal/api/routes/routes.go b/backend/internal/api/routes/routes.go index 2a5444e..c283338 100644 --- a/backend/internal/api/routes/routes.go +++ b/backend/internal/api/routes/routes.go @@ -25,6 +25,7 @@ func SetupRoutes(r *gin.Engine) { bannerHandler := handlers.NewBannerHandler() paymentChannelHandler := handlers.NewPaymentChannelHandler() paymentHandler := handlers.NewPaymentHandler() + logHandler := handlers.NewLogHandler() r.Use(middlewares.CORSMiddleware()) @@ -235,6 +236,10 @@ func SetupRoutes(r *gin.Engine) { adminPaymentChannels.DELETE("/:id", paymentChannelHandler.Delete) adminPaymentChannels.PUT("/:id/toggle", paymentChannelHandler.Toggle) } + + admin.GET("/logs", logHandler.GetLogs) + admin.DELETE("/logs", logHandler.ClearLogs) + admin.GET("/logs/info", logHandler.GetLogInfo) } } } diff --git a/backend/internal/utils/logger.go b/backend/internal/utils/logger.go new file mode 100644 index 0000000..9fd9c4b --- /dev/null +++ b/backend/internal/utils/logger.go @@ -0,0 +1,94 @@ +package utils + +import ( + "bufio" + "io" + "log" + "os" + "path/filepath" +) + +var logFilePath = "data/app.log" + +func InitLogger() { + logDir := filepath.Dir(logFilePath) + if logDir != "." && logDir != "/" { + if err := os.MkdirAll(logDir, 0755); err != nil { + log.Fatalf("Failed to create log directory %s: %v", logDir, err) + } + } + + file, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + log.Fatalf("Failed to open log file %s: %v", logFilePath, err) + } + + multiWriter := io.MultiWriter(os.Stdout, file) + log.SetOutput(multiWriter) + + log.Printf("Logger initialized, log file: %s", logFilePath) +} + +func GetLogs(lines int) ([]string, error) { + file, err := os.Open(logFilePath) + if err != nil { + return nil, err + } + defer file.Close() + + ring := make([]string, 0, lines) + idx := 0 + + scanner := bufio.NewScanner(file) + buf := make([]byte, 0, 64*1024) + scanner.Buffer(buf, 1024*1024) + + for scanner.Scan() { + line := scanner.Text() + if len(ring) < cap(ring) { + ring = append(ring, line) + } else { + ring[idx] = line + } + idx = (idx + 1) % cap(ring) + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + if len(ring) < cap(ring) { + return ring, nil + } + + result := make([]string, len(ring)) + for i := 0; i < len(ring); i++ { + result[i] = ring[(idx+i)%len(ring)] + } + return result, nil +} + +func ClearLogs() error { + file, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer file.Close() + return nil +} + +func GetLogSize() (int64, error) { + info, err := os.Stat(logFilePath) + if err != nil { + return 0, err + } + return info.Size(), nil +} + +func GetLogModTime() (interface{}, error) { + info, err := os.Stat(logFilePath) + if err != nil { + return nil, err + } + return info.ModTime(), nil +} diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index de82028..44cd3c4 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -180,4 +180,8 @@ export const adminApi = { updatePaymentChannel: (id: number, data: any) => api.put(`/admin/payment-channels/${id}`, data), deletePaymentChannel: (id: number) => api.delete(`/admin/payment-channels/${id}`), togglePaymentChannel: (id: number) => api.put(`/admin/payment-channels/${id}/toggle`), + + getLogs: (lines?: number) => api.get('/admin/logs', { params: { lines: lines || 500 } }), + clearLogs: () => api.delete('/admin/logs'), + getLogInfo: () => api.get('/admin/logs/info'), } diff --git a/frontend/src/layouts/AdminLayout.vue b/frontend/src/layouts/AdminLayout.vue index 6c6e8b3..320b474 100644 --- a/frontend/src/layouts/AdminLayout.vue +++ b/frontend/src/layouts/AdminLayout.vue @@ -61,6 +61,10 @@ {{ $t('admin.paymentManagement') }} + + + 日志管理 + {{ $t('admin.systemSettings') }} @@ -160,7 +164,7 @@ import { ref, computed } from 'vue' import { useRouter, useRoute } from 'vue-router' import { useI18n } from 'vue-i18n' -import { DataAnalysis, User, Folder, Stamp, Goods, List, Van, Trophy, ChatDotSquare, Setting, Document, Picture, Compass, Fold, Expand, HomeFilled, FullScreen, ArrowDown, SwitchButton, ArrowRight, Wallet } from '@element-plus/icons-vue' +import { DataAnalysis, User, Folder, Stamp, Goods, List, Van, Trophy, ChatDotSquare, Setting, Document, Picture, Compass, Fold, Expand, HomeFilled, FullScreen, ArrowDown, SwitchButton, ArrowRight, Wallet, Notebook } from '@element-plus/icons-vue' import { useUserStore } from '../store/user' import { useCartStore } from '../store/cart' @@ -187,6 +191,7 @@ const pageTitles: Record = { '/admin/articles': '资讯管理', '/admin/banners': '轮播图管理', '/admin/payment': '支付管理', + '/admin/logs': '日志管理', '/admin/settings': '系统设置' } diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index d4268b1..ba0b323 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -51,6 +51,7 @@ const routes = [ { path: 'articles', name: 'AdminArticles', component: () => import('../views/admin/Articles.vue') }, { path: 'banners', name: 'AdminBanners', component: () => import('../views/admin/Banners.vue') }, { path: 'payment', name: 'AdminPayment', component: () => import('../views/admin/PaymentChannels.vue') }, + { path: 'logs', name: 'AdminLogs', component: () => import('../views/admin/Logs.vue') }, ], }, { diff --git a/frontend/src/views/Install.vue b/frontend/src/views/Install.vue index b9462e3..8f8c692 100644 --- a/frontend/src/views/Install.vue +++ b/frontend/src/views/Install.vue @@ -35,12 +35,10 @@ + + diff --git a/frontend/src/views/user/Lotteries.vue b/frontend/src/views/user/Lotteries.vue index 13b4a6d..a41bcae 100644 --- a/frontend/src/views/user/Lotteries.vue +++ b/frontend/src/views/user/Lotteries.vue @@ -37,7 +37,7 @@ function formatDate(date: string) { async function fetchLotteries() { loading.value = true - const res: any = await lotteryApi.list({ page: page.value, page_size: pageSize }) + const res: any = await lotteryApi.list() lotteries.value = res.data || [] total.value = res.pagination?.total || res.data?.length || 0 loading.value = false diff --git a/frontend/src/views/user/ProductDetail.vue b/frontend/src/views/user/ProductDetail.vue index 60ff481..b724d6e 100644 --- a/frontend/src/views/user/ProductDetail.vue +++ b/frontend/src/views/user/ProductDetail.vue @@ -74,7 +74,7 @@ const quantity = ref(1) const productImages = computed(() => { if (!product.value?.images) return [] - return product.value.images.split(',').map((s: string) => s.trim()).filter(Boolean).map(url => getImageUrl(url)) + return product.value.images.split(',').map((s: string) => s.trim()).filter(Boolean).map((url: string) => getImageUrl(url)) }) onMounted(async () => { diff --git a/logs.txt b/logs.txt index b703d83..38b6010 100644 --- a/logs.txt +++ b/logs.txt @@ -1,219 +1,25 @@ -sale | 2026/05/25 05:13:32 Database connected successfully (driver: sqlite) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.273ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="users" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [2.703ms] [rows:0] CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT,`username` text NOT NULL,`email` text NOT NULL,`password_hash` text NOT NULL,`role` text NOT NULL DEFAULT "user",`purchase_credits` integer DEFAULT 0,`invite_code` text,`referred_by` integer,`email_verified` numeric DEFAULT false,`is_active` numeric DEFAULT true,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.166ms] [rows:0] CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.760ms] [rows:0] CREATE UNIQUE INDEX `idx_users_invite_code` ON `users`(`invite_code`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.411ms] [rows:0] CREATE UNIQUE INDEX `idx_users_email` ON `users`(`email`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.077ms] [rows:0] CREATE UNIQUE INDEX `idx_users_username` ON `users`(`username`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.049ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="categories" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.797ms] [rows:0] CREATE TABLE `categories` (`id` integer PRIMARY KEY AUTOINCREMENT,`name` text NOT NULL,`description` text,`parent_id` integer,`min_amount` real,`max_amount` real,`min_quantity` integer,`max_quantity` integer,`min_weight` real,`max_weight` real,`sort_order` integer DEFAULT 0,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_categories_children` FOREIGN KEY (`parent_id`) REFERENCES `categories`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.936ms] [rows:0] CREATE INDEX `idx_categories_deleted_at` ON `categories`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.103ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="brands" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [2.034ms] [rows:0] CREATE TABLE `brands` (`id` integer PRIMARY KEY AUTOINCREMENT,`name` text NOT NULL,`description` text,`logo` text,`sort_order` integer DEFAULT 0,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.806ms] [rows:0] CREATE INDEX `idx_brands_deleted_at` ON `brands`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.792ms] [rows:0] CREATE UNIQUE INDEX `idx_brands_name` ON `brands`(`name`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.038ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="products" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.787ms] [rows:0] CREATE TABLE `products` (`id` integer PRIMARY KEY AUTOINCREMENT,`name` text NOT NULL,`description` text,`price` decimal(10,2) NOT NULL,`min_purchase` integer DEFAULT 1,`max_purchase` integer,`min_weight` real,`max_weight` real,`min_amount` real,`max_amount` real,`require_credit` numeric DEFAULT false,`credit_cost` integer DEFAULT 0,`credit_reward` integer DEFAULT 0,`images` text,`is_active` numeric DEFAULT true,`brand_id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_products_brand` FOREIGN KEY (`brand_id`) REFERENCES `brands`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.664ms] [rows:0] CREATE INDEX `idx_products_deleted_at` ON `products`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.032ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="product_categories" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.803ms] [rows:0] CREATE TABLE `product_categories` (`product_id` integer,`category_id` integer,PRIMARY KEY (`product_id`,`category_id`),CONSTRAINT `fk_product_categories_product` FOREIGN KEY (`product_id`) REFERENCES `products`(`id`),CONSTRAINT `fk_product_categories_category` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.031ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="product_custom_fields" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [2.133ms] [rows:0] CREATE TABLE `product_custom_fields` (`id` integer PRIMARY KEY AUTOINCREMENT,`product_id` integer NOT NULL,`field_name` text NOT NULL,`field_value` text,`created_at` datetime,CONSTRAINT `fk_products_custom_fields` FOREIGN KEY (`product_id`) REFERENCES `products`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.875ms] [rows:0] CREATE INDEX `idx_product_custom_fields_product_id` ON `product_custom_fields`(`product_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.031ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="inventory" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.744ms] [rows:0] CREATE TABLE `inventory` (`id` integer PRIMARY KEY AUTOINCREMENT,`product_id` integer NOT NULL,`supplier_id` integer NOT NULL,`quantity` integer DEFAULT 0,`updated_at` datetime) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.152ms] [rows:0] CREATE INDEX `idx_inventory_supplier_id` ON `inventory`(`supplier_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.952ms] [rows:0] CREATE INDEX `idx_inventory_product_id` ON `inventory`(`product_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.037ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="carts" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.982ms] [rows:0] CREATE TABLE `carts` (`id` integer PRIMARY KEY AUTOINCREMENT,`user_id` integer NOT NULL,`product_id` integer NOT NULL,`quantity` integer NOT NULL,`created_at` datetime,`updated_at` datetime,CONSTRAINT `fk_carts_product` FOREIGN KEY (`product_id`) REFERENCES `products`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.824ms] [rows:0] CREATE INDEX `idx_carts_product_id` ON `carts`(`product_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.857ms] [rows:0] CREATE INDEX `idx_carts_user_id` ON `carts`(`user_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.031ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="addresses" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.888ms] [rows:0] CREATE TABLE `addresses` (`id` integer PRIMARY KEY AUTOINCREMENT,`user_id` integer NOT NULL,`name` text NOT NULL,`phone` text NOT NULL,`province` text,`city` text,`district` text,`address` text NOT NULL,`is_default` numeric DEFAULT false,`created_at` datetime,`updated_at` datetime) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.821ms] [rows:0] CREATE INDEX `idx_addresses_user_id` ON `addresses`(`user_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.031ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="orders" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [2.168ms] [rows:0] CREATE TABLE `orders` (`id` integer PRIMARY KEY AUTOINCREMENT,`user_id` integer NOT NULL,`supplier_id` integer,`subtotal` decimal(10,2) NOT NULL,`shipping_fee` decimal(10,2) DEFAULT 0,`service_fee` decimal(10,2) DEFAULT 0,`tax` decimal(10,2) DEFAULT 0,`total_amount` decimal(10,2) NOT NULL,`refund_amount` decimal(10,2),`refund_status` text,`refund_reason` text,`status` text NOT NULL DEFAULT "pending_payment",`shipping_address_id` integer,`tracking_number` text,`shipping_photo` text,`express_photo` text,`customs_photo` text,`payment_method` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_orders_shipping_address` FOREIGN KEY (`shipping_address_id`) REFERENCES `addresses`(`id`),CONSTRAINT `fk_orders_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.849ms] [rows:0] CREATE INDEX `idx_orders_deleted_at` ON `orders`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.702ms] [rows:0] CREATE INDEX `idx_orders_supplier_id` ON `orders`(`supplier_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.699ms] [rows:0] CREATE INDEX `idx_orders_user_id` ON `orders`(`user_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.039ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="order_items" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [1.808ms] [rows:0] CREATE TABLE `order_items` (`id` integer PRIMARY KEY AUTOINCREMENT,`order_id` integer NOT NULL,`product_id` integer NOT NULL,`quantity` integer NOT NULL,`price` decimal(10,2) NOT NULL,CONSTRAINT `fk_order_items_product` FOREIGN KEY (`product_id`) REFERENCES `products`(`id`),CONSTRAINT `fk_orders_order_items` FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`)) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.797ms] [rows:0] CREATE INDEX `idx_order_items_product_id` ON `order_items`(`product_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.782ms] [rows:0] CREATE INDEX `idx_order_items_order_id` ON `order_items`(`order_id`) -sale | -sale | 2026/05/25 05:13:32 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.033ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="lotteries" -sale | -sale | 2026/05/25 05:13:32 /app/backend/internal/utils/database.go:54 -sale | [2.053ms] [rows:0] CREATE TABLE `lotteries` (`id` integer PRIMARY KEY AUTOINCREMENT,`name` text NOT NULL,`description` text,`image` text,`start_time` datetime,`end_time` datetime,`cycle` text,`daily_quota` integer,`total_quota` integer,`registration_validity` integer,`is_active` numeric DEFAULT true,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.951ms] [rows:0] CREATE INDEX `idx_lotteries_deleted_at` ON `lotteries`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.037ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="lottery_prizes" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [2.128ms] [rows:0] CREATE TABLE `lottery_prizes` (`id` integer PRIMARY KEY AUTOINCREMENT,`lottery_id` integer NOT NULL,`name` text NOT NULL,`type` text NOT NULL,`quantity` integer NOT NULL,`weight` integer DEFAULT 1,`credit_reward` integer,`draw_mode` text DEFAULT "random",CONSTRAINT `fk_lotteries_prizes` FOREIGN KEY (`lottery_id`) REFERENCES `lotteries`(`id`)) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.107ms] [rows:0] CREATE INDEX `idx_lottery_prizes_lottery_id` ON `lottery_prizes`(`lottery_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.041ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="lottery_participants" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [2.759ms] [rows:0] CREATE TABLE `lottery_participants` (`id` integer PRIMARY KEY AUTOINCREMENT,`lottery_id` integer NOT NULL,`user_id` integer NOT NULL,`purchase_weight` integer DEFAULT 0,`registered_at` datetime) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.771ms] [rows:0] CREATE INDEX `idx_lottery_participants_user_id` ON `lottery_participants`(`user_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.999ms] [rows:0] CREATE INDEX `idx_lottery_participants_lottery_id` ON `lottery_participants`(`lottery_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.042ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="lottery_winners" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [1.949ms] [rows:0] CREATE TABLE `lottery_winners` (`id` integer PRIMARY KEY AUTOINCREMENT,`lottery_id` integer NOT NULL,`prize_id` integer NOT NULL,`user_id` integer NOT NULL,`drawn_at` datetime) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.475ms] [rows:0] CREATE INDEX `idx_lottery_winners_user_id` ON `lottery_winners`(`user_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.571ms] [rows:0] CREATE INDEX `idx_lottery_winners_prize_id` ON `lottery_winners`(`prize_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [2.174ms] [rows:0] CREATE INDEX `idx_lottery_winners_lottery_id` ON `lottery_winners`(`lottery_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.044ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="tickets" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [2.120ms] [rows:0] CREATE TABLE `tickets` (`id` integer PRIMARY KEY AUTOINCREMENT,`user_id` integer NOT NULL,`title` text NOT NULL,`content` text NOT NULL,`category` text,`status` text NOT NULL DEFAULT "pending",`assigned_to` integer,`reply` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_tickets_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_tickets_assignee` FOREIGN KEY (`assigned_to`) REFERENCES `users`(`id`)) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.795ms] [rows:0] CREATE INDEX `idx_tickets_deleted_at` ON `tickets`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.772ms] [rows:0] CREATE INDEX `idx_tickets_user_id` ON `tickets`(`user_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.035ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="system_settings" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [2.284ms] [rows:0] CREATE TABLE `system_settings` (`id` integer PRIMARY KEY AUTOINCREMENT,`key` text NOT NULL,`value` text,`updated_at` datetime) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.969ms] [rows:0] CREATE UNIQUE INDEX `idx_system_settings_key` ON `system_settings`(`key`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.034ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="supplier_authorizations" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [1.884ms] [rows:0] CREATE TABLE `supplier_authorizations` (`id` integer PRIMARY KEY AUTOINCREMENT,`supplier_id` integer NOT NULL,`type` text NOT NULL,`ref_id` integer NOT NULL) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.844ms] [rows:0] CREATE INDEX `idx_supplier_authorizations_supplier_id` ON `supplier_authorizations`(`supplier_id`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.038ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="articles" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [2.719ms] [rows:0] CREATE TABLE `articles` (`id` integer PRIMARY KEY AUTOINCREMENT,`title` text NOT NULL,`content` text NOT NULL,`summary` text,`cover_image` text,`carousel` text,`is_pinned` numeric DEFAULT false,`is_published` numeric DEFAULT true,`sort_order` integer DEFAULT 0,`author_id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_articles_author` FOREIGN KEY (`author_id`) REFERENCES `users`(`id`)) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.838ms] [rows:0] CREATE INDEX `idx_articles_deleted_at` ON `articles`(`deleted_at`) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:32 -sale | [0.032ms] [rows:-] SELECT count(*) FROM sqlite_master WHERE type='table' AND name="banners" -sale | -sale | 2026/05/25 05:13:33 /app/backend/internal/utils/database.go:54 -sale | [2.439ms] [rows:0] CREATE TABLE `banners` (`id` integer PRIMARY KEY AUTOINCREMENT,`title` text NOT NULL,`desc` text,`image` text NOT NULL,`link` text,`button` text,`bg_color` text,`sort_order` integer DEFAULT 0,`is_active` numeric DEFAULT true,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime) -sale | -sale | 2026/05/25 05:13:33 /go/pkg/mod/github.com/glebarez/sqlite@v1.11.0/migrator.go:274 -sale | [1.909ms] [rows:0] CREATE INDEX `idx_banners_deleted_at` ON `banners`(`deleted_at`) -sale | 2026/05/25 05:13:33 Database migrated successfully -sale | 2026/05/25 05:13:33 Server starting on :8080 \ No newline at end of file +sale | 2026/05/28 00:21:55 /app/backend/internal/api/handlers/order.go:301 +sale | [0.888ms] [rows:1] SELECT * FROM `orders` WHERE `orders`.`id` = 8 AND `orders`.`deleted_at` IS NULL AND `orders`.`id` = 8 ORDER BY `orders`.`id` LIMIT 1 +sale | [GIN] 2026/05/28 - 00:21:55 | 201 | 6.616127ms | 156.245.232.134 | POST "/api/orders" +sale | +sale | 2026/05/28 00:21:56 /app/backend/internal/api/handlers/order.go:24 +sale | [1.598ms] [rows:0] SELECT * FROM `carts` WHERE user_id = 1 +sale | [GIN] 2026/05/28 - 00:21:56 | 200 | 1.758422ms | 156.245.232.134 | GET "/api/cart" +sale | +sale | 2026/05/28 00:21:56 /app/backend/internal/api/handlers/auth.go:323 +sale | [0.282ms] [rows:1] SELECT count(*) FROM `users` WHERE role = "admin" AND `users`.`deleted_at` IS NULL +sale | [GIN] 2026/05/28 - 00:21:56 | 200 | 391.749µs | 156.245.232.134 | GET "/api/installed" +sale | [GIN] 2026/05/28 - 00:21:56 | 200 | 366.199µs | 156.245.232.134 | GET "/assets/Checkout-SK8MjkR1.js" +sale | [GIN] 2026/05/28 - 00:21:56 | 200 | 127.963µs | 156.245.232.134 | GET "/assets/Checkout-BJu99NHn.css" +sale | +sale | 2026/05/28 00:21:57 /app/backend/internal/api/handlers/payment.go:42 +sale | [0.547ms] [rows:1] SELECT * FROM `orders` WHERE (id = 8 AND user_id = 1) AND `orders`.`deleted_at` IS NULL ORDER BY `orders`.`id` LIMIT 1 +sale | +sale | 2026/05/28 00:21:57 /app/backend/internal/api/handlers/payment.go:53 +sale | [0.327ms] [rows:1] SELECT * FROM `payment_channels` WHERE (is_enabled = true AND type = "bepusdt") AND `payment_channels`.`deleted_at` IS NULL ORDER BY sort_order ASC +sale | 2026/05/28 00:21:57 [BepUsdt] signature params: map[amount:100.00 notify_url:https://waiguoyan.com/api/payment/bepusdt/notify order_id:8 redirect_url:https://waiguoyan.com/orders/8 trade_type:usdt.trc20] +sale | 2026/05/28 00:21:57 [BepUsdt] signature: b13689e09dd763327e15d20290f328e4, token: DF944A644A32C96F0C5D9CB0D71A9350 +sale | 2026/05/28 00:21:57 [BepUsdt] request body: {"trade_type":"usdt.trc20","order_id":"8","amount":100,"notify_url":"https://waiguoyan.com/api/payment/bepusdt/notify","redirect_url":"https://waiguoyan.com/orders/8","signature":"b13689e09dd763327e15d20290f328e4"} +sale | 2026/05/28 00:21:57 [BepUsdt] response: {"message":"签名错误","status_code":400} +sale | [GIN] 2026/05/28 - 00:21:57 | 500 | 505.695187ms | 156.245.232.134 | POST "/api/orders/8/pay" +root@super:/opt/ace/compose/sale# \ No newline at end of file