feat(活动): 新增抽奖记录等级筛选功能并优化展示信息
refactor(抽奖记录): 重构抽奖记录列表接口,支持按等级筛选 新增用户昵称、头像及奖品名称、图片等展示字段 优化分页逻辑,默认返回最新100条记录 feat(游戏): 添加扫雷游戏验证和结算接口 新增游戏票据验证和结算相关接口定义及Swagger文档 docs(API): 更新Swagger文档 更新抽奖记录和游戏相关接口的文档描述 style(路由): 添加游戏路由注释 添加扫雷游戏接口路由的占位注释
This commit is contained in:
parent
e2782a69d3
commit
c8b04e2bc6
BIN
build/.DS_Store
vendored
BIN
build/.DS_Store
vendored
Binary file not shown.
BIN
build/resources/.DS_Store
vendored
BIN
build/resources/.DS_Store
vendored
Binary file not shown.
@ -38,7 +38,7 @@
|
|||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="/assets/index-q3pUuhDl.js"></script>
|
<script type="module" crossorigin src="/assets/index-iR6j7F-E.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-q7XdNN2Z.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-q7XdNN2Z.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
157
docs/docs.go
157
docs/docs.go
@ -3451,7 +3451,7 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
"/api/app/activities/{activity_id}/issues/{issue_id}/draw_logs": {
|
"/api/app/activities/{activity_id}/issues/{issue_id}/draw_logs": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "查看指定活动期数的抽奖记录,支持分页",
|
"description": "查看指定活动期数的抽奖记录,支持等级筛选(默认返回最新的100条,不支持自定义翻页)",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@ -3479,19 +3479,9 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 1,
|
"description": "奖品等级过滤",
|
||||||
"description": "页码",
|
"name": "level",
|
||||||
"name": "page",
|
"in": "query"
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 20,
|
|
||||||
"description": "每页数量,最多100",
|
|
||||||
"name": "page_size",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -5905,6 +5895,74 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/internal/game/settle": {
|
||||||
|
"post": {
|
||||||
|
"description": "游戏结束后结算并发放奖励",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Internal"
|
||||||
|
],
|
||||||
|
"summary": "结算游戏",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "结算信息",
|
||||||
|
"name": "result",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.SettleGameRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.SettleGameResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/internal/game/verify": {
|
||||||
|
"post": {
|
||||||
|
"description": "验证游戏票据是否有效",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Internal"
|
||||||
|
],
|
||||||
|
"summary": "验证游戏票据",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "票据信息",
|
||||||
|
"name": "ticket",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.VerifyTicketRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.VerifyTicketResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/pay/wechat/notify": {
|
"/pay/wechat/notify": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "接收微信支付结果通知,验证签名并处理订单状态",
|
"description": "接收微信支付结果通知,验证签名并处理订单状态",
|
||||||
@ -8174,6 +8232,9 @@ const docTemplate = `{
|
|||||||
"app.drawLogItem": {
|
"app.drawLogItem": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"avatar": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"current_level": {
|
"current_level": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -8195,8 +8256,17 @@ const docTemplate = `{
|
|||||||
"reward_id": {
|
"reward_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"reward_image": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"reward_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"user_name": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -9161,6 +9231,65 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"minesweeper.SettleGameRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"match_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"score": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"ticket": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minesweeper.SettleGameResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"reward": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minesweeper.VerifyTicketRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ticket": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minesweeper.VerifyTicketResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"remaining_times": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"model.ActivityDrawEffects": {
|
"model.ActivityDrawEffects": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@ -3443,7 +3443,7 @@
|
|||||||
},
|
},
|
||||||
"/api/app/activities/{activity_id}/issues/{issue_id}/draw_logs": {
|
"/api/app/activities/{activity_id}/issues/{issue_id}/draw_logs": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "查看指定活动期数的抽奖记录,支持分页",
|
"description": "查看指定活动期数的抽奖记录,支持等级筛选(默认返回最新的100条,不支持自定义翻页)",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@ -3471,19 +3471,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 1,
|
"description": "奖品等级过滤",
|
||||||
"description": "页码",
|
"name": "level",
|
||||||
"name": "page",
|
"in": "query"
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 20,
|
|
||||||
"description": "每页数量,最多100",
|
|
||||||
"name": "page_size",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -5897,6 +5887,74 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/internal/game/settle": {
|
||||||
|
"post": {
|
||||||
|
"description": "游戏结束后结算并发放奖励",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Internal"
|
||||||
|
],
|
||||||
|
"summary": "结算游戏",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "结算信息",
|
||||||
|
"name": "result",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.SettleGameRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.SettleGameResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/internal/game/verify": {
|
||||||
|
"post": {
|
||||||
|
"description": "验证游戏票据是否有效",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Internal"
|
||||||
|
],
|
||||||
|
"summary": "验证游戏票据",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "票据信息",
|
||||||
|
"name": "ticket",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.VerifyTicketRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/minesweeper.VerifyTicketResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/pay/wechat/notify": {
|
"/pay/wechat/notify": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "接收微信支付结果通知,验证签名并处理订单状态",
|
"description": "接收微信支付结果通知,验证签名并处理订单状态",
|
||||||
@ -8166,6 +8224,9 @@
|
|||||||
"app.drawLogItem": {
|
"app.drawLogItem": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"avatar": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"current_level": {
|
"current_level": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -8187,8 +8248,17 @@
|
|||||||
"reward_id": {
|
"reward_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"reward_image": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"reward_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"user_name": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -9153,6 +9223,65 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"minesweeper.SettleGameRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"match_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"score": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"ticket": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minesweeper.SettleGameResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"reward": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minesweeper.VerifyTicketRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ticket": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minesweeper.VerifyTicketResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"remaining_times": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"model.ActivityDrawEffects": {
|
"model.ActivityDrawEffects": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@ -1475,6 +1475,8 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
app.drawLogItem:
|
app.drawLogItem:
|
||||||
properties:
|
properties:
|
||||||
|
avatar:
|
||||||
|
type: string
|
||||||
current_level:
|
current_level:
|
||||||
type: integer
|
type: integer
|
||||||
id:
|
id:
|
||||||
@ -1489,8 +1491,14 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
reward_id:
|
reward_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
reward_image:
|
||||||
|
type: string
|
||||||
|
reward_name:
|
||||||
|
type: string
|
||||||
user_id:
|
user_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
user_name:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
app.getAppProductDetailResponse:
|
app.getAppProductDetailResponse:
|
||||||
properties:
|
properties:
|
||||||
@ -2118,6 +2126,44 @@ definitions:
|
|||||||
description: 描述信息
|
description: 描述信息
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
minesweeper.SettleGameRequest:
|
||||||
|
properties:
|
||||||
|
match_id:
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: string
|
||||||
|
score:
|
||||||
|
type: integer
|
||||||
|
ticket:
|
||||||
|
type: string
|
||||||
|
user_id:
|
||||||
|
type: string
|
||||||
|
win:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
minesweeper.SettleGameResponse:
|
||||||
|
properties:
|
||||||
|
reward:
|
||||||
|
type: string
|
||||||
|
success:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
minesweeper.VerifyTicketRequest:
|
||||||
|
properties:
|
||||||
|
ticket:
|
||||||
|
type: string
|
||||||
|
user_id:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
minesweeper.VerifyTicketResponse:
|
||||||
|
properties:
|
||||||
|
remaining_times:
|
||||||
|
type: integer
|
||||||
|
user_id:
|
||||||
|
type: string
|
||||||
|
valid:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
model.ActivityDrawEffects:
|
model.ActivityDrawEffects:
|
||||||
properties:
|
properties:
|
||||||
activity_category_id:
|
activity_category_id:
|
||||||
@ -4973,7 +5019,7 @@ paths:
|
|||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 查看指定活动期数的抽奖记录,支持分页
|
description: 查看指定活动期数的抽奖记录,支持等级筛选(默认返回最新的100条,不支持自定义翻页)
|
||||||
parameters:
|
parameters:
|
||||||
- description: 活动ID
|
- description: 活动ID
|
||||||
in: path
|
in: path
|
||||||
@ -4985,17 +5031,9 @@ paths:
|
|||||||
name: issue_id
|
name: issue_id
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: integer
|
||||||
- default: 1
|
- description: 奖品等级过滤
|
||||||
description: 页码
|
|
||||||
in: query
|
in: query
|
||||||
name: page
|
name: level
|
||||||
required: true
|
|
||||||
type: integer
|
|
||||||
- default: 20
|
|
||||||
description: 每页数量,最多100
|
|
||||||
in: query
|
|
||||||
name: page_size
|
|
||||||
required: true
|
|
||||||
type: integer
|
type: integer
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
@ -6550,6 +6588,50 @@ paths:
|
|||||||
summary: WangEditor图片上传
|
summary: WangEditor图片上传
|
||||||
tags:
|
tags:
|
||||||
- Common
|
- Common
|
||||||
|
/internal/game/settle:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 游戏结束后结算并发放奖励
|
||||||
|
parameters:
|
||||||
|
- description: 结算信息
|
||||||
|
in: body
|
||||||
|
name: result
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/minesweeper.SettleGameRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/minesweeper.SettleGameResponse'
|
||||||
|
summary: 结算游戏
|
||||||
|
tags:
|
||||||
|
- Internal
|
||||||
|
/internal/game/verify:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 验证游戏票据是否有效
|
||||||
|
parameters:
|
||||||
|
- description: 票据信息
|
||||||
|
in: body
|
||||||
|
name: ticket
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/minesweeper.VerifyTicketRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/minesweeper.VerifyTicketResponse'
|
||||||
|
summary: 验证游戏票据
|
||||||
|
tags:
|
||||||
|
- Internal
|
||||||
/pay/wechat/notify:
|
/pay/wechat/notify:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -8,22 +9,28 @@ import (
|
|||||||
"bindbox-game/internal/code"
|
"bindbox-game/internal/code"
|
||||||
"bindbox-game/internal/pkg/core"
|
"bindbox-game/internal/pkg/core"
|
||||||
"bindbox-game/internal/pkg/validation"
|
"bindbox-game/internal/pkg/validation"
|
||||||
|
"bindbox-game/internal/repository/mysql/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type listDrawLogsRequest struct {
|
type listDrawLogsRequest struct {
|
||||||
Page int `form:"page"`
|
Page int `form:"page"`
|
||||||
PageSize int `form:"page_size"`
|
PageSize int `form:"page_size"`
|
||||||
|
Level *int32 `form:"level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type drawLogItem struct {
|
type drawLogItem struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
IssueID int64 `json:"issue_id"`
|
UserName string `json:"user_name"`
|
||||||
OrderID int64 `json:"order_id"`
|
Avatar string `json:"avatar"`
|
||||||
RewardID int64 `json:"reward_id"`
|
IssueID int64 `json:"issue_id"`
|
||||||
IsWinner int32 `json:"is_winner"`
|
OrderID int64 `json:"order_id"`
|
||||||
Level int32 `json:"level"`
|
RewardID int64 `json:"reward_id"`
|
||||||
CurrentLevel int32 `json:"current_level"`
|
RewardName string `json:"reward_name"`
|
||||||
|
RewardImage string `json:"reward_image"`
|
||||||
|
IsWinner int32 `json:"is_winner"`
|
||||||
|
Level int32 `json:"level"`
|
||||||
|
CurrentLevel int32 `json:"current_level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type listDrawLogsResponse struct {
|
type listDrawLogsResponse struct {
|
||||||
@ -35,14 +42,13 @@ type listDrawLogsResponse struct {
|
|||||||
|
|
||||||
// ListDrawLogs 抽奖记录列表
|
// ListDrawLogs 抽奖记录列表
|
||||||
// @Summary 抽奖记录列表
|
// @Summary 抽奖记录列表
|
||||||
// @Description 查看指定活动期数的抽奖记录,支持分页
|
// @Description 查看指定活动期数的抽奖记录,支持等级筛选(默认返回最新的100条,不支持自定义翻页)
|
||||||
// @Tags APP端.活动
|
// @Tags APP端.活动
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param activity_id path integer true "活动ID"
|
// @Param activity_id path integer true "活动ID"
|
||||||
// @Param issue_id path integer true "期ID"
|
// @Param issue_id path integer true "期ID"
|
||||||
// @Param page query int true "页码" default(1)
|
// @Param level query int false "奖品等级过滤"
|
||||||
// @Param page_size query int true "每页数量,最多100" default(20)
|
|
||||||
// @Success 200 {object} listDrawLogsResponse
|
// @Success 200 {object} listDrawLogsResponse
|
||||||
// @Failure 400 {object} code.Failure
|
// @Failure 400 {object} code.Failure
|
||||||
// @Router /api/app/activities/{activity_id}/issues/{issue_id}/draw_logs [get]
|
// @Router /api/app/activities/{activity_id}/issues/{issue_id}/draw_logs [get]
|
||||||
@ -59,22 +65,142 @@ func (h *handler) ListDrawLogs() core.HandlerFunc {
|
|||||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递期ID"))
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递期ID"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
items, total, err := h.activity.ListDrawLogs(ctx.RequestContext(), issueID, req.Page, req.PageSize)
|
|
||||||
|
// 强制固定分页:第一页,100条
|
||||||
|
page := 1
|
||||||
|
pageSize := 100
|
||||||
|
|
||||||
|
// 计算5分钟前的时间点
|
||||||
|
fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
|
||||||
|
|
||||||
|
// 考虑到需要过滤掉5分钟内的数据,我们稍微多取一些数据,以确保过滤后能有足够的数据展示
|
||||||
|
// 但为了防止数据量过大,还是做一个硬性限制,比如取前200条
|
||||||
|
fetchSize := 200
|
||||||
|
|
||||||
|
items, _, err := h.activity.ListDrawLogs(ctx.RequestContext(), issueID, 1, fetchSize, req.Level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListDrawLogsError, err.Error()))
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListDrawLogsError, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res.Page = req.Page
|
|
||||||
res.PageSize = req.PageSize
|
// 收集ID用于批量查询
|
||||||
|
var userIDs []int64
|
||||||
|
var rewardIDs []int64
|
||||||
|
userSet := make(map[int64]struct{})
|
||||||
|
rewardSet := make(map[int64]struct{})
|
||||||
|
|
||||||
|
// 过滤并收集ID
|
||||||
|
var filteredItems []*model.ActivityDrawLogs
|
||||||
|
for _, v := range items {
|
||||||
|
// 过滤掉5分钟内的记录
|
||||||
|
if v.CreatedAt.After(fiveMinutesAgo) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果已经收集够了100条,就不再收集了
|
||||||
|
if len(filteredItems) >= pageSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredItems = append(filteredItems, v)
|
||||||
|
|
||||||
|
if v.UserID > 0 {
|
||||||
|
if _, ok := userSet[v.UserID]; !ok {
|
||||||
|
userSet[v.UserID] = struct{}{}
|
||||||
|
userIDs = append(userIDs, v.UserID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.RewardID > 0 {
|
||||||
|
if _, ok := rewardSet[v.RewardID]; !ok {
|
||||||
|
rewardSet[v.RewardID] = struct{}{}
|
||||||
|
rewardIDs = append(rewardIDs, v.RewardID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新items为过滤后的列表
|
||||||
|
items = filteredItems
|
||||||
|
total := int64(len(items)) // 更新total为实际返回数量
|
||||||
|
|
||||||
|
// 批量查询用户信息
|
||||||
|
userNameMap := make(map[int64]string)
|
||||||
|
userAvatarMap := make(map[int64]string)
|
||||||
|
if len(userIDs) > 0 {
|
||||||
|
users, err := h.readDB.Users.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Users.ID.In(userIDs...)).Find()
|
||||||
|
if err == nil {
|
||||||
|
for _, u := range users {
|
||||||
|
userNameMap[u.ID] = u.Nickname
|
||||||
|
userAvatarMap[u.ID] = u.Avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量查询奖品与商品信息
|
||||||
|
rewardNameMap := make(map[int64]string)
|
||||||
|
rewardImageMap := make(map[int64]string)
|
||||||
|
if len(rewardIDs) > 0 {
|
||||||
|
rewards, err := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.ActivityRewardSettings.ID.In(rewardIDs...)).Find()
|
||||||
|
if err == nil {
|
||||||
|
var productIDs []int64
|
||||||
|
productSet := make(map[int64]struct{})
|
||||||
|
rewardProductMap := make(map[int64]int64)
|
||||||
|
|
||||||
|
for _, r := range rewards {
|
||||||
|
rewardNameMap[r.ID] = r.Name
|
||||||
|
if r.ProductID > 0 {
|
||||||
|
if _, ok := productSet[r.ProductID]; !ok {
|
||||||
|
productSet[r.ProductID] = struct{}{}
|
||||||
|
productIDs = append(productIDs, r.ProductID)
|
||||||
|
}
|
||||||
|
rewardProductMap[r.ID] = r.ProductID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(productIDs) > 0 {
|
||||||
|
products, err := h.readDB.Products.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Products.ID.In(productIDs...)).Find()
|
||||||
|
if err == nil {
|
||||||
|
productImageMap := make(map[int64]string)
|
||||||
|
productNameMap := make(map[int64]string)
|
||||||
|
for _, p := range products {
|
||||||
|
first := ""
|
||||||
|
if p.ImagesJSON != "" {
|
||||||
|
var arr []string
|
||||||
|
_ = json.Unmarshal([]byte(p.ImagesJSON), &arr)
|
||||||
|
if len(arr) > 0 {
|
||||||
|
first = arr[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
productImageMap[p.ID] = first
|
||||||
|
productNameMap[p.ID] = p.Name
|
||||||
|
}
|
||||||
|
// 填充奖品图片(如果奖品没有名字,也可以用商品名字兜底,但这里先只做图片)
|
||||||
|
for rid, pid := range rewardProductMap {
|
||||||
|
rewardImageMap[rid] = productImageMap[pid]
|
||||||
|
// 如果配置里的奖品名为空,尝试用商品名
|
||||||
|
if rewardNameMap[rid] == "" {
|
||||||
|
rewardNameMap[rid] = productNameMap[pid]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Page = page
|
||||||
|
res.PageSize = pageSize
|
||||||
res.Total = total
|
res.Total = total
|
||||||
res.List = make([]drawLogItem, len(items))
|
res.List = make([]drawLogItem, len(items))
|
||||||
for i, v := range items {
|
for i, v := range items {
|
||||||
res.List[i] = drawLogItem{
|
res.List[i] = drawLogItem{
|
||||||
ID: v.ID,
|
ID: v.ID,
|
||||||
UserID: v.UserID,
|
UserID: v.UserID,
|
||||||
|
UserName: userNameMap[v.UserID],
|
||||||
|
Avatar: userAvatarMap[v.UserID],
|
||||||
IssueID: v.IssueID,
|
IssueID: v.IssueID,
|
||||||
OrderID: v.OrderID,
|
OrderID: v.OrderID,
|
||||||
RewardID: v.RewardID,
|
RewardID: v.RewardID,
|
||||||
|
RewardName: rewardNameMap[v.RewardID],
|
||||||
|
RewardImage: rewardImageMap[v.RewardID],
|
||||||
IsWinner: v.IsWinner,
|
IsWinner: v.IsWinner,
|
||||||
Level: v.Level,
|
Level: v.Level,
|
||||||
CurrentLevel: v.CurrentLevel,
|
CurrentLevel: v.CurrentLevel,
|
||||||
@ -109,7 +235,7 @@ func (h *handler) ListDrawLogsByLevel() core.HandlerFunc {
|
|||||||
// 这里暂且获取所有(或者一个较大的限制),然后在内存中分组。
|
// 这里暂且获取所有(或者一个较大的限制),然后在内存中分组。
|
||||||
// 如果数据量巨大,需要由 Service 层提供 Group By 查询。
|
// 如果数据量巨大,需要由 Service 层提供 Group By 查询。
|
||||||
// 考虑到单期中奖人数通常有限(除非是大规模活动),先尝试获取列表后分组。
|
// 考虑到单期中奖人数通常有限(除非是大规模活动),先尝试获取列表后分组。
|
||||||
logs, _, err := h.activity.ListDrawLogs(ctx.RequestContext(), issueID, 1, 1000) // 假设最多显示1000条中奖记录
|
logs, _, err := h.activity.ListDrawLogs(ctx.RequestContext(), issueID, 1, 1000, nil) // 假设最多显示1000条中奖记录
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListDrawLogsError, err.Error()))
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListDrawLogsError, err.Error()))
|
||||||
return
|
return
|
||||||
|
|||||||
@ -29,6 +29,15 @@ type listAppCategoriesResponse struct {
|
|||||||
List []appCategoryItem `json:"list"`
|
List []appCategoryItem `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListCategoriesForApp 获取分类列表
|
||||||
|
// @Summary 获取分类列表
|
||||||
|
// @Description 获取APP端商品分类列表
|
||||||
|
// @Tags APP端.基础
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} listAppCategoriesResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Router /api/app/categories [get]
|
||||||
func (h *categoryHandler) ListCategoriesForApp() core.HandlerFunc {
|
func (h *categoryHandler) ListCategoriesForApp() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
q := h.readDB.ProductCategories.WithContext(ctx.RequestContext())
|
q := h.readDB.ProductCategories.WithContext(ctx.RequestContext())
|
||||||
|
|||||||
@ -27,6 +27,14 @@ type listAppNoticesResponse struct {
|
|||||||
List []appNoticeItem `json:"list"`
|
List []appNoticeItem `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListNoticesForApp 获取公告列表
|
||||||
|
// @Summary 获取公告列表
|
||||||
|
// @Description 获取APP首页滚动公告
|
||||||
|
// @Tags APP端.基础
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} listAppNoticesResponse
|
||||||
|
// @Router /api/app/notices [get]
|
||||||
func (h *noticeHandler) ListNoticesForApp() core.HandlerFunc {
|
func (h *noticeHandler) ListNoticesForApp() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
rsp := new(listAppNoticesResponse)
|
rsp := new(listAppNoticesResponse)
|
||||||
|
|||||||
@ -46,6 +46,19 @@ type listStoreItemsResponse struct {
|
|||||||
List []listStoreItem `json:"list"`
|
List []listStoreItem `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListStoreItemsForApp 获取积分商城商品列表
|
||||||
|
// @Summary 获取积分商城商品列表
|
||||||
|
// @Description 分页获取积分商城商品列表,支持按类型筛选(product/item_card/coupon)
|
||||||
|
// @Tags APP端.积分商城
|
||||||
|
// @Accept x-www-form-urlencoded
|
||||||
|
// @Produce json
|
||||||
|
// @Security LoginVerifyToken
|
||||||
|
// @Param kind query string false "商品类型: product(默认), item_card, coupon"
|
||||||
|
// @Param page query int false "页码" default(1)
|
||||||
|
// @Param page_size query int false "每页数量" default(20)
|
||||||
|
// @Success 200 {object} listStoreItemsResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Router /api/app/store/items [get]
|
||||||
func (h *storeHandler) ListStoreItemsForApp() core.HandlerFunc {
|
func (h *storeHandler) ListStoreItemsForApp() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
req := new(listStoreItemsRequest)
|
req := new(listStoreItemsRequest)
|
||||||
|
|||||||
119
internal/api/internal/minesweeper/handler.go
Normal file
119
internal/api/internal/minesweeper/handler.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package minesweeper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bindbox-game/internal/pkg/core"
|
||||||
|
"bindbox-game/internal/repository/mysql"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
db mysql.Repo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(logger *zap.Logger, db mysql.Repo) *Handler {
|
||||||
|
return &Handler{
|
||||||
|
logger: logger,
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// i() 辅助函数
|
||||||
|
func (h *Handler) i() {}
|
||||||
|
|
||||||
|
// VerifyTicket 验证游戏票据
|
||||||
|
// @Summary 验证游戏票据
|
||||||
|
// @Description 验证游戏票据是否有效
|
||||||
|
// @Tags Internal
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param ticket body VerifyTicketRequest true "票据信息"
|
||||||
|
// @Success 200 {object} VerifyTicketResponse
|
||||||
|
// @Router /internal/game/verify [post]
|
||||||
|
func (h *Handler) VerifyTicket() core.HandlerFunc {
|
||||||
|
return func(c core.Context) {
|
||||||
|
req := new(VerifyTicketRequest)
|
||||||
|
if err := c.ShouldBindJSON(req); err != nil {
|
||||||
|
c.AbortWithError(core.Error(
|
||||||
|
400,
|
||||||
|
10001,
|
||||||
|
"参数错误",
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 实际验证逻辑,这里先Mock通过
|
||||||
|
// 实际应该检查Redis中ticket是否存在且对应正确的user_id
|
||||||
|
|
||||||
|
c.Payload(VerifyTicketResponse{
|
||||||
|
Valid: true,
|
||||||
|
UserID: req.UserID,
|
||||||
|
RemainingTimes: 1, // Mock
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettleGame 结算游戏
|
||||||
|
// @Summary 结算游戏
|
||||||
|
// @Description 游戏结束后结算并发放奖励
|
||||||
|
// @Tags Internal
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param result body SettleGameRequest true "结算信息"
|
||||||
|
// @Success 200 {object} SettleGameResponse
|
||||||
|
// @Router /internal/game/settle [post]
|
||||||
|
func (h *Handler) SettleGame() core.HandlerFunc {
|
||||||
|
return func(c core.Context) {
|
||||||
|
req := new(SettleGameRequest)
|
||||||
|
if err := c.ShouldBindJSON(req); err != nil {
|
||||||
|
c.AbortWithError(core.Error(
|
||||||
|
400,
|
||||||
|
10001,
|
||||||
|
"参数错误",
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 实际结算逻辑
|
||||||
|
// 1. 验证 ticket 状态为“进行中”
|
||||||
|
// 2. 如果 Win=true,发放奖励
|
||||||
|
// 3. 标记 ticket 为“已完成”
|
||||||
|
|
||||||
|
h.logger.Info("Game Settled",
|
||||||
|
zap.String("user_id", req.UserID),
|
||||||
|
zap.Bool("win", req.Win),
|
||||||
|
zap.Int("score", req.Score),
|
||||||
|
)
|
||||||
|
|
||||||
|
c.Payload(SettleGameResponse{
|
||||||
|
Success: true,
|
||||||
|
Reward: "100积分", // Mock
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type VerifyTicketRequest struct {
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
Ticket string `json:"ticket"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VerifyTicketResponse struct {
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
RemainingTimes int `json:"remaining_times"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SettleGameRequest struct {
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
Ticket string `json:"ticket"`
|
||||||
|
MatchID string `json:"match_id"`
|
||||||
|
Win bool `json:"win"`
|
||||||
|
Score int `json:"score"`
|
||||||
|
Metadata string `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SettleGameResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Reward string `json:"reward"`
|
||||||
|
}
|
||||||
@ -58,7 +58,7 @@ type listTasksResponse struct {
|
|||||||
// @Param page query int false "页码" default(1)
|
// @Param page query int false "页码" default(1)
|
||||||
// @Param page_size query int false "每页数量" default(20)
|
// @Param page_size query int false "每页数量" default(20)
|
||||||
// @Success 200 {object} listTasksResponse "任务列表"
|
// @Success 200 {object} listTasksResponse "任务列表"
|
||||||
// @Router /app/task_center/tasks [get]
|
// @Router /api/app/task-center/tasks [get]
|
||||||
func (h *handler) ListTasksForApp() core.HandlerFunc {
|
func (h *handler) ListTasksForApp() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
req := new(listTasksRequest)
|
req := new(listTasksRequest)
|
||||||
@ -115,7 +115,7 @@ type taskProgressResponse struct {
|
|||||||
// @Param id path int true "任务ID"
|
// @Param id path int true "任务ID"
|
||||||
// @Param user_id path int true "用户ID"
|
// @Param user_id path int true "用户ID"
|
||||||
// @Success 200 {object} taskProgressResponse "任务进度详情"
|
// @Success 200 {object} taskProgressResponse "任务进度详情"
|
||||||
// @Router /app/task_center/tasks/{id}/progress/{user_id} [get]
|
// @Router /api/app/task-center/tasks/{id}/progress/{user_id} [get]
|
||||||
func (h *handler) GetTaskProgressForApp() core.HandlerFunc {
|
func (h *handler) GetTaskProgressForApp() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
taskID, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
|
taskID, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
|
||||||
@ -150,7 +150,7 @@ type claimTaskRequest struct {
|
|||||||
// @Param user_id path int true "用户ID"
|
// @Param user_id path int true "用户ID"
|
||||||
// @Param request body claimTaskRequest true "领取请求"
|
// @Param request body claimTaskRequest true "领取请求"
|
||||||
// @Success 200 {object} map[string]any "领取成功"
|
// @Success 200 {object} map[string]any "领取成功"
|
||||||
// @Router /app/task_center/tasks/{id}/users/{user_id}/claim [post]
|
// @Router /api/app/task-center/tasks/{id}/claim/{user_id} [post]
|
||||||
func (h *handler) ClaimTaskTierForApp() core.HandlerFunc {
|
func (h *handler) ClaimTaskTierForApp() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
taskID, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
|
taskID, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
|
||||||
|
|||||||
@ -19,6 +19,18 @@ type redeemItemCardResponse struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RedeemPointsToItemCard 积分兑换道具卡
|
||||||
|
// @Summary 积分兑换道具卡
|
||||||
|
// @Description 使用积分兑换指定数量的道具卡
|
||||||
|
// @Tags APP端.用户
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security LoginVerifyToken
|
||||||
|
// @Param user_id path int true "用户ID"
|
||||||
|
// @Param request body redeemItemCardRequest true "兑换请求参数"
|
||||||
|
// @Success 200 {object} redeemItemCardResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Router /api/app/users/{user_id}/points/redeem-item-card [post]
|
||||||
func (h *handler) RedeemPointsToItemCard() core.HandlerFunc {
|
func (h *handler) RedeemPointsToItemCard() core.HandlerFunc {
|
||||||
return func(ctx core.Context) {
|
return func(ctx core.Context) {
|
||||||
req := new(redeemItemCardRequest)
|
req := new(redeemItemCardRequest)
|
||||||
|
|||||||
@ -54,8 +54,17 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, error) {
|
|||||||
userHandler := userapi.New(logger, db)
|
userHandler := userapi.New(logger, db)
|
||||||
commonHandler := commonapi.New(logger, db)
|
commonHandler := commonapi.New(logger, db)
|
||||||
payHandler := payapi.New(logger, db)
|
payHandler := payapi.New(logger, db)
|
||||||
|
// minesweeperHandler := minesweeperapi.New(logger, db)
|
||||||
intc := interceptor.New(logger, db)
|
intc := interceptor.New(logger, db)
|
||||||
|
|
||||||
|
// 内部服务接口路由组 (供 Nakama 调用)
|
||||||
|
// internalRouter := mux.Group("/internal")
|
||||||
|
// {
|
||||||
|
// TODO: 添加IP白名单或Internal-Key验证中间件
|
||||||
|
// internalRouter.POST("/game/verify", minesweeperHandler.VerifyTicket())
|
||||||
|
// internalRouter.POST("/game/settle", minesweeperHandler.SettleGame())
|
||||||
|
// }
|
||||||
|
|
||||||
// 管理端非认证接口路由组
|
// 管理端非认证接口路由组
|
||||||
adminNonAuthApiRouter := mux.Group("/api/admin")
|
adminNonAuthApiRouter := mux.Group("/api/admin")
|
||||||
{
|
{
|
||||||
|
|||||||
@ -67,9 +67,9 @@ type Service interface {
|
|||||||
DeleteIssueReward(ctx context.Context, rewardID int64) error
|
DeleteIssueReward(ctx context.Context, rewardID int64) error
|
||||||
|
|
||||||
// ListDrawLogs 抽奖记录列表
|
// ListDrawLogs 抽奖记录列表
|
||||||
// 参数: issueID 期ID, page/pageSize 分页
|
// 参数: issueID 期ID, page/pageSize 分页, level 等级过滤
|
||||||
// 返回: 抽奖记录集合、总数与错误
|
// 返回: 抽奖记录集合、总数与错误
|
||||||
ListDrawLogs(ctx context.Context, issueID int64, page, pageSize int) (items []*model.ActivityDrawLogs, total int64, err error)
|
ListDrawLogs(ctx context.Context, issueID int64, page, pageSize int, level *int32) (items []*model.ActivityDrawLogs, total int64, err error)
|
||||||
|
|
||||||
// GetCategoryNames 批量查询分类名称
|
// GetCategoryNames 批量查询分类名称
|
||||||
// 参数: ids 分类ID数组
|
// 参数: ids 分类ID数组
|
||||||
|
|||||||
@ -7,10 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ListDrawLogs 查询抽奖记录列表(支持分页)
|
// ListDrawLogs 查询抽奖记录列表(支持分页)
|
||||||
// 参数: issueID 期ID, page/pageSize 分页参数
|
// 参数: issueID 期ID, page/pageSize 分页参数, level 等级过滤(可选)
|
||||||
// 返回: 抽奖记录集合、总数与错误
|
// 返回: 抽奖记录集合、总数与错误
|
||||||
func (s *service) ListDrawLogs(ctx context.Context, issueID int64, page, pageSize int) (items []*model.ActivityDrawLogs, total int64, err error) {
|
func (s *service) ListDrawLogs(ctx context.Context, issueID int64, page, pageSize int, level *int32) (items []*model.ActivityDrawLogs, total int64, err error) {
|
||||||
q := s.readDB.ActivityDrawLogs.WithContext(ctx).ReadDB().Where(s.readDB.ActivityDrawLogs.IssueID.Eq(issueID))
|
q := s.readDB.ActivityDrawLogs.WithContext(ctx).ReadDB().Where(s.readDB.ActivityDrawLogs.IssueID.Eq(issueID))
|
||||||
|
if level != nil {
|
||||||
|
q = q.Where(s.readDB.ActivityDrawLogs.Level.Eq(*level))
|
||||||
|
}
|
||||||
total, err = q.Count()
|
total, err = q.Count()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
|||||||
@ -19,3 +19,6 @@
|
|||||||
{"level":"fatal","time":"2025-12-11 00:56:11","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
{"level":"fatal","time":"2025-12-11 00:56:11","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
||||||
{"level":"fatal","time":"2025-12-11 15:05:14","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
{"level":"fatal","time":"2025-12-11 15:05:14","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
||||||
{"level":"info","time":"2025-12-21 14:34:33","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
{"level":"info","time":"2025-12-21 14:34:33","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||||
|
{"level":"info","time":"2025-12-21 17:43:58","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||||
|
{"level":"info","time":"2025-12-21 17:59:49","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||||
|
{"level":"fatal","time":"2025-12-21 17:59:49","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
||||||
|
|||||||
BIN
web/.DS_Store
vendored
BIN
web/.DS_Store
vendored
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user