diff --git a/.gitignore b/.gitignore index 03dd16dd..244998fd 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ main uploads/* s3_cache +/frontend/.next/ diff --git a/docs/docs.go b/docs/docs.go index 6c5a06cf..8145ca87 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -15,92 +15,24 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/api.php": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "type": "string", - "name": "act", - "in": "query" - }, - { - "type": "string", - "name": "key", - "in": "query", - "required": true - }, - { - "maxLength": 64, - "minLength": 1, - "type": "string", - "name": "out_trade_no", - "in": "query", - "required": true - }, - { - "type": "string", - "name": "pid", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/payment.QueryMerchantOrderResponse" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "退款请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.RefundOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/payment.RefundMerchantOrderResponse" - } - } - } - } - }, "/api/v1/admin/system-configs": { "get": { + "description": "返回所有系统配置列表,支持按配置类型(system/business)过滤,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "获取系统配置列表", + "parameters": [ + { + "type": "string", + "description": "配置类型(system/business)", + "name": "type", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -111,6 +43,7 @@ const docTemplate = `{ } }, "post": { + "description": "创建一条新的系统配置项,配置键不可重复,同时将新配置同步到 Redis,需要管理员权限", "consumes": [ "application/json" ], @@ -120,9 +53,10 @@ const docTemplate = `{ "tags": [ "admin" ], + "summary": "创建系统配置", "parameters": [ { - "description": "request body", + "description": "创建请求参数", "name": "request", "in": "body", "required": true, @@ -143,12 +77,14 @@ const docTemplate = `{ }, "/api/v1/admin/system-configs/{key}": { "get": { + "description": "根据配置键获取对应的系统配置详情,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "获取单个系统配置", "parameters": [ { "type": "string", @@ -168,6 +104,7 @@ const docTemplate = `{ } }, "put": { + "description": "根据配置键更新对应的配置内容,同时将更新同步到 Redis,需要管理员权限", "consumes": [ "application/json" ], @@ -177,6 +114,7 @@ const docTemplate = `{ "tags": [ "admin" ], + "summary": "更新系统配置", "parameters": [ { "type": "string", @@ -186,7 +124,7 @@ const docTemplate = `{ "required": true }, { - "description": "request body", + "description": "更新请求参数", "name": "request", "in": "body", "required": true, @@ -205,12 +143,14 @@ const docTemplate = `{ } }, "delete": { + "description": "根据配置键删除对应配置,同时从 Redis 中移除对应缓存,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "删除系统配置", "parameters": [ { "type": "string", @@ -232,6 +172,7 @@ const docTemplate = `{ }, "/api/v1/admin/tasks/dispatch": { "post": { + "description": "手动触发指定类型的异步任务,支持指定时间范围和用户,需要管理员权限", "consumes": [ "application/json" ], @@ -241,9 +182,10 @@ const docTemplate = `{ "tags": [ "admin" ], + "summary": "下发异步任务", "parameters": [ { - "description": "request body", + "description": "任务请求参数", "name": "request", "in": "body", "required": true, @@ -264,149 +206,14 @@ const docTemplate = `{ }, "/api/v1/admin/tasks/types": { "get": { + "description": "返回系统支持的所有可调度任务类型列表,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/admin/user-pay-configs": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/user_pay_config.CreateUserPayConfigRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/admin/user-pay-configs/{id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "type": "string", - "description": "配置ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "type": "string", - "description": "配置ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/user_pay_config.UpdateUserPayConfigRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "type": "string", - "description": "配置ID", - "name": "id", - "in": "path", - "required": true - } - ], + "summary": "获取支持的任务类型", "responses": { "200": { "description": "OK", @@ -419,12 +226,14 @@ const docTemplate = `{ }, "/api/v1/admin/users": { "get": { + "description": "分页返回用户列表,支持按用户 ID 和用户名筛选,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "获取用户列表", "parameters": [ { "minimum": 1, @@ -462,12 +271,17 @@ const docTemplate = `{ }, "/api/v1/admin/users/{id}/status": { "put": { + "description": "启用或禁用指定用户,管理员账号无法被禁用,需要管理员权限", + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "更新用户状态", "parameters": [ { "type": "integer", @@ -477,7 +291,7 @@ const docTemplate = `{ "required": true }, { - "description": "状态", + "description": "状态参数", "name": "request", "in": "body", "required": true, @@ -498,6 +312,7 @@ const docTemplate = `{ }, "/api/v1/config/public": { "get": { + "description": "返回对前端公开的系统配置信息,如允许上传的文件类型、站点名称、是否开放注册等", "consumes": [ "application/json" ], @@ -507,6 +322,7 @@ const docTemplate = `{ "tags": [ "config" ], + "summary": "获取公共配置", "responses": { "200": { "description": "OK", @@ -517,618 +333,16 @@ const docTemplate = `{ } } }, - "/api/v1/dashboard/stats/daily": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "dashboard" - ], - "summary": "获取每日收支统计", - "parameters": [ - { - "type": "integer", - "description": "查询天数,最大7天", - "name": "days", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/dashboard/stats/top-customers": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "dashboard" - ], - "summary": "获取Top客户", - "parameters": [ - { - "type": "integer", - "description": "查询天数,最大7天", - "name": "days", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "返回数量,最大10", - "name": "limit", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/dashboard/stats/user-balance": { - "get": { - "description": "统计所有用户的AvailableBalance字段", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "dashboard" - ], - "summary": "获取用户余额统计", - "responses": { - "200": { - "description": "OK", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/util.ResponseAny" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/dashboard.UserBalanceStatsResponse" - } - } - } - ] - } - } - } - } - }, "/api/v1/health": { "get": { + "description": "检查服务是否正常运行", "produces": [ "application/json" ], "tags": [ "health" ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/leaderboard": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leaderboard" - ], - "summary": "获取排行榜列表", - "parameters": [ - { - "type": "integer", - "description": "页码", - "name": "page", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "每页数量", - "name": "page_size", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/leaderboard/me": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leaderboard" - ], - "summary": "获取当前用户排名", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/leaderboard/users/{id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leaderboard" - ], - "summary": "获取指定用户排名", - "parameters": [ - { - "type": "integer", - "description": "用户ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/api_key.CreateAPIKeyRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys/{id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/api_key.UpdateAPIKeyRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys/{id}/payment-links": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "创建支付链接请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/link.PaymentLinkRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys/{id}/payment-links/{linkId}": { - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "format": "int64", - "description": "Payment Link ID", - "name": "linkId", - "in": "path", - "required": true - }, - { - "description": "更新支付链接请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/link.PaymentLinkRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "format": "int64", - "description": "Payment Link ID", - "name": "linkId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "支付订单请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.PayOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment-links/pay": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "description": "支付请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/link.PayByLinkRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment-links/{token}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "string", - "description": "支付链接 Token", - "name": "token", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment/order": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "type": "string", - "description": "订单号", - "name": "order_no", - "in": "query", - "required": true - } - ], + "summary": "健康检查", "responses": { "200": { "description": "OK", @@ -1141,15 +355,20 @@ const docTemplate = `{ }, "/api/v1/oauth/callback": { "post": { + "description": "接收前端传回的 state 和 code,完成 OAuth/OIDC 认证并建立用户会话", + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "oauth" ], + "summary": "OAuth 回调", "parameters": [ { - "description": "request body", + "description": "回调请求参数", "name": "request", "in": "body", "required": true, @@ -1170,12 +389,14 @@ const docTemplate = `{ }, "/api/v1/oauth/login": { "get": { + "description": "生成 OAuth 登录 URL,前端跳转至该地址完成授权", "produces": [ "application/json" ], "tags": [ "oauth" ], + "summary": "获取登录地址", "responses": { "200": { "description": "OK", @@ -1188,12 +409,14 @@ const docTemplate = `{ }, "/api/v1/oauth/logout": { "get": { + "description": "清除当前用户的登录会话,完成退出", "produces": [ "application/json" ], "tags": [ "oauth" ], + "summary": "退出登录", "responses": { "200": { "description": "OK", @@ -1206,452 +429,14 @@ const docTemplate = `{ }, "/api/v1/oauth/user-info": { "get": { + "description": "返回当前登录用户的基本信息及余额数据,需要登录", "produces": [ "application/json" ], "tags": [ "oauth" ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/dispute": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dispute.CreateDisputeRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/dispute/close": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dispute.CloseDisputeRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/disputes": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "schema": { - "$ref": "#/definitions/dispute.ListDisputesRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/disputes/merchant": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "schema": { - "$ref": "#/definitions/dispute.ListDisputesRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/refund-review": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dispute.RefundReviewRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/transactions": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "schema": { - "$ref": "#/definitions/order.TransactionListRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/payment/transfer": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "转账请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.TransferRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/claim": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "description": "领取红包请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/redenvelope.ClaimRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/covers": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "type": "string", - "description": "封面类型 (cover/heterotypic)", - "name": "type", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/create": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "description": "创建红包请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/redenvelope.CreateRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/list": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "description": "列表请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/redenvelope.ListRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/{id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "type": "string", - "description": "红包ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/upload/redenvelope/cover": { - "post": { - "consumes": [ - "multipart/form-data" - ], - "produces": [ - "application/json" - ], - "tags": [ - "upload" - ], - "parameters": [ - { - "type": "file", - "description": "图片文件", - "name": "file", - "in": "formData", - "required": true - }, - { - "type": "string", - "description": "封面类型 (cover/heterotypic)", - "name": "type", - "in": "formData", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/user/pay-key": { - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/user.UpdatePayKeyRequest" - } - } - ], + "summary": "获取当前登录用户信息", "responses": { "200": { "description": "OK", @@ -1685,370 +470,9 @@ const docTemplate = `{ } } } - }, - "/pay/distribute": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "type": "string", - "description": "Basic Auth (base64(client_id:client_secret))", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "分发请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.MerchantDistributeRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/pay/submit.php": { - "get": { - "consumes": [ - "application/x-www-form-urlencoded" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.CreateOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/x-www-form-urlencoded" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.CreateOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } } }, "definitions": { - "api_key.CreateAPIKeyRequest": { - "type": "object", - "required": [ - "app_homepage_url", - "app_name", - "notify_url" - ], - "properties": { - "app_description": { - "type": "string", - "maxLength": 100 - }, - "app_homepage_url": { - "type": "string", - "maxLength": 100 - }, - "app_name": { - "type": "string", - "maxLength": 20 - }, - "notify_url": { - "type": "string", - "maxLength": 100 - }, - "public_key": { - "type": "string", - "maxLength": 100 - }, - "redirect_uri": { - "type": "string", - "maxLength": 100 - }, - "test_mode": { - "type": "boolean" - } - } - }, - "api_key.UpdateAPIKeyRequest": { - "type": "object", - "properties": { - "app_description": { - "type": "string", - "maxLength": 100 - }, - "app_homepage_url": { - "type": "string", - "maxLength": 100 - }, - "app_name": { - "type": "string", - "maxLength": 20 - }, - "notify_url": { - "type": "string", - "maxLength": 100 - }, - "public_key": { - "type": "string", - "maxLength": 100 - }, - "redirect_uri": { - "type": "string", - "maxLength": 100 - }, - "test_mode": { - "type": "boolean" - } - } - }, - "dashboard.UserBalanceStatsResponse": { - "type": "object", - "properties": { - "avg_amount": { - "type": "number" - }, - "max_amount": { - "type": "number" - }, - "median_amount": { - "type": "number" - }, - "min_amount": { - "type": "number" - }, - "std_dev": { - "type": "number" - }, - "total_amount": { - "type": "number" - }, - "total_count": { - "type": "integer" - } - } - }, - "dispute.CloseDisputeRequest": { - "type": "object", - "required": [ - "dispute_id" - ], - "properties": { - "dispute_id": { - "type": "string", - "example": "0" - } - } - }, - "dispute.CreateDisputeRequest": { - "type": "object", - "required": [ - "order_id", - "reason" - ], - "properties": { - "order_id": { - "type": "string", - "example": "0" - }, - "reason": { - "type": "string", - "maxLength": 100 - } - } - }, - "dispute.ListDisputesRequest": { - "type": "object", - "properties": { - "dispute_id": { - "type": "string", - "example": "0" - }, - "page": { - "type": "integer", - "minimum": 1 - }, - "page_size": { - "type": "integer", - "maximum": 100, - "minimum": 1 - }, - "status": { - "type": "string", - "enum": [ - "disputing", - "refund", - "closed" - ] - } - } - }, - "dispute.RefundReviewRequest": { - "type": "object", - "required": [ - "dispute_id", - "status" - ], - "properties": { - "dispute_id": { - "type": "string", - "example": "0" - }, - "reason": { - "type": "string", - "maxLength": 100 - }, - "status": { - "type": "string", - "enum": [ - "refund", - "closed" - ] - } - } - }, - "link.PayByLinkRequest": { - "type": "object", - "required": [ - "pay_key", - "token" - ], - "properties": { - "pay_key": { - "type": "string", - "maxLength": 6 - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "token": { - "type": "string" - } - } - }, - "link.PaymentLinkRequest": { - "type": "object", - "required": [ - "amount", - "product_name" - ], - "properties": { - "amount": { - "type": "number" - }, - "product_name": { - "type": "string", - "maxLength": 30 - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "total_limit": { - "type": "integer", - "minimum": 1 - }, - "user_limit": { - "type": "integer", - "minimum": 1 - } - } - }, - "model.OrderTransferStatus": { - "type": "string", - "enum": [ - "pending", - "completed" - ], - "x-enum-varnames": [ - "OrderTransferStatusPending", - "OrderTransferStatusCompleted" - ] - }, - "model.PayLevel": { - "type": "integer", - "format": "int32", - "enum": [ - 0, - 1, - 2, - 3 - ], - "x-enum-varnames": [ - "PayLevelFree", - "PayLevelBasic", - "PayLevelStandard", - "PayLevelPremium" - ] - }, - "model.RedEnvelopeType": { - "type": "string", - "enum": [ - "fixed", - "random" - ], - "x-enum-varnames": [ - "RedEnvelopeTypeFixed", - "RedEnvelopeTypeRandom" - ] - }, "oauth.CallbackRequest": { "type": "object", "properties": { @@ -2060,348 +484,11 @@ const docTemplate = `{ } } }, - "order.TransactionListRequest": { - "type": "object", - "properties": { - "client_id": { - "type": "string" - }, - "endTime": { - "type": "string" - }, - "id": { - "type": "string", - "example": "0" - }, - "order_name": { - "type": "string" - }, - "page": { - "type": "integer", - "minimum": 1 - }, - "page_size": { - "type": "integer", - "maximum": 100, - "minimum": 1 - }, - "payee_transfer_status": { - "enum": [ - "pending", - "completed" - ], - "allOf": [ - { - "$ref": "#/definitions/model.OrderTransferStatus" - } - ] - }, - "payee_username": { - "type": "string" - }, - "payer_username": { - "type": "string" - }, - "startTime": { - "type": "string" - }, - "statuses": { - "type": "array", - "items": { - "type": "string" - } - }, - "types": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "payment.CreateOrderRequest": { - "type": "object", - "required": [ - "amount", - "order_name" - ], - "properties": { - "amount": { - "type": "number" - }, - "merchant_order_no": { - "type": "string", - "maxLength": 64, - "minLength": 1 - }, - "notify_url": { - "type": "string", - "maxLength": 100 - }, - "order_name": { - "type": "string", - "maxLength": 64 - }, - "payment_type": { - "type": "string" - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "return_url": { - "type": "string", - "maxLength": 100 - } - } - }, - "payment.MerchantDistributeRequest": { - "type": "object", - "required": [ - "amount", - "user_id", - "username" - ], - "properties": { - "amount": { - "type": "number" - }, - "out_trade_no": { - "type": "string", - "maxLength": 64, - "minLength": 1 - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "user_id": { - "type": "integer" - }, - "username": { - "type": "string" - } - } - }, - "payment.PayOrderRequest": { - "type": "object", - "required": [ - "order_no", - "pay_key" - ], - "properties": { - "order_no": { - "type": "string" - }, - "pay_key": { - "type": "string", - "maxLength": 6 - } - } - }, - "payment.QueryMerchantOrderResponse": { - "type": "object", - "properties": { - "addtime": { - "type": "string", - "example": "2023-12-08 12:00:00" - }, - "code": { - "type": "integer", - "example": 1 - }, - "endtime": { - "type": "string", - "example": "2023-12-08 12:05:00" - }, - "money": { - "type": "string", - "example": "10.00" - }, - "msg": { - "type": "string", - "example": "查询订单号成功!" - }, - "name": { - "type": "string", - "example": "商品名称" - }, - "out_trade_no": { - "type": "string", - "example": "M202312080001" - }, - "pid": { - "type": "string", - "example": "1001" - }, - "status": { - "type": "integer", - "example": 1 - }, - "trade_no": { - "type": "string", - "example": "123456" - }, - "type": { - "type": "string", - "example": "epay" - } - } - }, - "payment.RefundMerchantOrderResponse": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "example": 1 - }, - "msg": { - "type": "string", - "example": "退款成功" - } - } - }, - "payment.RefundOrderRequest": { - "type": "object", - "required": [ - "key", - "money", - "pid", - "trade_no" - ], - "properties": { - "key": { - "type": "string" - }, - "money": { - "type": "number" - }, - "out_trade_no": { - "type": "string" - }, - "pid": { - "type": "string" - }, - "trade_no": { - "type": "integer" - } - } - }, - "payment.TransferRequest": { - "type": "object", - "required": [ - "amount", - "pay_key", - "recipient_id", - "recipient_username" - ], - "properties": { - "amount": { - "type": "number" - }, - "pay_key": { - "type": "string", - "maxLength": 6 - }, - "recipient_id": { - "type": "string", - "example": "0" - }, - "recipient_username": { - "type": "string" - }, - "remark": { - "type": "string", - "maxLength": 100 - } - } - }, - "redenvelope.ClaimRequest": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "example": "0" - } - } - }, - "redenvelope.CreateRequest": { - "type": "object", - "required": [ - "pay_key", - "total_amount", - "total_count", - "type" - ], - "properties": { - "cover_upload_id": { - "type": "string", - "example": "0" - }, - "greeting": { - "type": "string", - "maxLength": 100 - }, - "heterotypic_upload_id": { - "type": "string", - "example": "0" - }, - "pay_key": { - "type": "string", - "maxLength": 10 - }, - "total_amount": { - "type": "number" - }, - "total_count": { - "type": "integer", - "minimum": 1 - }, - "type": { - "enum": [ - "fixed", - "random" - ], - "allOf": [ - { - "$ref": "#/definitions/model.RedEnvelopeType" - } - ] - } - } - }, - "redenvelope.ListRequest": { - "type": "object", - "required": [ - "page", - "page_size" - ], - "properties": { - "page": { - "type": "integer", - "minimum": 1 - }, - "page_size": { - "type": "integer", - "maximum": 100, - "minimum": 1 - }, - "type": { - "type": "string", - "enum": [ - "sent", - "received" - ] - } - } - }, "system_config.CreateSystemConfigRequest": { "type": "object", "required": [ "key", + "type", "value" ], "properties": { @@ -2413,6 +500,13 @@ const docTemplate = `{ "type": "string", "maxLength": 64 }, + "type": { + "type": "string", + "enum": [ + "system", + "business" + ] + }, "value": { "type": "string", "maxLength": 255 @@ -2455,18 +549,6 @@ const docTemplate = `{ } } }, - "user.UpdatePayKeyRequest": { - "type": "object", - "required": [ - "pay_key" - ], - "properties": { - "pay_key": { - "type": "string", - "maxLength": 6 - } - } - }, "user.updateUserStatusRequest": { "type": "object", "properties": { @@ -2475,65 +557,6 @@ const docTemplate = `{ } } }, - "user_pay_config.CreateUserPayConfigRequest": { - "type": "object", - "required": [ - "distribute_rate", - "fee_rate", - "score_rate" - ], - "properties": { - "daily_limit": { - "type": "integer" - }, - "distribute_rate": { - "type": "number" - }, - "fee_rate": { - "type": "number" - }, - "level": { - "$ref": "#/definitions/model.PayLevel" - }, - "max_score": { - "type": "integer" - }, - "min_score": { - "type": "integer" - }, - "score_rate": { - "type": "number" - } - } - }, - "user_pay_config.UpdateUserPayConfigRequest": { - "type": "object", - "required": [ - "distribute_rate", - "fee_rate", - "score_rate" - ], - "properties": { - "daily_limit": { - "type": "integer" - }, - "distribute_rate": { - "type": "number" - }, - "fee_rate": { - "type": "number" - }, - "max_score": { - "type": "integer" - }, - "min_score": { - "type": "integer" - }, - "score_rate": { - "type": "number" - } - } - }, "util.ResponseAny": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 98c4939f..e6d78dfe 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -6,92 +6,24 @@ "version": "1.0.0" }, "paths": { - "/api.php": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "type": "string", - "name": "act", - "in": "query" - }, - { - "type": "string", - "name": "key", - "in": "query", - "required": true - }, - { - "maxLength": 64, - "minLength": 1, - "type": "string", - "name": "out_trade_no", - "in": "query", - "required": true - }, - { - "type": "string", - "name": "pid", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/payment.QueryMerchantOrderResponse" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "退款请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.RefundOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/payment.RefundMerchantOrderResponse" - } - } - } - } - }, "/api/v1/admin/system-configs": { "get": { + "description": "返回所有系统配置列表,支持按配置类型(system/business)过滤,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "获取系统配置列表", + "parameters": [ + { + "type": "string", + "description": "配置类型(system/business)", + "name": "type", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -102,6 +34,7 @@ } }, "post": { + "description": "创建一条新的系统配置项,配置键不可重复,同时将新配置同步到 Redis,需要管理员权限", "consumes": [ "application/json" ], @@ -111,9 +44,10 @@ "tags": [ "admin" ], + "summary": "创建系统配置", "parameters": [ { - "description": "request body", + "description": "创建请求参数", "name": "request", "in": "body", "required": true, @@ -134,12 +68,14 @@ }, "/api/v1/admin/system-configs/{key}": { "get": { + "description": "根据配置键获取对应的系统配置详情,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "获取单个系统配置", "parameters": [ { "type": "string", @@ -159,6 +95,7 @@ } }, "put": { + "description": "根据配置键更新对应的配置内容,同时将更新同步到 Redis,需要管理员权限", "consumes": [ "application/json" ], @@ -168,6 +105,7 @@ "tags": [ "admin" ], + "summary": "更新系统配置", "parameters": [ { "type": "string", @@ -177,7 +115,7 @@ "required": true }, { - "description": "request body", + "description": "更新请求参数", "name": "request", "in": "body", "required": true, @@ -196,12 +134,14 @@ } }, "delete": { + "description": "根据配置键删除对应配置,同时从 Redis 中移除对应缓存,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "删除系统配置", "parameters": [ { "type": "string", @@ -223,6 +163,7 @@ }, "/api/v1/admin/tasks/dispatch": { "post": { + "description": "手动触发指定类型的异步任务,支持指定时间范围和用户,需要管理员权限", "consumes": [ "application/json" ], @@ -232,9 +173,10 @@ "tags": [ "admin" ], + "summary": "下发异步任务", "parameters": [ { - "description": "request body", + "description": "任务请求参数", "name": "request", "in": "body", "required": true, @@ -255,149 +197,14 @@ }, "/api/v1/admin/tasks/types": { "get": { + "description": "返回系统支持的所有可调度任务类型列表,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/admin/user-pay-configs": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/user_pay_config.CreateUserPayConfigRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/admin/user-pay-configs/{id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "type": "string", - "description": "配置ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "type": "string", - "description": "配置ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/user_pay_config.UpdateUserPayConfigRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "parameters": [ - { - "type": "string", - "description": "配置ID", - "name": "id", - "in": "path", - "required": true - } - ], + "summary": "获取支持的任务类型", "responses": { "200": { "description": "OK", @@ -410,12 +217,14 @@ }, "/api/v1/admin/users": { "get": { + "description": "分页返回用户列表,支持按用户 ID 和用户名筛选,需要管理员权限", "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "获取用户列表", "parameters": [ { "minimum": 1, @@ -453,12 +262,17 @@ }, "/api/v1/admin/users/{id}/status": { "put": { + "description": "启用或禁用指定用户,管理员账号无法被禁用,需要管理员权限", + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "admin" ], + "summary": "更新用户状态", "parameters": [ { "type": "integer", @@ -468,7 +282,7 @@ "required": true }, { - "description": "状态", + "description": "状态参数", "name": "request", "in": "body", "required": true, @@ -489,6 +303,7 @@ }, "/api/v1/config/public": { "get": { + "description": "返回对前端公开的系统配置信息,如允许上传的文件类型、站点名称、是否开放注册等", "consumes": [ "application/json" ], @@ -498,6 +313,7 @@ "tags": [ "config" ], + "summary": "获取公共配置", "responses": { "200": { "description": "OK", @@ -508,618 +324,16 @@ } } }, - "/api/v1/dashboard/stats/daily": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "dashboard" - ], - "summary": "获取每日收支统计", - "parameters": [ - { - "type": "integer", - "description": "查询天数,最大7天", - "name": "days", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/dashboard/stats/top-customers": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "dashboard" - ], - "summary": "获取Top客户", - "parameters": [ - { - "type": "integer", - "description": "查询天数,最大7天", - "name": "days", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "返回数量,最大10", - "name": "limit", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/dashboard/stats/user-balance": { - "get": { - "description": "统计所有用户的AvailableBalance字段", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "dashboard" - ], - "summary": "获取用户余额统计", - "responses": { - "200": { - "description": "OK", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/util.ResponseAny" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/dashboard.UserBalanceStatsResponse" - } - } - } - ] - } - } - } - } - }, "/api/v1/health": { "get": { + "description": "检查服务是否正常运行", "produces": [ "application/json" ], "tags": [ "health" ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/leaderboard": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leaderboard" - ], - "summary": "获取排行榜列表", - "parameters": [ - { - "type": "integer", - "description": "页码", - "name": "page", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "每页数量", - "name": "page_size", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/leaderboard/me": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leaderboard" - ], - "summary": "获取当前用户排名", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/leaderboard/users/{id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leaderboard" - ], - "summary": "获取指定用户排名", - "parameters": [ - { - "type": "integer", - "description": "用户ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/api_key.CreateAPIKeyRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys/{id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/api_key.UpdateAPIKeyRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys/{id}/payment-links": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "创建支付链接请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/link.PaymentLinkRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/api-keys/{id}/payment-links/{linkId}": { - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "format": "int64", - "description": "Payment Link ID", - "name": "linkId", - "in": "path", - "required": true - }, - { - "description": "更新支付链接请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/link.PaymentLinkRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "API Key ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "format": "int64", - "description": "Payment Link ID", - "name": "linkId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "支付订单请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.PayOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment-links/pay": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "description": "支付请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/link.PayByLinkRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment-links/{token}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "merchant" - ], - "parameters": [ - { - "type": "string", - "description": "支付链接 Token", - "name": "token", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/merchant/payment/order": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "type": "string", - "description": "订单号", - "name": "order_no", - "in": "query", - "required": true - } - ], + "summary": "健康检查", "responses": { "200": { "description": "OK", @@ -1132,15 +346,20 @@ }, "/api/v1/oauth/callback": { "post": { + "description": "接收前端传回的 state 和 code,完成 OAuth/OIDC 认证并建立用户会话", + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "oauth" ], + "summary": "OAuth 回调", "parameters": [ { - "description": "request body", + "description": "回调请求参数", "name": "request", "in": "body", "required": true, @@ -1161,12 +380,14 @@ }, "/api/v1/oauth/login": { "get": { + "description": "生成 OAuth 登录 URL,前端跳转至该地址完成授权", "produces": [ "application/json" ], "tags": [ "oauth" ], + "summary": "获取登录地址", "responses": { "200": { "description": "OK", @@ -1179,12 +400,14 @@ }, "/api/v1/oauth/logout": { "get": { + "description": "清除当前用户的登录会话,完成退出", "produces": [ "application/json" ], "tags": [ "oauth" ], + "summary": "退出登录", "responses": { "200": { "description": "OK", @@ -1197,452 +420,14 @@ }, "/api/v1/oauth/user-info": { "get": { + "description": "返回当前登录用户的基本信息及余额数据,需要登录", "produces": [ "application/json" ], "tags": [ "oauth" ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/dispute": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dispute.CreateDisputeRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/dispute/close": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dispute.CloseDisputeRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/disputes": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "schema": { - "$ref": "#/definitions/dispute.ListDisputesRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/disputes/merchant": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "schema": { - "$ref": "#/definitions/dispute.ListDisputesRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/refund-review": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dispute.RefundReviewRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/order/transactions": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "order" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "schema": { - "$ref": "#/definitions/order.TransactionListRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/payment/transfer": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "转账请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.TransferRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/claim": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "description": "领取红包请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/redenvelope.ClaimRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/covers": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "type": "string", - "description": "封面类型 (cover/heterotypic)", - "name": "type", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/create": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "description": "创建红包请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/redenvelope.CreateRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/list": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "description": "列表请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/redenvelope.ListRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/redenvelope/{id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "redenvelope" - ], - "parameters": [ - { - "type": "string", - "description": "红包ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/upload/redenvelope/cover": { - "post": { - "consumes": [ - "multipart/form-data" - ], - "produces": [ - "application/json" - ], - "tags": [ - "upload" - ], - "parameters": [ - { - "type": "file", - "description": "图片文件", - "name": "file", - "in": "formData", - "required": true - }, - { - "type": "string", - "description": "封面类型 (cover/heterotypic)", - "name": "type", - "in": "formData", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/api/v1/user/pay-key": { - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/user.UpdatePayKeyRequest" - } - } - ], + "summary": "获取当前登录用户信息", "responses": { "200": { "description": "OK", @@ -1676,370 +461,9 @@ } } } - }, - "/pay/distribute": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "type": "string", - "description": "Basic Auth (base64(client_id:client_secret))", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "分发请求", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.MerchantDistributeRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } - }, - "/pay/submit.php": { - "get": { - "consumes": [ - "application/x-www-form-urlencoded" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.CreateOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - }, - "post": { - "consumes": [ - "application/x-www-form-urlencoded" - ], - "produces": [ - "application/json" - ], - "tags": [ - "payment" - ], - "parameters": [ - { - "description": "request body", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/payment.CreateOrderRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/util.ResponseAny" - } - } - } - } } }, "definitions": { - "api_key.CreateAPIKeyRequest": { - "type": "object", - "required": [ - "app_homepage_url", - "app_name", - "notify_url" - ], - "properties": { - "app_description": { - "type": "string", - "maxLength": 100 - }, - "app_homepage_url": { - "type": "string", - "maxLength": 100 - }, - "app_name": { - "type": "string", - "maxLength": 20 - }, - "notify_url": { - "type": "string", - "maxLength": 100 - }, - "public_key": { - "type": "string", - "maxLength": 100 - }, - "redirect_uri": { - "type": "string", - "maxLength": 100 - }, - "test_mode": { - "type": "boolean" - } - } - }, - "api_key.UpdateAPIKeyRequest": { - "type": "object", - "properties": { - "app_description": { - "type": "string", - "maxLength": 100 - }, - "app_homepage_url": { - "type": "string", - "maxLength": 100 - }, - "app_name": { - "type": "string", - "maxLength": 20 - }, - "notify_url": { - "type": "string", - "maxLength": 100 - }, - "public_key": { - "type": "string", - "maxLength": 100 - }, - "redirect_uri": { - "type": "string", - "maxLength": 100 - }, - "test_mode": { - "type": "boolean" - } - } - }, - "dashboard.UserBalanceStatsResponse": { - "type": "object", - "properties": { - "avg_amount": { - "type": "number" - }, - "max_amount": { - "type": "number" - }, - "median_amount": { - "type": "number" - }, - "min_amount": { - "type": "number" - }, - "std_dev": { - "type": "number" - }, - "total_amount": { - "type": "number" - }, - "total_count": { - "type": "integer" - } - } - }, - "dispute.CloseDisputeRequest": { - "type": "object", - "required": [ - "dispute_id" - ], - "properties": { - "dispute_id": { - "type": "string", - "example": "0" - } - } - }, - "dispute.CreateDisputeRequest": { - "type": "object", - "required": [ - "order_id", - "reason" - ], - "properties": { - "order_id": { - "type": "string", - "example": "0" - }, - "reason": { - "type": "string", - "maxLength": 100 - } - } - }, - "dispute.ListDisputesRequest": { - "type": "object", - "properties": { - "dispute_id": { - "type": "string", - "example": "0" - }, - "page": { - "type": "integer", - "minimum": 1 - }, - "page_size": { - "type": "integer", - "maximum": 100, - "minimum": 1 - }, - "status": { - "type": "string", - "enum": [ - "disputing", - "refund", - "closed" - ] - } - } - }, - "dispute.RefundReviewRequest": { - "type": "object", - "required": [ - "dispute_id", - "status" - ], - "properties": { - "dispute_id": { - "type": "string", - "example": "0" - }, - "reason": { - "type": "string", - "maxLength": 100 - }, - "status": { - "type": "string", - "enum": [ - "refund", - "closed" - ] - } - } - }, - "link.PayByLinkRequest": { - "type": "object", - "required": [ - "pay_key", - "token" - ], - "properties": { - "pay_key": { - "type": "string", - "maxLength": 6 - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "token": { - "type": "string" - } - } - }, - "link.PaymentLinkRequest": { - "type": "object", - "required": [ - "amount", - "product_name" - ], - "properties": { - "amount": { - "type": "number" - }, - "product_name": { - "type": "string", - "maxLength": 30 - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "total_limit": { - "type": "integer", - "minimum": 1 - }, - "user_limit": { - "type": "integer", - "minimum": 1 - } - } - }, - "model.OrderTransferStatus": { - "type": "string", - "enum": [ - "pending", - "completed" - ], - "x-enum-varnames": [ - "OrderTransferStatusPending", - "OrderTransferStatusCompleted" - ] - }, - "model.PayLevel": { - "type": "integer", - "format": "int32", - "enum": [ - 0, - 1, - 2, - 3 - ], - "x-enum-varnames": [ - "PayLevelFree", - "PayLevelBasic", - "PayLevelStandard", - "PayLevelPremium" - ] - }, - "model.RedEnvelopeType": { - "type": "string", - "enum": [ - "fixed", - "random" - ], - "x-enum-varnames": [ - "RedEnvelopeTypeFixed", - "RedEnvelopeTypeRandom" - ] - }, "oauth.CallbackRequest": { "type": "object", "properties": { @@ -2051,348 +475,11 @@ } } }, - "order.TransactionListRequest": { - "type": "object", - "properties": { - "client_id": { - "type": "string" - }, - "endTime": { - "type": "string" - }, - "id": { - "type": "string", - "example": "0" - }, - "order_name": { - "type": "string" - }, - "page": { - "type": "integer", - "minimum": 1 - }, - "page_size": { - "type": "integer", - "maximum": 100, - "minimum": 1 - }, - "payee_transfer_status": { - "enum": [ - "pending", - "completed" - ], - "allOf": [ - { - "$ref": "#/definitions/model.OrderTransferStatus" - } - ] - }, - "payee_username": { - "type": "string" - }, - "payer_username": { - "type": "string" - }, - "startTime": { - "type": "string" - }, - "statuses": { - "type": "array", - "items": { - "type": "string" - } - }, - "types": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "payment.CreateOrderRequest": { - "type": "object", - "required": [ - "amount", - "order_name" - ], - "properties": { - "amount": { - "type": "number" - }, - "merchant_order_no": { - "type": "string", - "maxLength": 64, - "minLength": 1 - }, - "notify_url": { - "type": "string", - "maxLength": 100 - }, - "order_name": { - "type": "string", - "maxLength": 64 - }, - "payment_type": { - "type": "string" - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "return_url": { - "type": "string", - "maxLength": 100 - } - } - }, - "payment.MerchantDistributeRequest": { - "type": "object", - "required": [ - "amount", - "user_id", - "username" - ], - "properties": { - "amount": { - "type": "number" - }, - "out_trade_no": { - "type": "string", - "maxLength": 64, - "minLength": 1 - }, - "remark": { - "type": "string", - "maxLength": 100 - }, - "user_id": { - "type": "integer" - }, - "username": { - "type": "string" - } - } - }, - "payment.PayOrderRequest": { - "type": "object", - "required": [ - "order_no", - "pay_key" - ], - "properties": { - "order_no": { - "type": "string" - }, - "pay_key": { - "type": "string", - "maxLength": 6 - } - } - }, - "payment.QueryMerchantOrderResponse": { - "type": "object", - "properties": { - "addtime": { - "type": "string", - "example": "2023-12-08 12:00:00" - }, - "code": { - "type": "integer", - "example": 1 - }, - "endtime": { - "type": "string", - "example": "2023-12-08 12:05:00" - }, - "money": { - "type": "string", - "example": "10.00" - }, - "msg": { - "type": "string", - "example": "查询订单号成功!" - }, - "name": { - "type": "string", - "example": "商品名称" - }, - "out_trade_no": { - "type": "string", - "example": "M202312080001" - }, - "pid": { - "type": "string", - "example": "1001" - }, - "status": { - "type": "integer", - "example": 1 - }, - "trade_no": { - "type": "string", - "example": "123456" - }, - "type": { - "type": "string", - "example": "epay" - } - } - }, - "payment.RefundMerchantOrderResponse": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "example": 1 - }, - "msg": { - "type": "string", - "example": "退款成功" - } - } - }, - "payment.RefundOrderRequest": { - "type": "object", - "required": [ - "key", - "money", - "pid", - "trade_no" - ], - "properties": { - "key": { - "type": "string" - }, - "money": { - "type": "number" - }, - "out_trade_no": { - "type": "string" - }, - "pid": { - "type": "string" - }, - "trade_no": { - "type": "integer" - } - } - }, - "payment.TransferRequest": { - "type": "object", - "required": [ - "amount", - "pay_key", - "recipient_id", - "recipient_username" - ], - "properties": { - "amount": { - "type": "number" - }, - "pay_key": { - "type": "string", - "maxLength": 6 - }, - "recipient_id": { - "type": "string", - "example": "0" - }, - "recipient_username": { - "type": "string" - }, - "remark": { - "type": "string", - "maxLength": 100 - } - } - }, - "redenvelope.ClaimRequest": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "example": "0" - } - } - }, - "redenvelope.CreateRequest": { - "type": "object", - "required": [ - "pay_key", - "total_amount", - "total_count", - "type" - ], - "properties": { - "cover_upload_id": { - "type": "string", - "example": "0" - }, - "greeting": { - "type": "string", - "maxLength": 100 - }, - "heterotypic_upload_id": { - "type": "string", - "example": "0" - }, - "pay_key": { - "type": "string", - "maxLength": 10 - }, - "total_amount": { - "type": "number" - }, - "total_count": { - "type": "integer", - "minimum": 1 - }, - "type": { - "enum": [ - "fixed", - "random" - ], - "allOf": [ - { - "$ref": "#/definitions/model.RedEnvelopeType" - } - ] - } - } - }, - "redenvelope.ListRequest": { - "type": "object", - "required": [ - "page", - "page_size" - ], - "properties": { - "page": { - "type": "integer", - "minimum": 1 - }, - "page_size": { - "type": "integer", - "maximum": 100, - "minimum": 1 - }, - "type": { - "type": "string", - "enum": [ - "sent", - "received" - ] - } - } - }, "system_config.CreateSystemConfigRequest": { "type": "object", "required": [ "key", + "type", "value" ], "properties": { @@ -2404,6 +491,13 @@ "type": "string", "maxLength": 64 }, + "type": { + "type": "string", + "enum": [ + "system", + "business" + ] + }, "value": { "type": "string", "maxLength": 255 @@ -2446,18 +540,6 @@ } } }, - "user.UpdatePayKeyRequest": { - "type": "object", - "required": [ - "pay_key" - ], - "properties": { - "pay_key": { - "type": "string", - "maxLength": 6 - } - } - }, "user.updateUserStatusRequest": { "type": "object", "properties": { @@ -2466,65 +548,6 @@ } } }, - "user_pay_config.CreateUserPayConfigRequest": { - "type": "object", - "required": [ - "distribute_rate", - "fee_rate", - "score_rate" - ], - "properties": { - "daily_limit": { - "type": "integer" - }, - "distribute_rate": { - "type": "number" - }, - "fee_rate": { - "type": "number" - }, - "level": { - "$ref": "#/definitions/model.PayLevel" - }, - "max_score": { - "type": "integer" - }, - "min_score": { - "type": "integer" - }, - "score_rate": { - "type": "number" - } - } - }, - "user_pay_config.UpdateUserPayConfigRequest": { - "type": "object", - "required": [ - "distribute_rate", - "fee_rate", - "score_rate" - ], - "properties": { - "daily_limit": { - "type": "integer" - }, - "distribute_rate": { - "type": "number" - }, - "fee_rate": { - "type": "number" - }, - "max_score": { - "type": "integer" - }, - "min_score": { - "type": "integer" - }, - "score_rate": { - "type": "number" - } - } - }, "util.ResponseAny": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index d6268ff4..ba3f4a15 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,190 +1,4 @@ definitions: - api_key.CreateAPIKeyRequest: - properties: - app_description: - maxLength: 100 - type: string - app_homepage_url: - maxLength: 100 - type: string - app_name: - maxLength: 20 - type: string - notify_url: - maxLength: 100 - type: string - public_key: - maxLength: 100 - type: string - redirect_uri: - maxLength: 100 - type: string - test_mode: - type: boolean - required: - - app_homepage_url - - app_name - - notify_url - type: object - api_key.UpdateAPIKeyRequest: - properties: - app_description: - maxLength: 100 - type: string - app_homepage_url: - maxLength: 100 - type: string - app_name: - maxLength: 20 - type: string - notify_url: - maxLength: 100 - type: string - public_key: - maxLength: 100 - type: string - redirect_uri: - maxLength: 100 - type: string - test_mode: - type: boolean - type: object - dashboard.UserBalanceStatsResponse: - properties: - avg_amount: - type: number - max_amount: - type: number - median_amount: - type: number - min_amount: - type: number - std_dev: - type: number - total_amount: - type: number - total_count: - type: integer - type: object - dispute.CloseDisputeRequest: - properties: - dispute_id: - example: "0" - type: string - required: - - dispute_id - type: object - dispute.CreateDisputeRequest: - properties: - order_id: - example: "0" - type: string - reason: - maxLength: 100 - type: string - required: - - order_id - - reason - type: object - dispute.ListDisputesRequest: - properties: - dispute_id: - example: "0" - type: string - page: - minimum: 1 - type: integer - page_size: - maximum: 100 - minimum: 1 - type: integer - status: - enum: - - disputing - - refund - - closed - type: string - type: object - dispute.RefundReviewRequest: - properties: - dispute_id: - example: "0" - type: string - reason: - maxLength: 100 - type: string - status: - enum: - - refund - - closed - type: string - required: - - dispute_id - - status - type: object - link.PayByLinkRequest: - properties: - pay_key: - maxLength: 6 - type: string - remark: - maxLength: 100 - type: string - token: - type: string - required: - - pay_key - - token - type: object - link.PaymentLinkRequest: - properties: - amount: - type: number - product_name: - maxLength: 30 - type: string - remark: - maxLength: 100 - type: string - total_limit: - minimum: 1 - type: integer - user_limit: - minimum: 1 - type: integer - required: - - amount - - product_name - type: object - model.OrderTransferStatus: - enum: - - pending - - completed - type: string - x-enum-varnames: - - OrderTransferStatusPending - - OrderTransferStatusCompleted - model.PayLevel: - enum: - - 0 - - 1 - - 2 - - 3 - format: int32 - type: integer - x-enum-varnames: - - PayLevelFree - - PayLevelBasic - - PayLevelStandard - - PayLevelPremium - model.RedEnvelopeType: - enum: - - fixed - - random - type: string - x-enum-varnames: - - RedEnvelopeTypeFixed - - RedEnvelopeTypeRandom oauth.CallbackRequest: properties: code: @@ -192,243 +6,6 @@ definitions: state: type: string type: object - order.TransactionListRequest: - properties: - client_id: - type: string - endTime: - type: string - id: - example: "0" - type: string - order_name: - type: string - page: - minimum: 1 - type: integer - page_size: - maximum: 100 - minimum: 1 - type: integer - payee_transfer_status: - allOf: - - $ref: '#/definitions/model.OrderTransferStatus' - enum: - - pending - - completed - payee_username: - type: string - payer_username: - type: string - startTime: - type: string - statuses: - items: - type: string - type: array - types: - items: - type: string - type: array - type: object - payment.CreateOrderRequest: - properties: - amount: - type: number - merchant_order_no: - maxLength: 64 - minLength: 1 - type: string - notify_url: - maxLength: 100 - type: string - order_name: - maxLength: 64 - type: string - payment_type: - type: string - remark: - maxLength: 100 - type: string - return_url: - maxLength: 100 - type: string - required: - - amount - - order_name - type: object - payment.MerchantDistributeRequest: - properties: - amount: - type: number - out_trade_no: - maxLength: 64 - minLength: 1 - type: string - remark: - maxLength: 100 - type: string - user_id: - type: integer - username: - type: string - required: - - amount - - user_id - - username - type: object - payment.PayOrderRequest: - properties: - order_no: - type: string - pay_key: - maxLength: 6 - type: string - required: - - order_no - - pay_key - type: object - payment.QueryMerchantOrderResponse: - properties: - addtime: - example: "2023-12-08 12:00:00" - type: string - code: - example: 1 - type: integer - endtime: - example: "2023-12-08 12:05:00" - type: string - money: - example: "10.00" - type: string - msg: - example: 查询订单号成功! - type: string - name: - example: 商品名称 - type: string - out_trade_no: - example: M202312080001 - type: string - pid: - example: "1001" - type: string - status: - example: 1 - type: integer - trade_no: - example: "123456" - type: string - type: - example: epay - type: string - type: object - payment.RefundMerchantOrderResponse: - properties: - code: - example: 1 - type: integer - msg: - example: 退款成功 - type: string - type: object - payment.RefundOrderRequest: - properties: - key: - type: string - money: - type: number - out_trade_no: - type: string - pid: - type: string - trade_no: - type: integer - required: - - key - - money - - pid - - trade_no - type: object - payment.TransferRequest: - properties: - amount: - type: number - pay_key: - maxLength: 6 - type: string - recipient_id: - example: "0" - type: string - recipient_username: - type: string - remark: - maxLength: 100 - type: string - required: - - amount - - pay_key - - recipient_id - - recipient_username - type: object - redenvelope.ClaimRequest: - properties: - id: - example: "0" - type: string - required: - - id - type: object - redenvelope.CreateRequest: - properties: - cover_upload_id: - example: "0" - type: string - greeting: - maxLength: 100 - type: string - heterotypic_upload_id: - example: "0" - type: string - pay_key: - maxLength: 10 - type: string - total_amount: - type: number - total_count: - minimum: 1 - type: integer - type: - allOf: - - $ref: '#/definitions/model.RedEnvelopeType' - enum: - - fixed - - random - required: - - pay_key - - total_amount - - total_count - - type - type: object - redenvelope.ListRequest: - properties: - page: - minimum: 1 - type: integer - page_size: - maximum: 100 - minimum: 1 - type: integer - type: - enum: - - sent - - received - type: string - required: - - page - - page_size - type: object system_config.CreateSystemConfigRequest: properties: description: @@ -437,11 +14,17 @@ definitions: key: maxLength: 64 type: string + type: + enum: + - system + - business + type: string value: maxLength: 255 type: string required: - key + - type - value type: object system_config.UpdateSystemConfigRequest: @@ -468,59 +51,11 @@ definitions: required: - task_type type: object - user.UpdatePayKeyRequest: - properties: - pay_key: - maxLength: 6 - type: string - required: - - pay_key - type: object user.updateUserStatusRequest: properties: is_active: type: boolean type: object - user_pay_config.CreateUserPayConfigRequest: - properties: - daily_limit: - type: integer - distribute_rate: - type: number - fee_rate: - type: number - level: - $ref: '#/definitions/model.PayLevel' - max_score: - type: integer - min_score: - type: integer - score_rate: - type: number - required: - - distribute_rate - - fee_rate - - score_rate - type: object - user_pay_config.UpdateUserPayConfigRequest: - properties: - daily_limit: - type: integer - distribute_rate: - type: number - fee_rate: - type: number - max_score: - type: integer - min_score: - type: integer - score_rate: - type: number - required: - - distribute_rate - - fee_rate - - score_rate - type: object util.ResponseAny: properties: data: {} @@ -533,58 +68,14 @@ info: title: LINUX DO Credit version: 1.0.0 paths: - /api.php: - get: - consumes: - - application/json - parameters: - - in: query - name: act - type: string - - in: query - name: key - required: true - type: string - - in: query - maxLength: 64 - minLength: 1 - name: out_trade_no - required: true - type: string - - in: query - name: pid - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/payment.QueryMerchantOrderResponse' - tags: - - payment - post: - consumes: - - application/json - parameters: - - description: 退款请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/payment.RefundOrderRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/payment.RefundMerchantOrderResponse' - tags: - - payment /api/v1/admin/system-configs: get: + description: 返回所有系统配置列表,支持按配置类型(system/business)过滤,需要管理员权限 + parameters: + - description: 配置类型(system/business) + in: query + name: type + type: string produces: - application/json responses: @@ -592,13 +83,15 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 获取系统配置列表 tags: - admin post: consumes: - application/json + description: 创建一条新的系统配置项,配置键不可重复,同时将新配置同步到 Redis,需要管理员权限 parameters: - - description: request body + - description: 创建请求参数 in: body name: request required: true @@ -611,10 +104,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 创建系统配置 tags: - admin /api/v1/admin/system-configs/{key}: delete: + description: 根据配置键删除对应配置,同时从 Redis 中移除对应缓存,需要管理员权限 parameters: - description: 配置键 in: path @@ -628,9 +123,11 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 删除系统配置 tags: - admin get: + description: 根据配置键获取对应的系统配置详情,需要管理员权限 parameters: - description: 配置键 in: path @@ -644,18 +141,20 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 获取单个系统配置 tags: - admin put: consumes: - application/json + description: 根据配置键更新对应的配置内容,同时将更新同步到 Redis,需要管理员权限 parameters: - description: 配置键 in: path name: key required: true type: string - - description: request body + - description: 更新请求参数 in: body name: request required: true @@ -668,14 +167,16 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 更新系统配置 tags: - admin /api/v1/admin/tasks/dispatch: post: consumes: - application/json + description: 手动触发指定类型的异步任务,支持指定时间范围和用户,需要管理员权限 parameters: - - description: request body + - description: 任务请求参数 in: body name: request required: true @@ -688,10 +189,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 下发异步任务 tags: - admin /api/v1/admin/tasks/types: get: + description: 返回系统支持的所有可调度任务类型列表,需要管理员权限 produces: - application/json responses: @@ -699,97 +202,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' - tags: - - admin - /api/v1/admin/user-pay-configs: - get: - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - admin - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/user_pay_config.CreateUserPayConfigRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - admin - /api/v1/admin/user-pay-configs/{id}: - delete: - parameters: - - description: 配置ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - admin - get: - parameters: - - description: 配置ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - admin - put: - consumes: - - application/json - parameters: - - description: 配置ID - in: path - name: id - required: true - type: string - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/user_pay_config.UpdateUserPayConfigRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' + summary: 获取支持的任务类型 tags: - admin /api/v1/admin/users: get: + description: 分页返回用户列表,支持按用户 ID 和用户名筛选,需要管理员权限 parameters: - in: query minimum: 1 @@ -813,17 +231,21 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 获取用户列表 tags: - admin /api/v1/admin/users/{id}/status: put: + consumes: + - application/json + description: 启用或禁用指定用户,管理员账号无法被禁用,需要管理员权限 parameters: - description: 用户ID in: path name: id required: true type: integer - - description: 状态 + - description: 状态参数 in: body name: request required: true @@ -836,12 +258,14 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 更新用户状态 tags: - admin /api/v1/config/public: get: consumes: - application/json + description: 返回对前端公开的系统配置信息,如允许上传的文件类型、站点名称、是否开放注册等 produces: - application/json responses: @@ -849,75 +273,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 获取公共配置 tags: - config - /api/v1/dashboard/stats/daily: - get: - consumes: - - application/json - parameters: - - description: 查询天数,最大7天 - in: query - name: days - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - summary: 获取每日收支统计 - tags: - - dashboard - /api/v1/dashboard/stats/top-customers: - get: - consumes: - - application/json - parameters: - - description: 查询天数,最大7天 - in: query - name: days - required: true - type: integer - - description: 返回数量,最大10 - in: query - name: limit - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - summary: 获取Top客户 - tags: - - dashboard - /api/v1/dashboard/stats/user-balance: - get: - consumes: - - application/json - description: 统计所有用户的AvailableBalance字段 - produces: - - application/json - responses: - "200": - description: OK - schema: - allOf: - - $ref: '#/definitions/util.ResponseAny' - - properties: - data: - $ref: '#/definitions/dashboard.UserBalanceStatsResponse' - type: object - summary: 获取用户余额统计 - tags: - - dashboard /api/v1/health: get: + description: 检查服务是否正常运行 produces: - application/json responses: @@ -925,335 +286,16 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 健康检查 tags: - health - /api/v1/leaderboard: - get: - consumes: - - application/json - parameters: - - description: 页码 - in: query - name: page - required: true - type: integer - - description: 每页数量 - in: query - name: page_size - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - summary: 获取排行榜列表 - tags: - - leaderboard - /api/v1/leaderboard/me: - get: - consumes: - - application/json - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - summary: 获取当前用户排名 - tags: - - leaderboard - /api/v1/leaderboard/users/{id}: - get: - consumes: - - application/json - parameters: - - description: 用户ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - summary: 获取指定用户排名 - tags: - - leaderboard - /api/v1/merchant/api-keys: - get: - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/api_key.CreateAPIKeyRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - /api/v1/merchant/api-keys/{id}: - delete: - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - get: - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - put: - consumes: - - application/json - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/api_key.UpdateAPIKeyRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - /api/v1/merchant/api-keys/{id}/payment-links: - get: - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - post: - consumes: - - application/json - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - - description: 创建支付链接请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/link.PaymentLinkRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - /api/v1/merchant/api-keys/{id}/payment-links/{linkId}: - delete: - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - - description: Payment Link ID - format: int64 - in: path - name: linkId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - put: - consumes: - - application/json - parameters: - - description: API Key ID - format: int64 - in: path - name: id - required: true - type: integer - - description: Payment Link ID - format: int64 - in: path - name: linkId - required: true - type: integer - - description: 更新支付链接请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/link.PaymentLinkRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - /api/v1/merchant/payment: - post: - consumes: - - application/json - parameters: - - description: 支付订单请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/payment.PayOrderRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - payment - /api/v1/merchant/payment-links/{token}: - get: - parameters: - - description: 支付链接 Token - in: path - name: token - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - /api/v1/merchant/payment-links/pay: - post: - consumes: - - application/json - parameters: - - description: 支付请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/link.PayByLinkRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - merchant - /api/v1/merchant/payment/order: - get: - consumes: - - application/json - parameters: - - description: 订单号 - in: query - name: order_no - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - payment /api/v1/oauth/callback: post: + consumes: + - application/json + description: 接收前端传回的 state 和 code,完成 OAuth/OIDC 认证并建立用户会话 parameters: - - description: request body + - description: 回调请求参数 in: body name: request required: true @@ -1266,10 +308,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: OAuth 回调 tags: - oauth /api/v1/oauth/login: get: + description: 生成 OAuth 登录 URL,前端跳转至该地址完成授权 produces: - application/json responses: @@ -1277,10 +321,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 获取登录地址 tags: - oauth /api/v1/oauth/logout: get: + description: 清除当前用户的登录会话,完成退出 produces: - application/json responses: @@ -1288,10 +334,12 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 退出登录 tags: - oauth /api/v1/oauth/user-info: get: + description: 返回当前登录用户的基本信息及余额数据,需要登录 produces: - application/json responses: @@ -1299,283 +347,9 @@ paths: description: OK schema: $ref: '#/definitions/util.ResponseAny' + summary: 获取当前登录用户信息 tags: - oauth - /api/v1/order/dispute: - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/dispute.CreateDisputeRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - order - /api/v1/order/dispute/close: - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/dispute.CloseDisputeRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - order - /api/v1/order/disputes: - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - schema: - $ref: '#/definitions/dispute.ListDisputesRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - order - /api/v1/order/disputes/merchant: - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - schema: - $ref: '#/definitions/dispute.ListDisputesRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - order - /api/v1/order/refund-review: - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/dispute.RefundReviewRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - order - /api/v1/order/transactions: - post: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - schema: - $ref: '#/definitions/order.TransactionListRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - order - /api/v1/payment/transfer: - post: - consumes: - - application/json - parameters: - - description: 转账请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/payment.TransferRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - payment - /api/v1/redenvelope/{id}: - get: - parameters: - - description: 红包ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - redenvelope - /api/v1/redenvelope/claim: - post: - consumes: - - application/json - parameters: - - description: 领取红包请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/redenvelope.ClaimRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - redenvelope - /api/v1/redenvelope/covers: - get: - parameters: - - description: 封面类型 (cover/heterotypic) - in: query - name: type - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - redenvelope - /api/v1/redenvelope/create: - post: - consumes: - - application/json - parameters: - - description: 创建红包请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/redenvelope.CreateRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - redenvelope - /api/v1/redenvelope/list: - post: - consumes: - - application/json - parameters: - - description: 列表请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/redenvelope.ListRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - redenvelope - /api/v1/upload/redenvelope/cover: - post: - consumes: - - multipart/form-data - parameters: - - description: 图片文件 - in: formData - name: file - required: true - type: file - - description: 封面类型 (cover/heterotypic) - in: formData - name: type - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - upload - /api/v1/user/pay-key: - put: - consumes: - - application/json - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/user.UpdatePayKeyRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - user /f/{id}: get: parameters: @@ -1591,68 +365,4 @@ paths: description: OK tags: - upload - /pay/distribute: - post: - consumes: - - application/json - parameters: - - description: Basic Auth (base64(client_id:client_secret)) - in: header - name: Authorization - required: true - type: string - - description: 分发请求 - in: body - name: request - required: true - schema: - $ref: '#/definitions/payment.MerchantDistributeRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - payment - /pay/submit.php: - get: - consumes: - - application/x-www-form-urlencoded - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/payment.CreateOrderRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - payment - post: - consumes: - - application/x-www-form-urlencoded - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/payment.CreateOrderRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/util.ResponseAny' - tags: - - payment swagger: "2.0" diff --git a/frontend/app/(docs)/docs/terms-of-service/page.tsx b/frontend/app/(docs)/docs/terms-of-service/page.tsx index 8725147d..982394fc 100644 --- a/frontend/app/(docs)/docs/terms-of-service/page.tsx +++ b/frontend/app/(docs)/docs/terms-of-service/page.tsx @@ -9,8 +9,6 @@ export default function TermsOfServicePage() { sections={termsSections} description={ - 欢迎使用 LINUX DO Credit。本协议详述了您在使用本平台服务时的权利与义务。 -
为了保障您的合法权益,请您仔细阅读以下条款。
} diff --git a/frontend/app/(main)/admin/credit/page.tsx b/frontend/app/(main)/admin/credit/page.tsx deleted file mode 100644 index 20b4075d..00000000 --- a/frontend/app/(main)/admin/credit/page.tsx +++ /dev/null @@ -1,29 +0,0 @@ -"use client" - -import { useEffect } from "react" -import { UserPayConfigs } from "@/components/common/admin/credit" -import { useUser } from "@/contexts/user-context" -import { AdminProvider, useAdmin } from "@/contexts/admin-context" - -/* 用户积分配置页面 */ -export default function UserPayConfigPage() { - return ( - - - - ) -} - -/* 用户积分配置页面内容 */ -function UserPayConfigPageContent() { - const { user } = useUser() - const { refetchUserPayConfigs } = useAdmin() - - useEffect(() => { - if (user?.is_admin) { - refetchUserPayConfigs() - } - }, [user?.is_admin, refetchUserPayConfigs]) - - return -} diff --git a/frontend/app/(main)/balance/page.tsx b/frontend/app/(main)/balance/page.tsx deleted file mode 100644 index 6c192d70..00000000 --- a/frontend/app/(main)/balance/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { BalanceMain } from "@/components/common/balance/balance-main" - -export default function BalancePage() { - return -} diff --git a/frontend/app/(main)/components/page.tsx b/frontend/app/(main)/components/page.tsx new file mode 100644 index 00000000..06704944 --- /dev/null +++ b/frontend/app/(main)/components/page.tsx @@ -0,0 +1,751 @@ +"use client" + +import * as React from "react" +import { useState, useMemo } from "react" +import { motion, AnimatePresence } from "motion/react" +import { + Card, + CardContent, + CardHeader, + CardTitle, + CardDescription +} from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { Progress } from "@/components/ui/progress" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs" +import { + Coins, + Gift, + Inbox, + Layers, + Shield, + Info, + ArrowRight, + Terminal, + Activity, + User, + ExternalLink, + Code2, + Copy, + Check +} from "lucide-react" +import { + Area, + AreaChart, + XAxis, + ResponsiveContainer, + Tooltip as RechartsTooltip +} from "recharts" +import { toast } from "sonner" + +// ========================================== +// 1. 卡片类组件 (Cards) +// ========================================== + +function FeatureCard({ + title, + description, + linkText, + href +}: { + title: string + description: string + linkText: string + href?: string +}) { + return ( + + + {title} + + + + {description} + + + + + ) +} + +function ReceiveBanner() { + const [isVisible, setIsVisible] = useState(true) + + return ( + + {isVisible && ( + +
+
+

获得积分收益

+

+ 通过无代码选项快速开始探索或使用与我们的 API 集成的可自定义积分服务。集成方式多样,满足各种场景需求。 +

+
+ + +
+
+
+
+ )} +
+ ) +} + +// ========================================== +// 2. 仪表盘组件 (Dashboards) +// ========================================== + +const MOCK_CHART_DATA = [ + { date: "06-01", total: 12000, income: 400, expense: 200 }, + { date: "06-02", total: 13500, income: 1500, expense: 300 }, + { date: "06-03", total: 12800, income: 300, expense: 1000 }, + { date: "06-04", total: 15000, income: 2500, expense: 300 }, + { date: "06-05", total: 14200, income: 200, expense: 1000 }, + { date: "06-06", total: 16800, income: 3000, expense: 400 }, + { date: "06-07", total: 17500, income: 1200, expense: 500 }, +] + +function MockTrendChart() { + return ( + + + 积分变动趋势 (静态模拟) + +
+ + + + + + + + + + + + + +
+
+ ) +} + +function MockIncomeStats() { + const stats = [ + { date: "06-07", amount: 1200, percentage: 80 }, + { date: "06-06", amount: 3000, percentage: 100 }, + { date: "06-05", amount: 200, percentage: 15 }, + { date: "06-04", amount: 2500, percentage: 90 }, + { date: "06-03", amount: 300, percentage: 20 }, + { date: "06-02", amount: 1500, percentage: 65 }, + { date: "06-01", amount: 400, percentage: 25 }, + ] + + return ( + + +
+ 7天收入统计 (静态模拟) +
LDC 9,100.00
+
+ +
+
+ {stats.map((s) => ( +
+
+ {s.date} + +{s.amount.toFixed(2)} +
+ +
+ ))} +
+
+ ) +} + +function MockTopCustomers() { + const customers = [ + { rank: 1, name: "dev_user", count: 42, amount: 28500 }, + { rank: 2, name: "linux_do_fan", count: 28, amount: 19800 }, + { rank: 3, name: "gorm_expert", count: 19, amount: 12400 }, + { rank: 4, name: "nextjs_coder", count: 12, amount: 8500 }, + { rank: 5, name: "redis_helper", count: 8, amount: 5000 }, + ] + + return ( + + + Top 客户统计 (静态模拟) + +
+ {customers.map((c) => ( +
+
+
+ #{c.rank} + {c.name} +
+
+ {c.amount.toLocaleString()} LDC +
+
+
+ + {c.count}单 +
+
+ ))} +
+
+ ) +} + +// ========================================== +// 3. 数据表格组件 (Tables) +// ========================================== + +interface MockOrder { + id: string + order_name: string + amount: number + type: 'payment' | 'transfer' | 'community' | 'red_envelope' + status: 'success' | 'pending' | 'expired' | 'disputing' | 'refund' + order_no: string + created_at: string +} + +const MOCK_ORDERS: MockOrder[] = [ + { id: "1", order_name: "API 接口充值积分", amount: 1000, type: "payment", status: "success", order_no: "ORD202606070001", created_at: "2026-06-07 14:20:15" }, + { id: "2", order_name: "退款原路退回", amount: 500, type: "payment", status: "refund", order_no: "ORD202606070002", created_at: "2026-06-07 12:05:44" }, + { id: "3", order_name: "拼手气红包分配", amount: 200, type: "red_envelope", status: "success", order_no: "ORD202606060012", created_at: "2026-06-06 18:30:00" }, + { id: "4", order_name: "在线流转纠纷处理", amount: 1500, type: "transfer", status: "disputing", order_no: "ORD202606050025", created_at: "2026-06-05 09:12:10" }, + { id: "5", order_name: "社区绑定自动转入", amount: 350, type: "community", status: "pending", order_no: "ORD202606040081", created_at: "2026-06-04 23:45:19" }, + { id: "6", order_name: "红包超时未领过期退回", amount: 100, type: "red_envelope", status: "expired", order_no: "ORD202606030009", created_at: "2026-06-03 15:00:00" }, +] + +function MockTransactionTable() { + const getStatusBadge = (status: MockOrder["status"]) => { + const map = { + success: { text: "交易成功", class: "bg-green-500/10 text-green-600 border-green-500/20" }, + pending: { text: "等待付款", class: "bg-amber-500/10 text-amber-600 border-amber-500/20" }, + expired: { text: "订单过期", class: "bg-slate-500/10 text-slate-500 border-slate-500/20" }, + disputing: { text: "争议中", class: "bg-rose-500/10 text-rose-600 border-rose-500/20" }, + refund: { text: "交易退款", class: "bg-indigo-500/10 text-indigo-600 border-indigo-500/20" }, + } + return ( + + {map[status].text} + + ) + } + + const getTypeBadge = (type: MockOrder["type"]) => { + const map = { + payment: { text: "消耗", class: "bg-orange-500/10 text-orange-600" }, + transfer: { text: "流转", class: "bg-blue-500/10 text-blue-600" }, + community: { text: "社区", class: "bg-purple-500/10 text-purple-600" }, + red_envelope: { text: "红包", class: "bg-red-500/10 text-red-600" }, + } + return ( + + {map[type].text} + + ) + } + + return ( + +
+ + + + + + + + + + + + + + {MOCK_ORDERS.map((order) => ( + + + + + + + + + + ))} + +
名称类型额度状态流水编号交易时间操作
{order.order_name}{getTypeBadge(order.type)} + {order.amount.toFixed(2)} + {getStatusBadge(order.status)}{order.order_no}{order.created_at} + +
+
+
+ ) +} + +// ========================================== +// 4. Tab 导航组件 (Tabs) +// ========================================== + +function MockTradeTabs() { + const [activeTab, setActiveTab] = useState("receive") + + const tabContent = { + receive: { + title: "积分收益 (Receive)", + description: "本模块汇集用户所有的进账记录。可通过 API、活动赚取等形式增加积分值。", + icon: Coins, + color: "text-emerald-500", + bgColor: "bg-emerald-500/10", + }, + payment: { + title: "积分消耗 (Payment)", + description: "本模块汇总用户的出账流水。支持兑换、系统扣减与在线付款场景的费用记账。", + icon: Gift, + color: "text-orange-500", + bgColor: "bg-orange-500/10", + }, + community: { + title: "社区划转 (Community)", + description: "对接 Discourse 外部论坛同步时自动调度的积分余额转换事件。", + icon: Shield, + color: "text-purple-500", + bgColor: "bg-purple-500/10", + }, + online: { + title: "在线流转 (Online)", + description: "指代用户通过付款链接或集市网关主动进行的收单支付流转活动记录。", + icon: Activity, + color: "text-blue-500", + bgColor: "bg-blue-500/10", + }, + all: { + title: "所有活动 (All Activities)", + description: "汇总上述所有分类的完整历史日志,支持按分类检索和导出报表。", + icon: Layers, + color: "text-slate-500", + bgColor: "bg-slate-500/10", + }, + } + + const activeInfo = tabContent[activeTab as keyof typeof tabContent] || tabContent.receive + + return ( + + + + + 积分收益 + + + 积分消耗 + + + 社区划转 + + + 在线流转 + + + 所有活动 + + + + +
+
+ +
+
+

{activeInfo.title}

+

{activeInfo.description}

+
+
+
+
+
+ ) +} + +// ========================================== +// 5. 代码片段复制辅助组件 +// ========================================== + +function CodeShowcase({ code, title }: { code: string; title: string }) { + const [copied, setCopied] = useState(false) + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(code) + setCopied(true) + toast.success("代码片段已复制到剪贴板") + setTimeout(() => setCopied(false), 2000) + } catch { + toast.error("复制失败") + } + } + + return ( + + +
+ + {title} +
+ +
+
+        {code}
+      
+
+ ) +} + +// ========================================== +// 主组件 (Main Showcase) +// ========================================== + +export default function ComponentLibraryPage() { + const [activeCategory, setActiveCategory] = useState("cards") + + const categories = [ + { id: "cards", title: "卡片组件 (Cards)", desc: "页面核心功能聚合引导卡片", icon: User }, + { id: "dashboards", title: "大盘统计 (Dashboards)", desc: "交易波动与客户数据展示图表", icon: Activity }, + { id: "tables", title: "数据表格 (Tables)", desc: "支持多类型与状态的明细流水表", icon: Layers }, + { id: "tabs", title: "多标签页 (Tabs)", desc: "分类管理多页签内容切换", icon: Info }, + ] + + const codeSnippets = useMemo(() => { + return { + cards: `// FeatureCard: 三栏网格功能展示卡片 +interface FeatureCardProps { + title: string; + description: string; + linkText: string; + href?: string; +} + +export function FeatureCard({ title, description, linkText, href }: FeatureCardProps) { + return ( + + + {title} + + + + {description} + + + + + ); +}`, + dashboards: `// 7天收入统计: 进度条数据统计卡片 +interface IncomeStatItem { + date: string; + amount: number; + percentage: number; +} + +export function IncomeStatsCard({ stats }: { stats: IncomeStatItem[] }) { + return ( + + + 7天收入统计 + +
+ {stats.map(s => ( +
+
+ {s.date} + +{s.amount.toFixed(2)} +
+ +
+ ))} +
+
+ ); +}`, + tables: `// 活动记录表格: 数据明细展现 +interface MockOrder { + id: string; + order_name: string; + amount: number; + type: 'payment' | 'transfer' | 'community' | 'red_envelope'; + status: 'success' | 'pending' | 'expired' | 'disputing' | 'refund'; + order_no: string; + created_at: string; +} + +export function TransactionTable({ orders }: { orders: MockOrder[] }) { + return ( + + + + + + + + + + {orders.map(order => ( + + + + + + ))} + +
名称额度状态
{order.order_name}{order.amount.toFixed(2)}{order.status}
+ ); +}`, + tabs: `// Tab 触发器及多模块切换导航 +import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; + +export function MockTradeTabs() { + return ( + + + + 积分收益 + + + 积分消耗 + + + 积分收益模块内容... + 积分消耗模块内容... + + ); +}`, + } + }, []) + + return ( +
+
+

静态组件库 (Component Library)

+

+ 展示项目重构中提取的有价值静态组件资源,提供可视化的静态演示与代码片段,便于平台后续的二次开发集成。 +

+
+ +
+ {/* 左侧导航 */} +
+ {categories.map((cat) => ( + + ))} +
+ + {/* 右侧主展示区 */} +
+ {activeCategory === "cards" && ( + +
+

卡片组件展示

+ +
+ + + +
+
+ +
+

组件代码片段 (FeatureCard)

+ +
+
+ )} + + {activeCategory === "dashboards" && ( + +
+

大盘数据组件展示

+
+
+ +
+ + +
+
+ +
+

组件代码片段 (IncomeStats)

+ +
+
+ )} + + {activeCategory === "tables" && ( + +
+

活动明细表格展示

+ +
+ +
+

组件代码片段 (TransactionTable)

+ +
+
+ )} + + {activeCategory === "tabs" && ( + +
+

多标签导航展示

+ +
+ +
+

组件代码片段 (MockTradeTabs)

+ +
+
+ )} +
+
+
+ ) +} diff --git a/frontend/app/(main)/layout.tsx b/frontend/app/(main)/layout.tsx index d8361612..704d3883 100644 --- a/frontend/app/(main)/layout.tsx +++ b/frontend/app/(main)/layout.tsx @@ -8,7 +8,6 @@ import { SiteHeader } from "@/components/layout/header" import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar" import { UserProvider } from "@/contexts/user-context" -import { MerchantProvider } from "@/contexts/merchant-context" export default function MainLayout({ @@ -21,7 +20,6 @@ export default function MainLayout({ return ( - - ) } diff --git a/frontend/app/(main)/leaderboard/page.tsx b/frontend/app/(main)/leaderboard/page.tsx deleted file mode 100644 index 085d0ba2..00000000 --- a/frontend/app/(main)/leaderboard/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { LeaderboardMain } from "@/components/common/leaderboard/leaderboard-main" - -export default function LeaderboardPage() { - return -} diff --git a/frontend/app/(main)/merchant/online-paying/page.tsx b/frontend/app/(main)/merchant/online-paying/page.tsx deleted file mode 100644 index 24b06827..00000000 --- a/frontend/app/(main)/merchant/online-paying/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Suspense } from "react" -import { MerchantOnline } from "@/components/common/merchant/merchant-online" - -export default function Page() { - return ( - - - - ) -} diff --git a/frontend/app/(main)/merchant/page.tsx b/frontend/app/(main)/merchant/page.tsx deleted file mode 100644 index 10a64b02..00000000 --- a/frontend/app/(main)/merchant/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { MerchantMain } from "@/components/common/merchant/merchant-main" - -export default function MerchantPage() { - return -} diff --git a/frontend/app/(main)/trade/page.tsx b/frontend/app/(main)/trade/page.tsx deleted file mode 100644 index 5c37cad7..00000000 --- a/frontend/app/(main)/trade/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TradeMain } from "@/components/common/trade/trade-main" - -export default function TradePage() { - return -} diff --git a/frontend/app/(pay)/layout.tsx b/frontend/app/(pay)/layout.tsx deleted file mode 100644 index f3688ffd..00000000 --- a/frontend/app/(pay)/layout.tsx +++ /dev/null @@ -1,22 +0,0 @@ -"use client" - -import { MerchantProvider } from "@/contexts/merchant-context" -import { UserProvider } from "@/contexts/user-context" - -/** - * 积分服务页面布局 - * 为积分服务相关的页面提供社区用户和开发者上下文 - */ -export default function PayLayout({ - children, -}: { - children: React.ReactNode -}) { - return ( - - - {children} - - - ) -} diff --git a/frontend/app/(pay)/paying/online/page.tsx b/frontend/app/(pay)/paying/online/page.tsx deleted file mode 100644 index 562514e3..00000000 --- a/frontend/app/(pay)/paying/online/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Suspense } from "react" -import { PayingOnline } from "@/components/common/pay/paying/paying-online" - -export default function Page() { - return ( - - - - ) -} diff --git a/frontend/app/(pay)/paying/page.tsx b/frontend/app/(pay)/paying/page.tsx deleted file mode 100644 index 1a8cfd06..00000000 --- a/frontend/app/(pay)/paying/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Suspense } from "react" -import { PayingMain } from "@/components/common/pay/paying/paying-main" - -export default function Page() { - return ( - - - - ) -} diff --git a/frontend/app/(redenvelope)/layout.tsx b/frontend/app/(redenvelope)/layout.tsx deleted file mode 100644 index 9ead5ac7..00000000 --- a/frontend/app/(redenvelope)/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * 红包页面布局 - * 提供简洁的布局,不包含侧边栏和用户上下文 - * 允许未登录用户访问红包详情 - */ -export default function RedEnvelopeLayout({ - children, -}: { - children: React.ReactNode -}) { - return ( -
- {children} -
- ) -} \ No newline at end of file diff --git a/frontend/app/(redenvelope)/redenvelope/[id]/page.tsx b/frontend/app/(redenvelope)/redenvelope/[id]/page.tsx deleted file mode 100644 index 6ab5510a..00000000 --- a/frontend/app/(redenvelope)/redenvelope/[id]/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type { Metadata } from "next" -import { headers } from "next/headers" -import { RedEnvelopeClaimPage } from "@/components/common/redenvelope/red-envelope-claim" - -export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise { - const { id } = await params - const requestHeaders = await headers() - const protocol = requestHeaders.get("x-forwarded-proto") ?? "https" - const host = requestHeaders.get("x-forwarded-host") ?? requestHeaders.get("host") ?? "" - const baseUrl = host ? `${protocol}://${host}` : "" - const title = "你收到一个LDC红包" - const description = "点击打开领取" - const url = baseUrl ? `${baseUrl}/redenvelope/${id}` : undefined - const image = baseUrl ? `${baseUrl}/red-envelope.svg` : "/red-envelope.svg" - - return { - title, - description, - openGraph: { - title, - description, - url, - type: "website", - images: [{ url: image, width: 384, height: 512, alt: "红包" }], - } - } -} - -export default async function RedEnvelopePage({ params }: { params: Promise<{ id: string }> }) { - const { id } = await params - return -} \ No newline at end of file diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index fb32b7be..f18cf43a 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,34 +1,14 @@ import type { Metadata } from "next"; -import { Inter, Noto_Sans_SC, Geist_Mono } from 'next/font/google'; import { Toaster } from "@/components/ui/sonner"; import { ThemeProvider } from "@/components/layout/theme-provider"; import { CustomThemeProvider } from "@/lib/theme"; import { BellRingProvider } from "@/contexts/bell-ring-context"; import { NotificationSettingsProvider } from "@/contexts/notification-settings-context"; -import { RiskBlockDialog } from "@/components/common/risk/risk-block-dialog"; import "./globals.css"; -const inter = Inter({ - variable: '--font-inter', - subsets: ['latin'], - display: 'swap', -}); - -const notoSansSC = Noto_Sans_SC({ - variable: '--font-noto-sans-sc', - subsets: ['latin'], - display: 'swap', - weight: ['300', '400', '500', '600', '700'] -}); - -const geistMono = Geist_Mono({ - variable: '--font-geist-mono', - subsets: ['latin'], -}); - export const metadata: Metadata = { - title: "LINUX DO Credit", - description: "Linux Do 社区积分服务平台", + title: "Refreshing Platform", + description: "通用二次开发标准范式平台", }; export default function RootLayout({ @@ -39,11 +19,11 @@ export default function RootLayout({ return ( {children} - diff --git a/frontend/components/auth/login-page.tsx b/frontend/components/auth/login-page.tsx index 5bab9f08..7be24683 100644 --- a/frontend/components/auth/login-page.tsx +++ b/frontend/components/auth/login-page.tsx @@ -7,7 +7,6 @@ import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Spinner } from "@/components/ui/spinner" import { LoginForm } from "@/components/auth/login-form" -import { InputOTP, InputOTPGroup, InputOTPSlot } from "@/components/ui/input-otp" import { Check } from "lucide-react" import { AuroraBackground } from "@/components/ui/aurora-background" @@ -38,16 +37,6 @@ export function LoginPage() { const [isCheckingSession, setIsCheckingSession] = useState(() => !searchParams.get('state') || !searchParams.get('code')) const [loginSuccess, setLoginSuccess] = useState(false) - const [needsPayKeySetup, setNeedsPayKeySetup] = useState(false) - - const [payKey, setPayKey] = useState("") - const [confirmPayKey, setConfirmPayKey] = useState("") - const [isSubmittingPayKey, setIsSubmittingPayKey] = useState(false) - const [setupStep, setSetupStep] = useState<'password' | 'confirm'>('password') - - const isPayKeyValid = payKey.length === 6 && /^\d{6}$/.test(payKey) - const isConfirmValid = confirmPayKey.length === 6 && /^\d{6}$/.test(confirmPayKey) - const passwordsMatch = payKey === confirmPayKey const resolveRedirectTarget = useCallback(() => { const callbackUrl = searchParams.get('callbackUrl') @@ -61,18 +50,6 @@ export function LoginPage() { return target }, [searchParams]) - /* 安全密码输入 */ - const handlePayKeyChange = (value: string) => { - const numericValue = value.replace(/\D/g, '') - setPayKey(numericValue) - } - - /* 确认安全密码 */ - const handleConfirmPayKeyChange = (value: string) => { - const numericValue = value.replace(/\D/g, '') - setConfirmPayKey(numericValue) - } - /* 登录页兜底:已登录用户直接跳转 */ useEffect(() => { const state = searchParams.get('state') @@ -133,19 +110,12 @@ export function LoginPage() { setIsProcessingCallback(true) try { await services.auth.handleCallback({ state, code }) + setLoginSuccess(true) + toast.success("登录成功") - const user = await services.auth.getUserInfo() - - if (!user.is_pay_key) { - setNeedsPayKeySetup(true) - } else { - setLoginSuccess(true) - toast.success("登录成功") - - setTimeout(() => { - router.replace(resolveRedirectTarget()) - }, 1500) - } + setTimeout(() => { + router.replace(resolveRedirectTarget()) + }, 1500) } catch (error) { console.error('OAuth callback error:', error) toast.error(error instanceof Error ? error.message : "登录失败,请重试") @@ -157,147 +127,6 @@ export function LoginPage() { handleOAuthCallback() }, [searchParams, router, resolveRedirectTarget]) - /* 安全密码设置 */ - const handlePayKeySubmit = async (e: React.FormEvent) => { - e.preventDefault() - - if (setupStep === 'password') { - if (!isPayKeyValid) { - toast.error("安全密码必须为6位数字") - return - } - setSetupStep('confirm') - } else { - if (!isConfirmValid) { - toast.error("确认密码必须为6位数字") - return - } - - if (!passwordsMatch) { - toast.error("两次输入的安全密码不一致") - setSetupStep('password') - setConfirmPayKey("") - return - } - - setIsSubmittingPayKey(true) - try { - await services.user.updatePayKey(payKey) - toast.success("安全密码设置成功") - setNeedsPayKeySetup(false) - setLoginSuccess(true) - setPayKey("") - setConfirmPayKey("") - setSetupStep('password') - setTimeout(() => { - router.replace(resolveRedirectTarget()) - }, 1500) - } catch (error) { - const errorMessage = error instanceof Error ? error.message : "设置安全密码失败" - toast.error(errorMessage) - setSetupStep('password') - setConfirmPayKey("") - } finally { - setIsSubmittingPayKey(false) - } - } - } - - /* 渲染 PayKey 设置界面 */ - const renderPayKeySetup = (key: string) => ( - -
-

- {setupStep === 'password' ? '设置安全密码' : '确认安全密码'} -

-

- {setupStep === 'password' - ? '请设置6位数字安全密码,用于安全操作' - : '请再次输入密码进行确认'} -

-
- -
-
- {setupStep === 'password' ? ( - - - {[0, 1, 2, 3, 4, 5].map((i) => ( - - ))} - - - ) : ( -
- - - {[0, 1, 2, 3, 4, 5].map((i) => ( - - ))} - - - {!passwordsMatch && confirmPayKey.length === 6 && ( - - 两次输入的密码不一致 - - )} -
- )} -
- -
- {setupStep === 'confirm' && ( - - )} - -
-
-
- ) - return ( 请稍候,我们正在确认当前会话...

- ) : needsPayKeySetup ? ( - renderPayKeySetup("oauth-pay-key-setup") ) : loginSuccess ? (
- * ``` - * @param {UserPayConfig} config - 积分配置 - * @param {Partial} editData - 编辑数据 - * @param {function} onEditDataChange - 编辑数据改变回调 - * @param {function} onSave - 保存回调 - * @param {boolean} saving - 是否正在保存 - * @returns {React.ReactNode} 积分配置详情面板组件 - */ -function PayConfigDetailPanel({ - config, - editData, - onEditDataChange, - onSave, - saving -}: { - config: UserPayConfig | null - editData: Partial - onEditDataChange: (field: keyof UserPayConfig, value: UserPayConfig[keyof UserPayConfig]) => void - onSave: () => void - saving: boolean -}) { - - - return ( - -
-
-
- -

Level {config?.level}

-
- -
- -

{config?.id}

-
- -
- -

{config ? formatDateTime(config.created_at) : ''}

-
- -
- -

{config ? formatDateTime(config.updated_at) : ''}

-
- - - - -
- -
-
- -
- { - const value = e.target.value - if (value === '') { - onEditDataChange('min_score', 0) - return - } - - const numValue = parseInt(value) - if (isNaN(numValue)) { - return - } - - if (numValue >= 0) { - onEditDataChange('min_score', numValue) - } - }} - className="text-xs text-right h-4 w-16 px-0 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-[12px]" - /> -

LDC

-
-
- -
- -
- { - const value = e.target.value - if (value === '') { - onEditDataChange('max_score', null) - return - } - - const numValue = parseInt(value) - if (isNaN(numValue)) { - return - } - - if (numValue >= 0) { - onEditDataChange('max_score', numValue) - } - }} - className="text-xs text-right h-4 w-16 px-0 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-[12px]" - /> -

LDC

-
-
- -
- -
- { - const value = e.target.value - if (value === '') { - onEditDataChange('fee_rate', '0') - return - } - - const numValue = parseInt(value) - if (isNaN(numValue)) { - return - } - - if (numValue >= 0 && numValue <= 100) { - onEditDataChange('fee_rate', (numValue / 100).toString()) - } - }} - className="text-xs text-right h-4 w-16 px-0 mr-3 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-[12px]" - /> -

%

-
-
- -
- -
- { - const value = e.target.value - if (value === '') { - onEditDataChange('score_rate', '0') - return - } - - const numValue = parseInt(value) - if (isNaN(numValue)) { - return - } - - if (numValue >= 0 && numValue <= 100) { - onEditDataChange('score_rate', (numValue / 100).toString()) - } - }} - className="text-xs text-right h-4 w-16 px-0 mr-3 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-[12px]" - /> -

%

-
-
- -
- -
- { - const value = e.target.value - if (value === '') { - onEditDataChange('distribute_rate', '0') - return - } - - const numValue = parseInt(value) - if (isNaN(numValue)) { - return - } - - if (numValue >= 0 && numValue <= 100) { - onEditDataChange('distribute_rate', (numValue / 100).toString()) - } - }} - className="text-xs text-right h-4 w-16 px-0 mr-3 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-[12px]" - /> -

%

-
-
- -
- -
- { - const value = e.target.value - if (value === '') { - onEditDataChange('daily_limit', null) - return - } - - const numValue = parseInt(value) - if (isNaN(numValue)) { - return - } - - if (numValue >= 0) { - onEditDataChange('daily_limit', numValue) - } - }} - className="text-xs text-right h-4 w-16 px-0 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-[12px]" - /> -

LDC

-
-
-
-
-
- ) -} - - - - - -/** - * 用户积分配置管理组件 - * - * @example - * ```tsx - * - * ``` - * @returns {React.ReactNode} 用户积分配置管理组件 - */ -export function UserPayConfigs() { - const { - userPayConfigs: configs, - userPayConfigsLoading: loading, - userPayConfigsError: error, - refetchUserPayConfigs, - updateUserPayConfig, - deleteUserPayConfig - } = useAdmin() - - const getInitialEditData = (config: UserPayConfig) => ({ - min_score: config.min_score, - max_score: config.max_score, - daily_limit: config.daily_limit, - fee_rate: config.fee_rate.toString(), - score_rate: config.score_rate.toString(), - distribute_rate: config.distribute_rate.toString(), - }) - - const handleSave = async (config: UserPayConfig, editData: Partial) => { - if (!config) return - - await updateUserPayConfig(config.id, { - min_score: editData.min_score ?? config.min_score, - max_score: editData.max_score, - daily_limit: editData.daily_limit, - fee_rate: editData.fee_rate?.toString() ?? config.fee_rate.toString(), - score_rate: editData.score_rate?.toString() ?? config.score_rate.toString(), - distribute_rate: editData.distribute_rate?.toString() ?? config.distribute_rate.toString(), - }) - await refetchUserPayConfigs() - } - - const handleDelete = async (config: UserPayConfig) => { - await deleteUserPayConfig(config.id) - } - - return ( - - title="积分配置" - data={configs} - loading={loading} - error={error} - onReload={refetchUserPayConfigs} - getInitialEditData={getInitialEditData} - onSave={handleSave} - onDelete={handleDelete} - getId={(config) => config.id} - emptyDescription="未发现积分配置" - loadingDescription="配置加载中" - columns={[ - { header: "等级", cell: (item) => Level {item.level}, width: "min-w-[80px]", align: "left" }, - { header: "最低分", cell: (item) => item.min_score, width: "min-w-[200px]", align: "left" }, - { header: "最高分", cell: (item) => item.max_score || "无限制", width: "min-w-[200px]", align: "left" }, - { header: "每日限额", cell: (item) => item.daily_limit ? `LDC ${ item.daily_limit.toLocaleString() }` : "无限制", width: "min-w-[200px]", align: "left" }, - { header: "费率", cell: (item) => `${ (Number(item.fee_rate) * 100).toFixed(2) }%`, width: "min-w-[200px]", align: "left" }, - { header: "分数转化率", cell: (item) => `${ (Number(item.score_rate) * 100).toFixed(2) }%`, width: "min-w-[200px]", align: "left" }, - { header: "分发费率", cell: (item) => `${ (Number(item.distribute_rate) * 100).toFixed(2) }%`, width: "min-w-[200px]", align: "left" }, - { header: "更新时间", cell: (item) => {formatDateTime(item.updated_at)}, width: "min-w-[200px]", align: "left" }, - ]} - renderDetail={({ selected, hovered, editData, onEditDataChange, onSave, saving }) => ( - - )} - /> - ) -} diff --git a/frontend/components/common/admin/system.tsx b/frontend/components/common/admin/system.tsx index a4f79518..e77c3735 100644 --- a/frontend/components/common/admin/system.tsx +++ b/frontend/components/common/admin/system.tsx @@ -4,6 +4,7 @@ import * as React from "react" import { Input } from "@/components/ui/input" import { Switch } from "@/components/ui/switch" import { ManagePage, ManageDetailPanel } from "@/components/common/general/manage-pannel" +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs" import { formatDateTime } from "@/lib/utils" import type { SystemConfig } from "@/lib/services" @@ -70,7 +71,22 @@ function SystemConfigDetailPanel({ /> ) : (
+
+ + + {config?.type === 'system' ? '系统配置' : '业务配置'} + +
+

{config ? formatDateTime(config.created_at) : ''}

@@ -139,6 +166,12 @@ export function SystemConfigs() { deleteSystemConfig } = useAdmin() + const [activeTab, setActiveTab] = React.useState<'system' | 'business'>('business') + + React.useEffect(() => { + refetchSystemConfigs(activeTab) + }, [activeTab, refetchSystemConfigs]) + const getInitialEditData = (config: SystemConfig) => ({ value: config.value, description: config.description @@ -151,7 +184,6 @@ export function SystemConfigs() { value: editData.value ?? config.value, description: editData.description ?? config.description }) - await refetchSystemConfigs() } const handleDelete = async (config: SystemConfig) => { @@ -164,13 +196,21 @@ export function SystemConfigs() { data={configs} loading={loading} error={error} - onReload={refetchSystemConfigs} + onReload={() => refetchSystemConfigs(activeTab)} getInitialEditData={getInitialEditData} onSave={handleSave} onDelete={handleDelete} getId={(config) => config.key} emptyDescription="未发现系统配置" loadingDescription="配置加载中" + headerExtra={ + setActiveTab(val as 'system' | 'business')} className="w-[180px]"> + + 业务配置 + 系统配置 + + + } columns={[ { header: "配置键", cell: (item) => {item.key}, width: "200px" }, { header: "配置值", cell: (item) => {item.value}, width: "120px" }, diff --git a/frontend/components/common/admin/users.tsx b/frontend/components/common/admin/users.tsx index 478748a0..ddf7955c 100644 --- a/frontend/components/common/admin/users.tsx +++ b/frontend/components/common/admin/users.tsx @@ -8,10 +8,10 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@ import { Sheet, SheetTitle, SheetContent } from "@/components/ui/sheet" import { Badge } from "@/components/ui/badge" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { Layers, Search, UserX, UserCheck, Eye, Wallet, CreditCard, ShieldCheck, Filter, X, ChevronDown, ChevronLeft, ChevronRight, Users, Loader2 } from "lucide-react" +import { Layers, Search, UserX, UserCheck, Eye, ShieldCheck, Filter, X, ChevronDown, ChevronLeft, ChevronRight, Loader2 } from "lucide-react" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" -import { AdminUser, AdminService, DispatchTaskRequest } from "@/lib/services" +import { AdminUser, AdminService } from "@/lib/services" import { toast } from "sonner" import { formatDateTime } from "@/lib/utils" import { EmptyStateWithBorder } from "@/components/layout/empty" @@ -43,7 +43,6 @@ export function UsersManager() { const [selectedUser, setSelectedUser] = useState(null) const [detailOpen, setDetailOpen] = useState(false) - const [updatingUserId, setUpdatingUserId] = useState(null) useEffect(() => { fetchUsers() @@ -62,25 +61,7 @@ export function UsersManager() { setDetailOpen(true) } - const handleUpdateCredits = async (user: AdminUser) => { - try { - setUpdatingUserId(user.id) - const params: DispatchTaskRequest = { - task_type: 'user_gamification', - user_id: user.id - } - await AdminService.dispatchTask(params) - toast.success('积分更新任务已下发', { - description: `正在更新用户 ${ user.username } 的积分数据` - }) - } catch (err) { - toast.error('任务下发失败', { - description: err instanceof Error ? err.message : '未知错误' - }) - } finally { - setUpdatingUserId(null) - } - } + const totalPages = Math.ceil(total / pageSize) const hasSearchFilter = Boolean(searchUserId || searchUsername) @@ -315,12 +296,7 @@ export function UsersManager() { ID 用户 - 余额 - 基准分 - 支付分 - 总收益 - 总消耗 - 总划转 + 上次登陆 注册时间 上次更新 @@ -358,24 +334,7 @@ export function UsersManager() {
- - {Number(user.available_balance).toFixed(2)} - - - {Number(user.community_balance).toFixed(2)} - - - {Number(user.pay_score).toFixed(2)} - - - {Number(user.total_receive).toFixed(2)} - - - {Number(user.total_payment).toFixed(2)} - - - {Number(user.total_community).toFixed(2)} - + {formatDateTime(user.last_login_at)} @@ -404,24 +363,7 @@ export function UsersManager() { - - - - - - - 更新积分 - - - + @@ -487,60 +429,7 @@ export function UsersManager() { -
-

核心资产

-
-
-
- - 可用余额 -
-
- {Number(selectedUser.available_balance).toFixed(2)} -
-
-
-
- - 支付积分 -
-
- {Number(selectedUser.pay_score).toFixed(2)} -
-
-
-
- - 社区余额 -
-
- {Number(selectedUser.community_balance).toFixed(2)} -
-
-
-
- - -
-
-

财务概况

-
-
- 累计收益 - +{Number(selectedUser.total_community).toFixed(2)} -
-
- 累计收入 - +{Number(selectedUser.total_receive).toFixed(2)} -
-
- 累计支出 - {Number(selectedUser.total_payment) === 0 ? '0.00' : `-${ Number(selectedUser.total_payment).toFixed(2) }`} -
-
-
-

系统记录

diff --git a/frontend/components/common/balance/balance-main.tsx b/frontend/components/common/balance/balance-main.tsx deleted file mode 100644 index be2fa391..00000000 --- a/frontend/components/common/balance/balance-main.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client" - -import * as React from "react" -import { CountingNumber } from "@/components/animate-ui/primitives/texts/counting-number" -import { BalanceReport } from "@/components/common/balance/balance-report" -import { BalanceSummary } from "@/components/common/balance/balance-summary" -import { BalanceTable } from "@/components/common/balance/balance-table" -import { useUser } from "@/contexts/user-context" - -/** - * 积分余额主页面组件 - * - * 负责组装积分余额页面的各个子组件,包括积分余额总览、积分余额摘要、近期活动和报告侧边栏 - */ -export function BalanceMain() { - const { user, loading } = useUser() - - /** 计算总余额 */ - const totalBalance = React.useMemo(() => { - return parseFloat(user?.available_balance || '0') - }, [user?.available_balance]) - - return ( -
-
-

- 积分 - LDC - - {loading ? "-" : } - -

-
- -
-
-
-

积分摘要

- -
- -
-

近期活动

- -
-
- - -
-
- ) -} diff --git a/frontend/components/common/balance/balance-report.tsx b/frontend/components/common/balance/balance-report.tsx deleted file mode 100644 index e502f084..00000000 --- a/frontend/components/common/balance/balance-report.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import * as React from "react" - -/** - * 余额报告组件 - * - * 显示可下载或查看的报告列表 - */ -export function BalanceReport() { - return ( -
-

报告

-
暂无报告
-
- ) -} diff --git a/frontend/components/common/balance/balance-summary.tsx b/frontend/components/common/balance/balance-summary.tsx deleted file mode 100644 index 89076372..00000000 --- a/frontend/components/common/balance/balance-summary.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import * as React from "react" -import { CountingNumber } from "@/components/animate-ui/primitives/texts/counting-number" -import { useUser } from "@/contexts/user-context" - -/** 颜色配置 - 统一管理主题色 */ -const COLORS = { - available: "bg-primary/80", - pending: "bg-zinc-400/80", - emptyState: "bg-muted/50", -} as const - -/** - * 计算积分余额百分比 - */ -function calculatePercentages(available: number, total: number) { - if (total <= 0) { - return { available: 0, pending: 0 } - } - - const pending = total - available - return { - available: (available / total) * 100, - pending: (pending / total) * 100, - } -} - -/** - * 安全转换数字,避免 NaN - */ -function safeNumber(value: number): number { - return typeof value === 'number' && !isNaN(value) ? value : 0 -} - -/** - * 积分余额摘要组件 - * - * 显示积分余额的可视化摘要,包括可视化进度条和详细的积分余额分类列表 - */ -export function BalanceSummary() { - const { user, loading } = useUser() - - const available = parseFloat(user?.available_balance || '0') - const pending = parseFloat(user?.pending_balance || '0') - const total = available + pending - - const percentages = React.useMemo( - () => calculatePercentages(available, total), - [available, total] - ) - - return ( -
-
-
-
-
- -
-
- 积分类型 - 值 -
- -
-
- - - {loading ? "-" : ( - - )} LDC - -
- -
-
- - - {loading ? "-" : ( - - )} LDC - -
-
-
- ) -} diff --git a/frontend/components/common/balance/balance-table.tsx b/frontend/components/common/balance/balance-table.tsx deleted file mode 100644 index a33e358f..00000000 --- a/frontend/components/common/balance/balance-table.tsx +++ /dev/null @@ -1,150 +0,0 @@ -"use client" - -import * as React from "react" -import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs" -import { TransactionTableList } from "@/components/common/general/table-data" -import { TransactionProvider, useTransaction } from "@/contexts/transaction-context" -import { DEFAULT_ORDER_TYPES, type OrderType } from "@/lib/services" -import { formatLocalDate } from "@/lib/utils" - -/** 标签触发器样式 */ -const TAB_TRIGGER_STYLES = - "data-[state=active]:bg-transparent " + - "data-[state=active]:shadow-none " + - "data-[state=active]:border-0 " + - "data-[state=active]:border-b-2 " + - "data-[state=active]:border-indigo-500 " + - "bg-transparent " + - "rounded-none " + - "border-0 " + - "border-b-2 " + - "border-transparent " + - "px-0 " + - "text-sm " + - "font-bold " + - "text-muted-foreground " + - "data-[state=active]:text-indigo-500 " + - "-mb-[2px] " + - "relative " + - "hover:text-foreground " + - "transition-colors " + - "flex-none" - -/** 标签配置 - 数据驱动渲染 */ -const TABS = [ - { value: "receive" as const, label: "积分收益" }, - { value: "payment" as const, label: "积分消耗" }, - { value: "community" as const, label: "社区划转" }, - { value: "online" as const, label: "在线流转" }, - { value: "all" as const, label: "所有活动" }, -] as const - -/** - * 计算最近30天的时间范围 - * 每次调用时重新计算,避免缓存过期时间 - */ -function getTimeRange() { - const now = new Date() - now.setHours(23, 59, 59, 999) - const start = new Date(now) - start.setDate(start.getDate() - 30) - start.setHours(0, 0, 0, 0) - return { - startTime: formatLocalDate(start), - endTime: formatLocalDate(now) - } -} - -/** - * 积分余额活动表格组件 - * - * 显示不同类型的积分余额活动记录,支持多标签切换和分页加载 - */ -export function BalanceTable() { - const [activeTab, setActiveTab] = React.useState("all") - const [timeRange, setTimeRange] = React.useState<{ startTime: string; endTime: string } | null>(null) - - React.useEffect(() => { - setTimeRange(getTimeRange()) - }, []) - - if (!timeRange) { - return null - } - - return ( -
- setActiveTab(value as OrderType | "all")} - className="w-full" - > - - {TABS.map((tab) => ( - - {tab.label} - - ))} - - -
- - - -
-
-
- ) -} - -/** - * 积分余额活动列表组件 - * - * 负责获取和显示积分余额活动数据 - */ -const TransactionList = React.memo(function TransactionList({ type }: { type?: OrderType }) { - const { - transactions, - loading, - error, - lastParams, - fetchTransactions, - } = useTransaction() - - /** 当积分余额活动类型变化时重新加载数据 */ - React.useEffect(() => { - fetchTransactions({ - page: 1, - types: type ? [type] : DEFAULT_ORDER_TYPES, - startTime: lastParams.startTime, - endTime: lastParams.endTime, - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [type]) - - return ( - fetchTransactions({ - page: 1, - types: type ? [type] : DEFAULT_ORDER_TYPES, - startTime: lastParams.startTime, - endTime: lastParams.endTime, - })} - /> - ) -}) diff --git a/frontend/components/common/docs/api.tsx b/frontend/components/common/docs/api.tsx index f14b39c3..79fb6051 100644 --- a/frontend/components/common/docs/api.tsx +++ b/frontend/components/common/docs/api.tsx @@ -151,7 +151,7 @@ signBase64 = base64.StdEncoding.EncodeToString(signature)`}
  • 协议:EasyPay / CodePay / VPay 兼容协议
  • 服务类型:仅支持 type=epay
  • 网关基址:https://credit.linux.do/epay
  • -
  • 订单有效期:取系统配置 merchant_order_expire_minutes(平台端设置)
  • +
  • 订单有效期:取系统配置 order_expire_minutes(平台端设置)
  • 2.2 常见错误

    diff --git a/frontend/components/common/docs/how-to-use.tsx b/frontend/components/common/docs/how-to-use.tsx index c60006e0..a22419e6 100644 --- a/frontend/components/common/docs/how-to-use.tsx +++ b/frontend/components/common/docs/how-to-use.tsx @@ -55,7 +55,7 @@ export const howToUseSections: PolicySection[] = [
  • 创建应用
      -
    • 前往 集市中心
    • +
    • 前往 控制面板
    • 点击顶部右侧 创建应用 按钮
    • 填写必要信息:应用名称、应用主页、回调地址、通知地址
    @@ -86,7 +86,7 @@ export const howToUseSections: PolicySection[] = [
  • 适用场景:无代码开发基础,或只用于简单的积分服务。
  • 操作步骤:
      -
    1. 前往 集市中心 创建应用,获取 API 凭证
    2. +
    3. 前往 控制面板 创建应用,获取 API 凭证
    4. 选择应用,点击 在线收款 功能
    5. 创建在线积分服务
    6. 获取唯一积分服务链接
    7. @@ -101,7 +101,7 @@ export const howToUseSections: PolicySection[] = [
    8. 操作步骤:
      1. - 前往 集市中心,点击 创建应用,填写 New API 站点信息: + 前往 控制面板,点击 创建应用,填写 New API 站点信息:
        diff --git a/frontend/components/common/general/dispute-dialog.tsx b/frontend/components/common/general/dispute-dialog.tsx deleted file mode 100644 index 37e15106..00000000 --- a/frontend/components/common/general/dispute-dialog.tsx +++ /dev/null @@ -1,760 +0,0 @@ -"use client" - -import * as React from "react" -import { useState } from "react" -import { Button } from "@/components/ui/button" -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" -import { Spinner } from "@/components/ui/spinner" -import { AlertTriangle, X, Layers, Banknote, TicketSlash } from "lucide-react" -import { formatDateTime } from "@/lib/utils" -import type { Order, DisputeWithOrder, Dispute } from "@/lib/services" -import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog" -import { Label } from "@/components/ui/label" -import { DisputeService } from "@/lib/services" -import { toast } from "sonner" -import { useIsMobile } from "@/hooks/use-mobile" -import { usePublicConfig } from "@/hooks/use-public-config" -import { useTransaction } from "@/contexts/transaction-context" -import { useUser } from "@/contexts/user-context" -import { Textarea } from "@/components/ui/textarea" -import { typeConfig } from "@/components/common/general/table-filter" -import { VisuallyHidden } from "@radix-ui/react-visually-hidden" - -type DisputeViewer = 'payer' | 'payee' - -/** - * 活动详情弹窗 - */ -export function OrderDetailDialog({ order }: { order: Order }) { - const [open, setOpen] = useState(false) - - return ( - <> - - - - - -

        查看详情

        -
        -
        - - - - - 积分流转详情 - 查看积分活动的详细信息 - - -
        -
        -

        {order.app_name || 'RECEIPT'}

        -

        - {formatDateTime(order.created_at)} -

        -
        - -
        -

        Total Credits

        -
        - {parseFloat(order.amount).toFixed(2)} -
        -
        - -
        -
        - 编号 - {order.order_no} -
        -
        - 类型 - {typeConfig[order.type]?.label || order.type} -
        -
        - 消费方 - {order.payer_username} -
        -
        - 服务方 - {order.payee_username} -
        -
        - 备注 - {order.remark} -
        - {(order.status === 'success' || order.status === 'refund') && ( -
        - 时间 - {formatDateTime(order.trade_time)} -
        - )} -
        - -
        -
        - {[...Array(30)].map((_, i) => ( -
        - ))} -
        -

        - LINUX DO Credit -

        -
        -
        - -
        - - ) -} - -/** - * 发起争议弹窗 - */ -export function CreateDisputeDialog({ order, onSuccess }: { order: Order; onSuccess?: () => void }) { - const isMobile = useIsMobile() - const { config: publicConfig, loading: configLoading, error: configError } = usePublicConfig() - const { updateOrderStatus } = useTransaction() - const [open, setOpen] = useState(false) - const [loading, setLoading] = useState(false) - const [reason, setReason] = useState("") - - const resetForm = () => { - setReason("") - } - - const handleButtonClick = async () => { - if (configLoading) { - try { - await new Promise(resolve => setTimeout(resolve, 100)) - if (configLoading) { - toast.error('配置加载中', { description: '请稍候再试' }) - return - } - } catch { - toast.error('配置加载失败', { description: '请刷新页面重试' }) - return - } - } - - if (configError || !publicConfig) { - toast.error('无法获取配置', { description: configError?.message || '请刷新页面重试' }) - return - } - - const tradeTime = new Date(order.trade_time) - const expiryTime = new Date(tradeTime.getTime() + publicConfig.dispute_time_window_hours * 60 * 60 * 1000) - const now = new Date() - - if (now > expiryTime) { - toast.error('无法发起争议', { description: '已超过最晚发起争议时间' }) - return - } - - setOpen(true) - } - - const handleOpenChange = (newOpen: boolean) => { - if (newOpen && !loading) { - resetForm() - } - setOpen(newOpen) - } - - const handleCreateDispute = async () => { - if (!reason.trim()) { - toast.error('表单验证失败', { description: '请填写争议原因' }) - return - } - - if (reason.length > 100) { - toast.error('表单验证失败', { description: '争议原因不能超过 100 个字符' }) - return - } - - try { - setLoading(true) - const dispute = await DisputeService.createDispute({ order_id: order.id, reason: reason.trim() }) - toast.success('争议已发起', { description: '请等待服务方处理' }) - updateOrderStatus(order.id, { - status: 'disputing', - dispute_id: dispute.id - }) - setOpen(false) - onSuccess?.() - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : '发起争议失败' - toast.error('发起争议失败', { description: errorMessage }) - } finally { - setLoading(false) - } - } - - return ( - <> - - - - - -

        发起争议

        -
        -
        - - - - 发起争议 - - 如果您对该积分活动有疑问,可以发起争议,服务方将在规定时间内处理。 - - - -
        -
        - -