3580 lines
173 KiB
JSON
3580 lines
173 KiB
JSON
{
|
||
"info": {
|
||
"name": "黄金矿工 API 场景测试",
|
||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||
"description": "按当前后端代码更新:共 48 个请求(47 POST、1 GET),包含黄金矿工玩家接口、通关、原生/客服支付、奖励授权与保存确认、到期补发、普通/临时期管理及 activityConfig/list。08 公共日程无需账号;01 可单独 Runner;其他组按场景逐条执行,不要运行整个 Collection。详见 gold-miner.README.md。"
|
||
},
|
||
"auth": {
|
||
"type": "noauth"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['baseUrl']);",
|
||
"if (!/^https?:\\/\\//.test(pm.environment.get('baseUrl')) || /[<>]/.test(pm.environment.get('baseUrl'))) stop('请填写实际部署的 baseUrl');",
|
||
"const context=JSON.stringify([pm.environment.get('baseUrl'),pm.environment.get('uid')]);",
|
||
"const previous=pm.environment.get('gmContext');",
|
||
"if (previous && previous !== context) {",
|
||
" pm.environment.unset('gmInfo');",
|
||
" pm.environment.unset('gmActivitySchedule');",
|
||
" pm.environment.unset('expectedListedPeriodId');",
|
||
" pm.environment.unset('periodId');",
|
||
" pm.environment.unset('productId');",
|
||
" pm.environment.unset('priceFen');",
|
||
" pm.environment.unset('firstTaskId');",
|
||
" pm.environment.unset('secondTaskId');",
|
||
" pm.environment.unset('currentMainLevel');",
|
||
" pm.environment.unset('gmWinBefore');",
|
||
" pm.environment.unset('gmWinBody');",
|
||
" pm.environment.unset('gmWinAfter');",
|
||
" pm.environment.unset('legacySessionFrom');",
|
||
" pm.environment.unset('allowCustomerMessage');",
|
||
" pm.environment.unset('outTradeNo');",
|
||
" pm.environment.unset('orderPeriodId');",
|
||
" pm.environment.unset('gmGrant');",
|
||
" pm.environment.unset('grantId');",
|
||
" pm.environment.unset('coinBeforeDelivery');",
|
||
" pm.environment.unset('gmSavedGrantId');",
|
||
" pm.environment.unset('settlementCursor');",
|
||
" pm.environment.unset('expectedStatus');",
|
||
" pm.environment.unset('expectedProgressWins');",
|
||
" pm.environment.unset('claimPeriodId');",
|
||
" pm.environment.unset('claimTaskId');",
|
||
" pm.environment.unset('coinAfterDelivery');",
|
||
" pm.environment.unset('settlementId');",
|
||
" pm.environment.unset('expectedTargetPeriodId');",
|
||
" pm.environment.unset('mainLevelAfterWin');",
|
||
" pm.environment.unset('endlessSequence');",
|
||
" pm.environment.unset('expiredPeriodId');",
|
||
" pm.environment.unset('openid');",
|
||
" pm.environment.set('gmContext',context);",
|
||
" stop('已切换应用/账号,旧测试上下文已清理。请从第 01 组重新查询');",
|
||
"}",
|
||
"pm.environment.set('gmContext',context);"
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"item": [
|
||
{
|
||
"name": "01 基础查询与鉴权(可单独 Runner)",
|
||
"description": "本组不提交通关或发货。info 可能初始化玩家期记录并激活已有权益;补发查询本身不执行结算。支持普通周四周期和 goldMiner:test: 临时期,expectedStatus 留空时只校验结构。",
|
||
"item": [
|
||
{
|
||
"name": "01 活动信息并保存当期变量",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"info\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:action=info、uid、token。返回 serverTime/status/periodId/tasks;有效且已达资格时另含 startsAt/endsAt/configVersion/priceFen/productId/progressWins/maxTarget。status 为 unavailable/locked/purchasable/purchase_disabled/unlocked。任务字段:taskId/targetWins/itemsSnapshot/claimStatus/completed/progress;claimStatus 为 locked/claimable/issuing/claimed。测试期时间可为任意窗口,不能按固定四天推算。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"pm.test('活动状态结构', () => {",
|
||
" const d = r.data;",
|
||
" pm.expect(['unavailable','locked','purchasable','purchase_disabled','unlocked'].includes(d.status)).to.eql(true);",
|
||
" pm.expect(Number.isSafeInteger(d.serverTime)).to.eql(true);",
|
||
" for (const key of ['availability','qualified','entitlement','purchasable','currency','nextStartsAt','nextPeriodId','claimedThrough']) pm.expect(Object.prototype.hasOwnProperty.call(d,key)).to.eql(false);",
|
||
" if (pm.environment.get('expectedStatus')) pm.expect(d.status).to.eql(pm.environment.get('expectedStatus'));",
|
||
" if (['unavailable','locked'].includes(d.status)) { pm.expect(d.tasks).to.eql([]); return; }",
|
||
" pm.expect(Number.isSafeInteger(d.startsAt) && Number.isSafeInteger(d.endsAt) && d.startsAt < d.endsAt).to.eql(true);",
|
||
" pm.expect(d.serverTime >= d.startsAt && d.serverTime < d.endsAt).to.eql(true);",
|
||
" if (d.periodId.startsWith('goldMiner:test:')) {",
|
||
" pm.expect(/^goldMiner:test:[A-Za-z0-9_-]{1,60}$/.test(d.periodId)).to.eql(true);",
|
||
" } else {",
|
||
" pm.expect(/^goldMiner:\\d{4}-\\d{2}-\\d{2}$/.test(d.periodId)).to.eql(true);",
|
||
" pm.expect(d.endsAt - d.startsAt).to.eql(4 * 86400000);",
|
||
" pm.expect(new Date(d.startsAt + 8 * 3600000).getUTCDay()).to.eql(4);",
|
||
" pm.expect(new Date(d.startsAt + 8 * 3600000).getUTCHours()).to.eql(0);",
|
||
" }",
|
||
" pm.expect(Number.isSafeInteger(d.progressWins) && d.progressWins >= 0).to.eql(true);",
|
||
" pm.expect(d.tasks.length > 0).to.eql(true);",
|
||
" pm.expect(d.maxTarget).to.eql(d.tasks[d.tasks.length - 1].targetWins);",
|
||
" let lastTarget = 0;",
|
||
" d.tasks.forEach((t, i) => {",
|
||
" pm.expect(Object.keys(t).sort()).to.eql(['taskId','targetWins','itemsSnapshot','claimStatus','completed','progress'].sort());",
|
||
" pm.expect(t.targetWins > lastTarget).to.eql(true); lastTarget = t.targetWins;",
|
||
" pm.expect(t.progress).to.eql(Math.min(d.progressWins, t.targetWins));",
|
||
" pm.expect(t.completed).to.eql(d.progressWins >= t.targetWins);",
|
||
" if (d.status !== 'unlocked') pm.expect(t.claimStatus).to.eql(t.completed ? 'pending_unlock' : 'locked');",
|
||
" else if (!t.completed) pm.expect(t.claimStatus).to.eql('locked');",
|
||
" else pm.expect(['claimable','issuing','claimed'].includes(t.claimStatus)).to.eql(true);",
|
||
" });",
|
||
" if (String(pm.environment.get('expectedProgressWins') ?? '') !== '') pm.expect(d.progressWins).to.eql(Number(pm.environment.get('expectedProgressWins')));",
|
||
"});",
|
||
"if (r.code === 1) {",
|
||
" pm.environment.set('gmInfo', JSON.stringify(r.data));",
|
||
" if (['purchasable','purchase_disabled','unlocked'].includes(r.data.status)) {",
|
||
" for (const key of ['periodId','productId','priceFen']) pm.environment.set(key, r.data[key]);",
|
||
" pm.environment.set('firstTaskId', r.data.tasks[0].taskId);",
|
||
" pm.environment.set('secondTaskId', r.data.tasks[1]?.taskId || '');",
|
||
" } else {",
|
||
" for (const key of ['periodId','productId','priceFen','firstTaskId','secondTaskId']) pm.environment.unset(key);",
|
||
" if (r.data.status === 'locked') pm.environment.set('periodId',r.data.periodId);",
|
||
" }",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 读取主线存档",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"read\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userLevel",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userLevel"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"if (r.code === 1) pm.environment.set('currentMainLevel', r.data.levelAmount);"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 缺少 token",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"info\",\n \"uid\": \"{{uid}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:UNAUTHORIZED', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('UNAUTHORIZED'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 不支持的 IAA 账号域",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"info\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"gameName\": \"iaa\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:UNAUTHORIZED', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('UNAUTHORIZED'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "05 非法 action",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"invalid_action\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:INVALID_ACTION', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('INVALID_ACTION'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "06 非法分页游标",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"settlements\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"afterId\": 42\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token,afterId 可选分页游标;前端不传 limit,后端固定每页扫描 20 期。返回 status=pending_delivery/settling/no_pending_rewards、items、nextCursor;每项含 settlementId/periodId/rewards,奖励含 taskId/grantId/items。可发奖励优先返回,不受其他期结算阻塞;no_pending_rewards 表示该玩家当前环境下所有已结束期均无待发或待结算记录。\n\n"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:INVALID_INPUT', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('INVALID_INPUT'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "07 非法期 ID",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"invalid-period\",\n \"taskId\": \"task_1\",\n \"requestId\": \"invalid-period-test\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:INVALID_PERIOD', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('INVALID_PERIOD'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 通关进度(按场景手动)",
|
||
"description": "先读活动和主线存档。每次新胜利前重新读取活动信息。新胜利请求生成 eventId,重试请求复用完整原始载荷;不要以新胜利请求代替重试。",
|
||
"item": [
|
||
{
|
||
"name": "01 主线新胜利",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmWinBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userLevel",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userLevel"
|
||
]
|
||
},
|
||
"description": "mainLevelAfterWin=currentMainLevel+1;默认预期 counted。资格关需设 qualification、刚读取存档为 40,且活动已配置开放。封顶场景设 capped。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([]);",
|
||
"",
|
||
"need(['uid','token','periodId','currentMainLevel','gmInfo']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.periodId !== pm.environment.get('periodId')) stop('请重新查询本期活动信息');",
|
||
"const expected = pm.environment.get('expectedProgressResult');",
|
||
"if (!['counted','qualification','capped'].includes(expected)) stop('expectedProgressResult 仅支持 counted/qualification/capped');",
|
||
"const level = integer('mainLevelAfterWin', 1);",
|
||
"const oldLevel = integer('currentMainLevel', 0);",
|
||
"const mode = 'main';",
|
||
"if (mode === 'main' && level !== oldLevel + 1) stop('主线只测试顺序过关:mainLevelAfterWin 必须为刚读取的 currentMainLevel + 1');",
|
||
"if (mode === 'endless' && level !== oldLevel) stop('无尽测试须保留当前主线存档');",
|
||
"if (expected === 'qualification' && (mode !== 'main' || level !== 41)) stop('资格关用例要求主线第 41 关');",
|
||
"if (expected !== 'qualification' && !['purchasable','purchase_disabled','unlocked'].includes(info.status)) stop('请先准备有资格且处于活动期的账号');",
|
||
"const input = {periodId: pm.environment.get('periodId'), eventId: 'win-' + pm.variables.replaceIn('{{$guid}}'), outcome:'win', mode};",
|
||
"if (mode === 'main') input.clearedMainLevel = level;",
|
||
"else input.endlessSequence = integer('endlessSequence', 1);",
|
||
"const data = {action:'save', uid:pm.environment.get('uid'), token:pm.environment.get('token'), levelAmount:level, goldMiner:input};",
|
||
"if (mode === 'endless') data.isWuXian = 'true';",
|
||
"pm.environment.set('gmWinBefore', info.progressWins || 0);",
|
||
"pm.environment.set('gmWinBody', JSON.stringify(data));",
|
||
"pm.environment.unset('gmWinAfter');"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"const d = r.data?.goldMiner;",
|
||
"pm.test('活动子结果与计数', () => {",
|
||
" pm.expect(d.code).to.eql(1);",
|
||
" const before = Number(pm.environment.get('gmWinBefore'));",
|
||
" const expected = pm.environment.get('expectedProgressResult');",
|
||
" pm.expect(d.activityCounted).to.eql(expected === 'counted');",
|
||
" pm.expect(d.progressWins).to.eql(before + (expected === 'counted' ? 1 : 0));",
|
||
" if (expected === 'qualification') pm.expect(d.reason).to.eql('qualification_level');",
|
||
" else pm.expect(d.duplicate).to.eql(false);",
|
||
" if (expected === 'capped') pm.expect(d.progressWins).to.eql(JSON.parse(pm.environment.get('gmInfo')).maxTarget);",
|
||
"});",
|
||
"if (r.code === 1 && d?.code === 1) {",
|
||
" pm.environment.set('gmWinAfter', d.progressWins);",
|
||
" pm.environment.set('currentMainLevel', r.data.levelAmount);",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 无尽新胜利",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmWinBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userLevel",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userLevel"
|
||
]
|
||
},
|
||
"description": "mainLevelAfterWin=currentMainLevel;endlessSequence 使用此账号本期从未上报的唯一序号。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([]);",
|
||
"",
|
||
"need(['uid','token','periodId','currentMainLevel','gmInfo']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.periodId !== pm.environment.get('periodId')) stop('请重新查询本期活动信息');",
|
||
"const expected = pm.environment.get('expectedProgressResult');",
|
||
"if (!['counted','qualification','capped'].includes(expected)) stop('expectedProgressResult 仅支持 counted/qualification/capped');",
|
||
"const level = integer('mainLevelAfterWin', 1);",
|
||
"const oldLevel = integer('currentMainLevel', 0);",
|
||
"const mode = 'endless';",
|
||
"if (mode === 'main' && level !== oldLevel + 1) stop('主线只测试顺序过关:mainLevelAfterWin 必须为刚读取的 currentMainLevel + 1');",
|
||
"if (mode === 'endless' && level !== oldLevel) stop('无尽测试须保留当前主线存档');",
|
||
"if (expected === 'qualification' && (mode !== 'main' || level !== 41)) stop('资格关用例要求主线第 41 关');",
|
||
"if (expected !== 'qualification' && !['purchasable','purchase_disabled','unlocked'].includes(info.status)) stop('请先准备有资格且处于活动期的账号');",
|
||
"const input = {periodId: pm.environment.get('periodId'), eventId: 'win-' + pm.variables.replaceIn('{{$guid}}'), outcome:'win', mode};",
|
||
"if (mode === 'main') input.clearedMainLevel = level;",
|
||
"else input.endlessSequence = integer('endlessSequence', 1);",
|
||
"const data = {action:'save', uid:pm.environment.get('uid'), token:pm.environment.get('token'), levelAmount:level, goldMiner:input};",
|
||
"if (mode === 'endless') data.isWuXian = 'true';",
|
||
"pm.environment.set('gmWinBefore', info.progressWins || 0);",
|
||
"pm.environment.set('gmWinBody', JSON.stringify(data));",
|
||
"pm.environment.unset('gmWinAfter');"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"const d = r.data?.goldMiner;",
|
||
"pm.test('活动子结果与计数', () => {",
|
||
" pm.expect(d.code).to.eql(1);",
|
||
" const before = Number(pm.environment.get('gmWinBefore'));",
|
||
" const expected = pm.environment.get('expectedProgressResult');",
|
||
" pm.expect(d.activityCounted).to.eql(expected === 'counted');",
|
||
" pm.expect(d.progressWins).to.eql(before + (expected === 'counted' ? 1 : 0));",
|
||
" if (expected === 'qualification') pm.expect(d.reason).to.eql('qualification_level');",
|
||
" else pm.expect(d.duplicate).to.eql(false);",
|
||
" if (expected === 'capped') pm.expect(d.progressWins).to.eql(JSON.parse(pm.environment.get('gmInfo')).maxTarget);",
|
||
"});",
|
||
"if (r.code === 1 && d?.code === 1) {",
|
||
" pm.environment.set('gmWinAfter', d.progressWins);",
|
||
" pm.environment.set('currentMainLevel', r.data.levelAmount);",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 原事件重试不重复累计",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmRetryBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userLevel",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userLevel"
|
||
]
|
||
},
|
||
"description": "仅紧接已计数的胜利;资格关和封顶未记录去重条目,不适用此用例。无尽重试会再次影响旧 addLevel 统计,只用独立测试账号。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"need(['gmWinBody','gmWinAfter']);",
|
||
"const saved = JSON.parse(pm.environment.get('gmWinBody'));",
|
||
"saved.token = pm.environment.get('token');",
|
||
"pm.variables.set('gmRetryBody', JSON.stringify(saved));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('同一次胜利只计一次', () => { const d = r.data.goldMiner; pm.expect(d.code).to.eql(1); pm.expect(d.duplicate).to.eql(true); pm.expect(d.activityCounted).to.eql(false); pm.expect(d.progressWins).to.eql(Number(pm.environment.get('gmWinAfter'))); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 同一事件 ID 改变通关载荷",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmConflictBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userLevel",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userLevel"
|
||
]
|
||
},
|
||
"description": "仅对已计数原事件。活动拒绝发生在普通存档之后;本请求保留原 levelAmount,避免推进主线存档。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"need(['gmWinBody','gmWinAfter']);",
|
||
"const saved = JSON.parse(pm.environment.get('gmWinBody'));",
|
||
"saved.token = pm.environment.get('token');",
|
||
"pm.variables.set('gmRetryBody', JSON.stringify(saved));",
|
||
"if (saved.goldMiner.mode === 'main') saved.goldMiner.clearedMainLevel += 1; else saved.goldMiner.endlessSequence += 1;",
|
||
"pm.variables.set('gmConflictBody', JSON.stringify(saved));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('活动子结果拒绝冲突', () => { pm.expect(r.data.goldMiner.code).to.eql(0); pm.expect(r.data.goldMiner.errorCode).to.eql('EVENT_PAYLOAD_CONFLICT'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "05 结束后提交新的胜利",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmExpiredBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userLevel",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userLevel"
|
||
]
|
||
},
|
||
"description": "expiredPeriodId 为已结束的普通期或 goldMiner:test: 临时期;endlessSequence 为该旧期未记录序号。普通存档仍会执行,单独检查 data.goldMiner.errorCode=PERIOD_ENDED。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([]);",
|
||
"need(['uid','token','expiredPeriodId','currentMainLevel']);",
|
||
"const data = {action:'save',uid:pm.environment.get('uid'),token:pm.environment.get('token'),levelAmount:integer('currentMainLevel',1),isWuXian:'true',goldMiner:{periodId:pm.environment.get('expiredPeriodId'),eventId:'late-'+pm.variables.replaceIn('{{$guid}}'),outcome:'win',mode:'endless',endlessSequence:integer('endlessSequence',1)}};",
|
||
"pm.variables.set('gmExpiredBody',JSON.stringify(data));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('不补记过期进度', () => { pm.expect(r.data.goldMiner.code).to.eql(0); pm.expect(r.data.goldMiner.errorCode).to.eql('PERIOD_ENDED'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 原生支付与查单(手动)",
|
||
"description": "Android/iOS 创建入口按平台二选一;同一期另一平台也应复用原订单。签名请求本身不扣款;真实支付在客户端进行。",
|
||
"item": [
|
||
{
|
||
"name": "01 Android 创建订单(含篡改价格参数)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"itemid\": \"{{productId}}\",\n \"createRequestId\": \"{{createRequestId}}\",\n \"itemPrice\": 1,\n \"itemCount\": 999\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/orderPaySig",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"orderPaySig"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"need(['gmInfo','productId','priceFen']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.status !== 'purchasable' || info.productId !== pm.environment.get('productId')) stop('请先查询可购买的本期活动');",
|
||
"pm.variables.set('createRequestId','buy-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"pm.test('商品及金额取服务端快照', () => {",
|
||
" const sign = JSON.parse(r.data.signData);",
|
||
" pm.expect(sign.productId).to.eql(pm.environment.get('productId'));",
|
||
" pm.expect(sign.buyQuantity).to.eql(1);",
|
||
" pm.expect(sign.goodsPrice).to.eql(Number(pm.environment.get('priceFen')));",
|
||
" pm.expect(sign.outTradeNo).to.eql(r.data.outTradeNo);",
|
||
" pm.expect(typeof r.data.paySig).to.eql('string');",
|
||
" pm.expect(typeof r.data.signature).to.eql('string');",
|
||
"});",
|
||
"if (r.code === 1) { pm.environment.set('outTradeNo',r.data.outTradeNo); pm.environment.set('orderPeriodId',JSON.parse(pm.environment.get('gmInfo')).periodId); }"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 原生 iOS 创建订单(含篡改价格参数)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"itemid\": \"{{productId}}\",\n \"createRequestId\": \"{{createRequestId}}\",\n \"itemPrice\": 1,\n \"itemCount\": 999\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/iosorderPaySig",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"iosorderPaySig"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"need(['gmInfo','productId','priceFen']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.status !== 'purchasable' || info.productId !== pm.environment.get('productId')) stop('请先查询可购买的本期活动');",
|
||
"pm.variables.set('createRequestId','buy-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"pm.test('商品及金额取服务端快照', () => {",
|
||
" const sign = JSON.parse(r.data.signData);",
|
||
" pm.expect(sign.productId).to.eql(pm.environment.get('productId'));",
|
||
" pm.expect(sign.buyQuantity).to.eql(1);",
|
||
" pm.expect(sign.goodsPrice).to.eql(Number(pm.environment.get('priceFen')));",
|
||
" pm.expect(sign.outTradeNo).to.eql(r.data.outTradeNo);",
|
||
" pm.expect(typeof r.data.paySig).to.eql('string');",
|
||
" pm.expect(typeof r.data.signature).to.eql('string');",
|
||
"});",
|
||
"if (r.code === 1) { pm.environment.set('outTradeNo',r.data.outTradeNo); pm.environment.set('orderPeriodId',JSON.parse(pm.environment.get('gmInfo')).periodId); }"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 换 requestId 仍复用同一期订单",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"itemid\": \"{{productId}}\",\n \"createRequestId\": \"{{createRequestId}}\",\n \"itemPrice\": 1,\n \"itemCount\": 999\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/orderPaySig",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"orderPaySig"
|
||
]
|
||
},
|
||
"description": "仅紧接同一期下单,支付前执行;outTradeNo 必须来自本期首次创建。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"outTradeNo\", \"uid\", \"token\"]);",
|
||
"need(['gmInfo','productId','priceFen']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.status !== 'purchasable' || info.productId !== pm.environment.get('productId')) stop('请先查询可购买的本期活动');",
|
||
"pm.variables.set('createRequestId','buy-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('复用原订单', () => pm.expect(r.data.outTradeNo).to.eql(pm.environment.get('outTradeNo')));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "查单/通用领取:wx/getPayInfo",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"outTradeNo\": \"{{outTradeNo}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/getPayInfo",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"getPayInfo"
|
||
]
|
||
},
|
||
"description": "默认 pending;客户端真实支付并收到可信通知后设 paid,明确填写 expectedFulfillmentRoute 和 expectedTargetPeriodId。不会由此请求伪造支付。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"outTradeNo\", \"uid\", \"token\"]);",
|
||
"if (!['pending','paid'].includes(pm.environment.get('expectedPaymentState'))) stop('expectedPaymentState 只能为 pending/paid');",
|
||
"if (pm.environment.get('expectedPaymentState') === 'paid') need(['expectedFulfillmentRoute','expectedTargetPeriodId']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"",
|
||
"const expected = pm.environment.get('expectedPaymentState');",
|
||
"pm.test('查单匹配指定状态', () => {",
|
||
" if (expected === 'pending') { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('PAYMENT_PENDING'); return; }",
|
||
" pm.expect(r.code).to.eql(1); pm.expect(r.data.pay_state).to.eql(2);",
|
||
" pm.expect(r.data.rewardDelivery).to.eql('goldMiner.claim');",
|
||
" pm.expect(r.data.goldMiner.fulfillmentStatus).to.eql('fulfilled');",
|
||
" pm.expect(r.data.goldMiner.fulfillmentRoute).to.eql(pm.environment.get('expectedFulfillmentRoute'));",
|
||
" pm.expect(r.data.goldMiner.targetPeriodId).to.eql(pm.environment.get('expectedTargetPeriodId'));",
|
||
"});"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "查单/通用领取:wx/iosgetPayInfo",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"outTradeNo\": \"{{outTradeNo}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/iosgetPayInfo",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"iosgetPayInfo"
|
||
]
|
||
},
|
||
"description": "默认 pending;客户端真实支付并收到可信通知后设 paid,明确填写 expectedFulfillmentRoute 和 expectedTargetPeriodId。不会由此请求伪造支付。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"outTradeNo\", \"uid\", \"token\"]);",
|
||
"if (!['pending','paid'].includes(pm.environment.get('expectedPaymentState'))) stop('expectedPaymentState 只能为 pending/paid');",
|
||
"if (pm.environment.get('expectedPaymentState') === 'paid') need(['expectedFulfillmentRoute','expectedTargetPeriodId']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"",
|
||
"const expected = pm.environment.get('expectedPaymentState');",
|
||
"pm.test('查单匹配指定状态', () => {",
|
||
" if (expected === 'pending') { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('PAYMENT_PENDING'); return; }",
|
||
" pm.expect(r.code).to.eql(1); pm.expect(r.data.pay_state).to.eql(2);",
|
||
" pm.expect(r.data.rewardDelivery).to.eql('goldMiner.claim');",
|
||
" pm.expect(r.data.goldMiner.fulfillmentStatus).to.eql('fulfilled');",
|
||
" pm.expect(r.data.goldMiner.fulfillmentRoute).to.eql(pm.environment.get('expectedFulfillmentRoute'));",
|
||
" pm.expect(r.data.goldMiner.targetPeriodId).to.eql(pm.environment.get('expectedTargetPeriodId'));",
|
||
"});"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "查单/通用领取:wx/getOrderReward",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"outTradeNo\": \"{{outTradeNo}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/getOrderReward",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"getOrderReward"
|
||
]
|
||
},
|
||
"description": "默认 pending;客户端真实支付并收到可信通知后设 paid,明确填写 expectedFulfillmentRoute 和 expectedTargetPeriodId。不会由此请求伪造支付。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"outTradeNo\", \"uid\", \"token\"]);",
|
||
"if (!['pending','paid'].includes(pm.environment.get('expectedPaymentState'))) stop('expectedPaymentState 只能为 pending/paid');",
|
||
"if (pm.environment.get('expectedPaymentState') === 'paid') need(['expectedFulfillmentRoute','expectedTargetPeriodId']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"",
|
||
"const expected = pm.environment.get('expectedPaymentState');",
|
||
"pm.test('查单匹配指定状态', () => {",
|
||
" if (expected === 'pending') { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('PAYMENT_PENDING'); return; }",
|
||
" pm.expect(r.code).to.eql(1); pm.expect(r.data.pay_state).to.eql(2);",
|
||
" pm.expect(r.data.rewardDelivery).to.eql('goldMiner.claim');",
|
||
" pm.expect(r.data.goldMiner.fulfillmentStatus).to.eql('fulfilled');",
|
||
" pm.expect(r.data.goldMiner.fulfillmentRoute).to.eql(pm.environment.get('expectedFulfillmentRoute'));",
|
||
" pm.expect(r.data.goldMiner.targetPeriodId).to.eql(pm.environment.get('expectedTargetPeriodId'));",
|
||
"});"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "无效签名通知不得解锁",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmCallbackBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/payCallBack",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"payCallBack"
|
||
]
|
||
},
|
||
"description": "用尚未支付的测试订单,openid 须为所属账号。发送后以 pending 查单确认仍未支付;正向验签必须用支付平台通知。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([]);",
|
||
"need(['outTradeNo','productId','priceFen','openid']);",
|
||
"const payload = JSON.stringify({OutTradeNo:pm.environment.get('outTradeNo'),OpenId:pm.environment.get('openid'),Env:0,GoodsInfo:{ProductId:pm.environment.get('productId'),Quantity:1,OrigPrice:integer('priceFen',1)}});",
|
||
"pm.variables.set('gmCallbackBody',JSON.stringify({Event:'minigame_game_pay_goods_deliver_notify',MiniGame:{Payload:payload,PayEventSig:'0'.repeat(64),IsMock:false}}));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('通知被拒绝', () => { pm.expect(typeof r.ErrCode).to.eql('number'); pm.expect(r.ErrCode === 0).to.eql(false); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 任意档位领取与客户端保存(逐条手动)",
|
||
"description": "领取目标单独使用 claimPeriodId/claimTaskId,info 不会改写它们。领过的任务不得重新加币;确认幂等用同一 grantId。",
|
||
"item": [
|
||
{
|
||
"name": "01 获取奖励授权",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"requestId\": \"{{claimRequestId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n普通领奖仅活动有效期内调用;历史补发使用 05 文件夹清单授权和发货确认。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"claimPeriodId\", \"claimTaskId\", \"uid\", \"token\"]);",
|
||
"pm.variables.set('claimRequestId','claim-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"pm.test('奖励授权结构', () => {",
|
||
" pm.expect(r.data.taskId).to.eql(pm.environment.get('claimTaskId'));",
|
||
" pm.expect(typeof r.data.grantId).to.eql('string');",
|
||
" pm.expect(r.data.items.length > 0).to.eql(true);",
|
||
" pm.expect(['issuing','claimed'].includes(r.data.claimStatus)).to.eql(true);",
|
||
" pm.expect(r.data.requiresClientDelivery).to.eql(r.data.claimStatus !== 'claimed');",
|
||
"});",
|
||
"if (r.code === 1) {",
|
||
" const old = pm.environment.get('gmGrant') ? JSON.parse(pm.environment.get('gmGrant')) : null;",
|
||
" const current = {...r.data,periodId:pm.environment.get('claimPeriodId'),taskId:pm.environment.get('claimTaskId')};",
|
||
" if (!old || old.grantId !== current.grantId) { pm.environment.unset('gmSavedGrantId'); pm.environment.unset('coinAfterDelivery'); }",
|
||
" pm.environment.set('gmGrant',JSON.stringify(current));",
|
||
" pm.environment.set('grantId',current.grantId);",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 重复领取返回原凭证",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"requestId\": \"{{claimRequestId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"claimPeriodId\", \"claimTaskId\", \"uid\", \"token\"]);",
|
||
"",
|
||
"need(['gmGrant','grantId','claimPeriodId','claimTaskId']);",
|
||
"const grant = JSON.parse(pm.environment.get('gmGrant'));",
|
||
"if (grant.grantId !== pm.environment.get('grantId') || grant.periodId !== pm.environment.get('claimPeriodId') || grant.taskId !== pm.environment.get('claimTaskId')) stop('凭证与所选期/任务不一致,请先领取所选任务');",
|
||
"pm.variables.set('claimRequestId','claim-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('重复领取无新奖励凭证', () => { const prior = JSON.parse(pm.environment.get('gmGrant')); pm.expect(r.data.grantId).to.eql(prior.grantId); pm.expect(r.data.items).to.eql(prior.items); pm.expect(r.data.claimStatus).to.eql(prior.claimStatus); pm.expect(r.data.requiresClientDelivery).to.eql(prior.claimStatus !== 'claimed'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 读取金币总余额",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"read\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userCoin",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userCoin"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('余额为非负数', () => pm.expect(Number.isFinite(r.data.coinAmount) && r.data.coinAmount >= 0).to.eql(true));",
|
||
"if (r.code === 1) pm.environment.set('coinBeforeDelivery',r.data.coinAmount);"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 模拟客户端发货后保存总余额",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"save\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"coinAmount\": \"{{coinAfterDelivery}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/userCoin",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"userCoin"
|
||
]
|
||
},
|
||
"description": "仅独立测试账号、无其他设备写入时使用。领取后读余额,再手填 coinAfterDelivery;保存的是总余额。超时后先读服务端并核对原余额及凭证,不能重新相加。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"",
|
||
"need(['gmGrant','grantId','claimPeriodId','claimTaskId']);",
|
||
"const grant = JSON.parse(pm.environment.get('gmGrant'));",
|
||
"if (grant.grantId !== pm.environment.get('grantId') || grant.periodId !== pm.environment.get('claimPeriodId') || grant.taskId !== pm.environment.get('claimTaskId')) stop('凭证与所选期/任务不一致,请先领取所选任务');",
|
||
"",
|
||
"if (grant.claimStatus !== 'issuing' || !grant.requiresClientDelivery) stop('该凭证已完成,不得再次加币');",
|
||
"if (pm.environment.get('gmSavedGrantId') === grant.grantId) stop('此凭证已保存成功,只需确认领取');",
|
||
"const before = integer('coinBeforeDelivery');",
|
||
"const after = integer('coinAfterDelivery');",
|
||
"if (!grant.items.every(i => i.type === 'coin')) stop('当前测试仅支持金币发货');",
|
||
"const amount = grant.items.reduce((sum,i) => sum+i.count,0);",
|
||
"if (after !== before + amount) stop('coinAfterDelivery 应为刚读取的总余额加本次奖励;请人工填写');"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('保存指定总余额', () => pm.expect(r.data.coinAmount).to.eql(Number(pm.environment.get('coinAfterDelivery'))));",
|
||
"if (r.code === 1 && r.data.coinAmount === Number(pm.environment.get('coinAfterDelivery'))) pm.environment.set('gmSavedGrantId',pm.environment.get('grantId'));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "05 保存后确认领取(可原请求重试)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"confirm_delivery\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"grantId\": \"{{grantId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/grantId。返回 grantId/claimStatus/claimedThrough。仅在客户端已保存奖励后确认,重复确认幂等。\n\n完成后可重复确认、重复授权,再查询活动验证当前档 claimed 和下一档状态。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"",
|
||
"need(['gmGrant','grantId','claimPeriodId','claimTaskId']);",
|
||
"const grant = JSON.parse(pm.environment.get('gmGrant'));",
|
||
"if (grant.grantId !== pm.environment.get('grantId') || grant.periodId !== pm.environment.get('claimPeriodId') || grant.taskId !== pm.environment.get('claimTaskId')) stop('凭证与所选期/任务不一致,请先领取所选任务');",
|
||
"",
|
||
"if (pm.environment.get('gmSavedGrantId') !== grant.grantId) stop('请先完成本凭证的金币保存');"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"pm.test('确认同一凭证', () => { pm.expect(r.data.grantId).to.eql(pm.environment.get('grantId')); pm.expect(r.data.claimStatus).to.eql('claimed'); pm.expect(Number.isSafeInteger(r.data.claimedThrough) && r.data.claimedThrough >= 0).to.eql(true); });",
|
||
"if (r.code === 1) { const grant = JSON.parse(pm.environment.get('gmGrant')); grant.claimStatus='claimed'; grant.requiresClientDelivery=false; grant.claimedThrough=r.data.claimedThrough; pm.environment.set('gmGrant',JSON.stringify(grant)); }"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "06 未付费不能领",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"requestId\": \"{{claimRequestId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n未付费且任务尚未授权的已有玩家期记录。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"claimPeriodId\", \"claimTaskId\", \"uid\", \"token\"]);",
|
||
"pm.variables.set('claimRequestId','claim-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:NOT_PAID', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('NOT_PAID'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "07 未达标不能领",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"requestId\": \"{{claimRequestId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n已付费,所选任务未达标。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"claimPeriodId\", \"claimTaskId\", \"uid\", \"token\"]);",
|
||
"pm.variables.set('claimRequestId','claim-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:TARGET_NOT_REACHED', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('TARGET_NOT_REACHED'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "08 跳过前一档领取已达标任务",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"requestId\": \"{{claimRequestId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n已付费,所选后续任务已达标,但前一档未确认保存。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"claimPeriodId\", \"claimTaskId\", \"uid\", \"token\"]);",
|
||
"pm.variables.set('claimRequestId','claim-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"",
|
||
"pm.test('奖励授权结构', () => {",
|
||
" pm.expect(r.data.taskId).to.eql(pm.environment.get('claimTaskId'));",
|
||
" pm.expect(typeof r.data.grantId).to.eql('string');",
|
||
" pm.expect(r.data.items.length > 0).to.eql(true);",
|
||
" pm.expect(['issuing','claimed'].includes(r.data.claimStatus)).to.eql(true);",
|
||
" pm.expect(r.data.requiresClientDelivery).to.eql(r.data.claimStatus !== 'claimed');",
|
||
"});",
|
||
"if (r.code === 1) {",
|
||
" const old = pm.environment.get('gmGrant') ? JSON.parse(pm.environment.get('gmGrant')) : null;",
|
||
" const current = {...r.data,periodId:pm.environment.get('claimPeriodId'),taskId:pm.environment.get('claimTaskId')};",
|
||
" if (!old || old.grantId !== current.grantId) { pm.environment.unset('gmSavedGrantId'); pm.environment.unset('coinAfterDelivery'); }",
|
||
" pm.environment.set('gmGrant',JSON.stringify(current));",
|
||
" pm.environment.set('grantId',current.grantId);",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "09 错误发货凭证不能确认",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"confirm_delivery\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{claimPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"grantId\": \"postman-invalid-grant\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/grantId。返回 grantId/claimStatus/claimedThrough。仅在客户端已保存奖励后确认,重复确认幂等。\n\n所选任务须存在于该账号的玩家期记录。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"claimPeriodId\", \"claimTaskId\", \"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:INVALID_GRANT', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('INVALID_GRANT'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "05 到期补发(手动)",
|
||
"description": "查询所有历史已结束期的未确认奖励;后台 jobs/支付恢复负责结算。优先处理 items,有 nextCursor 即翻页,包括 settling 响应。扫描结束后从第一页复查;settling 时稍后重查,no_pending_rewards 时结束。05-05 选原 grantId,04-03/04 保存金币后使用 05-06 确认补发;ack_settlement 仅兼容展示确认。",
|
||
"item": [
|
||
{
|
||
"name": "01 清单第一页",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"settlements\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token,afterId 可选分页游标;前端不传 limit,后端固定每页扫描 20 期。返回 status=pending_delivery/settling/no_pending_rewards、items、nextCursor;每项含 settlementId/periodId/rewards,奖励含 taskId/grantId/items。可发奖励优先返回,不受其他期结算阻塞;no_pending_rewards 表示该玩家当前环境下所有已结束期均无待发或待结算记录。\n\n只查询后台已结算的未确认奖励。先处理可发奖励,有 nextCursor 即继续翻页;扫描结束后从第一页复查,settling 时稍后重查,no_pending_rewards 时结束。需部署 goldMiner/jobs 及每分钟触发器。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('补发清单结构', () => {",
|
||
" pm.expect(['settling','pending_delivery','no_pending_rewards'].includes(r.data.status)).to.eql(true);",
|
||
" pm.expect(Array.isArray(r.data.items)).to.eql(true);",
|
||
" pm.expect(r.data.nextCursor === null || typeof r.data.nextCursor === 'string').to.eql(true);",
|
||
" if (r.data.status === 'settling') pm.expect(r.data.items.length).to.eql(0);",
|
||
" if (r.data.status === 'no_pending_rewards') { pm.expect(r.data.items.length).to.eql(0); pm.expect(r.data.nextCursor).to.eql(null); }",
|
||
" r.data.items.forEach(s => {",
|
||
" pm.expect(typeof s.settlementId).to.eql('string'); pm.expect(typeof s.periodId).to.eql('string');",
|
||
" pm.expect(Array.isArray(s.rewards) && s.rewards.length > 0).to.eql(true);",
|
||
" s.rewards.forEach(g => { pm.expect(typeof g.grantId).to.eql('string'); pm.expect(typeof g.taskId).to.eql('string'); pm.expect(Array.isArray(g.items)).to.eql(true); });",
|
||
" });",
|
||
"});",
|
||
"if (r.code === 1) pm.environment.set('settlementCursor',r.data.nextCursor || '');"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 下一页(空 items 也可能有下一页)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"settlements\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"afterId\": \"{{settlementCursor}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token,afterId 可选分页游标;前端不传 limit,后端固定每页扫描 20 期。返回 status=pending_delivery/settling/no_pending_rewards、items、nextCursor;每项含 settlementId/periodId/rewards,奖励含 taskId/grantId/items。可发奖励优先返回,不受其他期结算阻塞;no_pending_rewards 表示该玩家当前环境下所有已结束期均无待发或待结算记录。\n\n只查询后台已结算的未确认奖励。先处理可发奖励,有 nextCursor 即继续翻页;扫描结束后从第一页复查,settling 时稍后重查,no_pending_rewards 时结束。需部署 goldMiner/jobs 及每分钟触发器。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"settlementCursor\", \"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('补发清单结构', () => {",
|
||
" pm.expect(['settling','pending_delivery','no_pending_rewards'].includes(r.data.status)).to.eql(true);",
|
||
" pm.expect(Array.isArray(r.data.items)).to.eql(true);",
|
||
" pm.expect(r.data.nextCursor === null || typeof r.data.nextCursor === 'string').to.eql(true);",
|
||
" if (r.data.status === 'settling') pm.expect(r.data.items.length).to.eql(0);",
|
||
" if (r.data.status === 'no_pending_rewards') { pm.expect(r.data.items.length).to.eql(0); pm.expect(r.data.nextCursor).to.eql(null); }",
|
||
" r.data.items.forEach(s => {",
|
||
" pm.expect(typeof s.settlementId).to.eql('string'); pm.expect(typeof s.periodId).to.eql('string');",
|
||
" pm.expect(Array.isArray(s.rewards) && s.rewards.length > 0).to.eql(true);",
|
||
" s.rewards.forEach(g => { pm.expect(typeof g.grantId).to.eql('string'); pm.expect(typeof g.taskId).to.eql('string'); pm.expect(Array.isArray(g.items)).to.eql(true); });",
|
||
" });",
|
||
"});",
|
||
"if (r.code === 1) pm.environment.set('settlementCursor',r.data.nextCursor || '');"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 未完成发货不能确认清单",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"ack_settlement\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"settlementId\": \"{{settlementId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/settlementId。返回 settlementId/acknowledged。仅已全部确认发货时成功;这是兼容展示确认,不代替 confirm_settlement_delivery。\n\n清单有未确认奖励时,旧 ack_settlement 仍不能提前确认展示。此请求不是发货确认。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"settlementId\", \"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('拒绝:DELIVERY_PENDING', () => { pm.expect(r.code).to.eql(0); pm.expect(r.errorCode).to.eql('DELIVERY_PENDING'); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 完成后确认清单(可重复)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"ack_settlement\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"settlementId\": \"{{settlementId}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/settlementId。返回 settlementId/acknowledged。仅已全部确认发货时成功;这是兼容展示确认,不代替 confirm_settlement_delivery。\n\n全部奖励确认后可选调用的旧展示确认,不是发货确认;新流程不要求调用。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"settlementId\", \"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('确认选定清单', () => { pm.expect(r.data.settlementId).to.eql(pm.environment.get('settlementId')); pm.expect(r.data.acknowledged).to.eql(true); });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "05 查询并选择首个待补发奖励(不调用 claim)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"settlements\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token,afterId 可选分页游标;前端不传 limit,后端固定每页扫描 20 期。返回 status=pending_delivery/settling/no_pending_rewards、items、nextCursor;每项含 settlementId/periodId/rewards,奖励含 taskId/grantId/items。可发奖励优先返回,不受其他期结算阻塞;no_pending_rewards 表示该玩家当前环境下所有已结束期均无待发或待结算记录。\n\n选择第一页首项;随后执行 04 文件夹的 03 读余额、04 保存余额,再执行本文件夹 06 确认。其他页奖励按返回标识选择,不走 claim。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('补发清单结构', () => {",
|
||
" pm.expect(['settling','pending_delivery','no_pending_rewards'].includes(r.data.status)).to.eql(true);",
|
||
" pm.expect(Array.isArray(r.data.items)).to.eql(true);",
|
||
" pm.expect(r.data.nextCursor === null || typeof r.data.nextCursor === 'string').to.eql(true);",
|
||
" if (r.data.status === 'settling') pm.expect(r.data.items.length).to.eql(0);",
|
||
" if (r.data.status === 'no_pending_rewards') { pm.expect(r.data.items.length).to.eql(0); pm.expect(r.data.nextCursor).to.eql(null); }",
|
||
" r.data.items.forEach(s => {",
|
||
" pm.expect(typeof s.settlementId).to.eql('string'); pm.expect(typeof s.periodId).to.eql('string');",
|
||
" pm.expect(Array.isArray(s.rewards) && s.rewards.length > 0).to.eql(true);",
|
||
" s.rewards.forEach(g => { pm.expect(typeof g.grantId).to.eql('string'); pm.expect(typeof g.taskId).to.eql('string'); pm.expect(Array.isArray(g.items)).to.eql(true); });",
|
||
" });",
|
||
"});",
|
||
"if (r.code === 1) pm.environment.set('settlementCursor',r.data.nextCursor || '');",
|
||
"",
|
||
"if (r.code === 1 && r.data.status === 'pending_delivery' && r.data.items.length) {",
|
||
" const s=r.data.items[0], g=s.rewards[0];",
|
||
" pm.environment.set('settlementId',s.settlementId);",
|
||
" pm.environment.set('claimPeriodId',s.periodId); pm.environment.set('claimTaskId',g.taskId);",
|
||
" pm.environment.set('grantId',g.grantId);",
|
||
" pm.environment.set('gmGrant',JSON.stringify({...g,periodId:s.periodId,claimStatus:'issuing',requiresClientDelivery:true}));",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "06 保存金币后确认补发(重复安全)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"confirm_settlement_delivery\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"settlementId\": \"{{settlementId}}\",\n \"grantIds\": [\n \"{{grantId}}\"\n ]\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/settlementId/grantIds(1~100 个不重复授权 ID)。返回 settlementId/confirmedGrantIds/deliveryStatus(partial/client_saved)。本用例逐项确认,须先完成对应奖励保存。\n\n只在所选 grantId 的金币确定已保存后执行。接口支持批量 grantIds,手工联调默认逐项,沿用既有金币保存保护。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"",
|
||
"need(['gmGrant','grantId','claimPeriodId','claimTaskId']);",
|
||
"const grant = JSON.parse(pm.environment.get('gmGrant'));",
|
||
"if (grant.grantId !== pm.environment.get('grantId') || grant.periodId !== pm.environment.get('claimPeriodId') || grant.taskId !== pm.environment.get('claimTaskId')) stop('凭证与所选期/任务不一致,请先领取所选任务');",
|
||
"",
|
||
"if (pm.environment.get('gmSavedGrantId') !== grant.grantId) stop('请先完成本凭证的金币保存');",
|
||
"need(['settlementId']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r=pm.response.json();",
|
||
"pm.test('业务成功',()=>pm.expect(r.code).to.eql(1));",
|
||
"pm.test('补发确认匹配授权',()=>{",
|
||
" pm.expect(r.data.settlementId).to.eql(pm.environment.get('settlementId'));",
|
||
" pm.expect(r.data.confirmedGrantIds).to.eql([pm.environment.get('grantId')]);",
|
||
" pm.expect(['partial','client_saved'].includes(r.data.deliveryStatus)).to.eql(true);",
|
||
"});"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "07 到期后普通领奖被拒绝",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"claim\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"periodId\": \"{{expiredPeriodId}}\",\n \"taskId\": \"{{claimTaskId}}\",\n \"requestId\": \"expired-claim\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "请求:uid/token/periodId/taskId/requestId。返回 grantId/taskId/items/claimStatus/claimedThrough/requiresClientDelivery。仅有效期内可申请;授权不加币。到期返回 PERIOD_SETTLEMENT_REQUIRED,转补发查询。\n\n手填 expiredPeriodId 和该期有效 claimTaskId;到期后普通领奖必须拒绝,含已授权任务的重复请求。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"uid\", \"token\"]);",
|
||
"need(['expiredPeriodId','claimTaskId']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r=pm.response.json();",
|
||
"pm.test('过期只走补发',()=>{pm.expect(r.code).to.eql(0);pm.expect(r.errorCode).to.eql('PERIOD_SETTLEMENT_REQUIRED');});"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "06 管理操作(手动)",
|
||
"description": "adminToken 对应服务端 ADMIN_TOKEN。逐条执行:索引、未来周配置、购买开关、测试临时期。publish_test_period 额外要求 PAYMENT_APP_ENV=test 和 GOLD_MINER_TEST_PERIODS_ENABLED=true。",
|
||
"item": [
|
||
{
|
||
"name": "01 创建活动索引",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"setup_indexes\",\n \"adminToken\": \"{{adminToken}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/admin",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"admin"
|
||
]
|
||
},
|
||
"description": "请求:action=setup_indexes、adminToken(ADMIN_TOKEN)。返回 code/msg。只准备现有设计需要的索引,不启用活动。\n\n"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"adminToken\"]);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 发布未来期配置",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmAdminBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/admin",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"admin"
|
||
]
|
||
},
|
||
"description": "configJson 格式见 README/API 文档,生效期必须为未来周四;同 configVersion 不重复发布。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"adminToken\", \"configJson\"]);",
|
||
"let config;",
|
||
"try { config=JSON.parse(pm.environment.get('configJson')); } catch { stop('configJson 必须是填写完成的配置 JSON'); }",
|
||
"const offers = config?.vipTiers === undefined ? [config] : config.vipTiers; if (!Array.isArray(offers) || !offers.length || (config.vipTiers && offers.length !== 6) || offers.some(o => !o || !Number.isSafeInteger(o.priceFen) || o.priceFen <= 0 || !Array.isArray(o.tasks) || !o.tasks.length)) stop('请填写正式确定的价格和任务;禁止发布空草稿');",
|
||
"pm.variables.set('gmAdminBody',JSON.stringify({action:'publish',adminToken:pm.environment.get('adminToken'),config}));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('配置发布成功', () => { const config=JSON.parse(pm.environment.get('configJson')); pm.expect(r.data.configVersion).to.eql(config.configVersion); pm.expect(r.data.effectiveFromPeriodId).to.eql(config.effectiveFromPeriodId); if (config.vipTiers) pm.expect(r.data.vipTiers).to.eql(config.vipTiers); else { pm.expect(r.data.priceFen).to.eql(config.priceFen); pm.expect(r.data.tasks).to.eql(config.tasks); } });"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 修改已有期购买开关",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{gmAdminBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/admin",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"admin"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need([\"adminToken\", \"adminPeriodId\", \"purchaseEnabled\"]);",
|
||
"const value=pm.environment.get('purchaseEnabled');",
|
||
"if (!['true','false'].includes(value)) stop('purchaseEnabled 必须为 true 或 false');",
|
||
"pm.variables.set('gmAdminBody',JSON.stringify({action:'set_purchasable',adminToken:pm.environment.get('adminToken'),periodId:pm.environment.get('adminPeriodId'),purchaseEnabled:value==='true'}));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 发布测试临时期(默认立即开启 30 分钟)",
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"const get = key => String(pm.environment.get(key) ?? '').trim();",
|
||
"const baseUrl = get('baseUrl');",
|
||
"if (!/^https?:\\/\\/[^\\s/?#]+(?::\\d+)?(?:\\/[^\\s?#]*)?$/.test(baseUrl) || baseUrl.endsWith('/') || /[<>]/.test(baseUrl)) stop('请填写 baseUrl(部署域名,无末尾 /)');",
|
||
"const adminToken = pm.environment.get('adminToken');",
|
||
"if (typeof adminToken !== 'string' || !adminToken.trim()) stop('请填写测试服 ADMIN_TOKEN 对应的 adminToken');",
|
||
"function timestamp(value, label) {",
|
||
" if (!/^\\d+$/.test(value) || !Number.isSafeInteger(Number(value)) || Number(value) <= 0 || !Number.isFinite(new Date(Number(value)).getTime())) stop(label + ' 必须为有效的 Unix 毫秒整数');",
|
||
" return Number(value);",
|
||
"}",
|
||
"let config;",
|
||
"try { config = JSON.parse(get('tempConfig')); } catch { stop('tempConfig 必须为 JSON 配置对象'); }",
|
||
"if (!config || typeof config !== 'object' || Array.isArray(config)) stop('tempConfig 必须为 JSON 配置对象');",
|
||
"let periodId = get('tempPeriodId');",
|
||
"if (periodId && !/^goldMiner:test:[A-Za-z0-9_-]{1,60}$/.test(periodId)) stop('tempPeriodId 格式为 goldMiner:test:自定义标识');",
|
||
"const startsAt = get('tempStartsAt') ? timestamp(get('tempStartsAt'), 'tempStartsAt') : Date.now();",
|
||
"let endsAt;",
|
||
"if (get('tempEndsAt')) endsAt = timestamp(get('tempEndsAt'), 'tempEndsAt');",
|
||
"else {",
|
||
" const minutes = Number(get('tempDurationMinutes'));",
|
||
" if (!Number.isSafeInteger(minutes) || minutes <= 0) stop('tempDurationMinutes 必须为正整数分钟');",
|
||
" endsAt = timestamp(String(startsAt + minutes * 60000), '计算出的结束时间');",
|
||
"}",
|
||
"if (endsAt <= startsAt) stop('tempEndsAt 必须晚于 tempStartsAt');",
|
||
"const nextPeriodId = get('tempNextPeriodId');",
|
||
"if (nextPeriodId && !/^goldMiner:(?:test:[A-Za-z0-9_-]{1,60}|\\d{4}-\\d{2}-\\d{2})$/.test(nextPeriodId)) stop('tempNextPeriodId 格式错误');",
|
||
"const previousBase = get('tempDraftBaseUrl');",
|
||
"if (previousBase && previousBase !== baseUrl) stop('baseUrl 已切换,请使用另一份环境,或清空 tempDraftBaseUrl/tempPeriodId/tempStartsAt/tempEndsAt 后重新生成');",
|
||
"if (!periodId) periodId = 'goldMiner:test:' + pm.variables.replaceIn('{{$guid}}');",
|
||
"// Only non-secret identifiers/times are persisted. Retrying Send reuses the same period.",
|
||
"pm.environment.set('tempPeriodId', periodId);",
|
||
"pm.environment.set('tempStartsAt', String(startsAt));",
|
||
"pm.environment.set('tempEndsAt', String(endsAt));",
|
||
"pm.environment.set('tempDraftBaseUrl', baseUrl);",
|
||
"const body = { action: 'publish_test_period', adminToken, periodId, startsAt, endsAt, config };",
|
||
"if (nextPeriodId) body.nextPeriodId = nextPeriodId;",
|
||
"// Local scope avoids storing a second copy of the administrator secret in the environment.",
|
||
"pm.variables.set('testPeriodRequestBody', JSON.stringify(body));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
|
||
"const response = pm.response.json();",
|
||
"const sent = JSON.parse(pm.variables.get('testPeriodRequestBody'));",
|
||
"pm.test('临时期发布成功(失败时查看响应 errorCode/msg)', function () { pm.expect(response.code).to.eql(1); });",
|
||
"if (response.code === 1 && response.data) {",
|
||
" const data = response.data;",
|
||
" pm.test('期 ID、开始和结束时间与请求一致', function () {",
|
||
" pm.expect(data.periodId).to.eql(sent.periodId);",
|
||
" pm.expect(data.startsAt).to.eql(sent.startsAt);",
|
||
" pm.expect(data.endsAt).to.eql(sent.endsAt);",
|
||
" });",
|
||
" pm.test('奖励配置和商品快照与请求一致', function () {",
|
||
" for (const key of ['configVersion', 'unlockPassedLevel', 'timezone', 'currency', ...(sent.config.vipTiers ? ['vipTiers'] : ['productId', 'priceFen', 'tasks'])]) {",
|
||
" pm.expect(data.configSnapshot[key]).to.eql(sent.config[key]);",
|
||
" }",
|
||
" pm.expect(data.configSnapshot.effectiveFromPeriodId).to.eql(sent.periodId);",
|
||
" pm.expect(typeof data.configHash).to.eql('string');",
|
||
" });",
|
||
" pm.test('顺延目标不早于本期结束', function () {",
|
||
" pm.expect(Number.isSafeInteger(data.nextStartsAt) && data.nextStartsAt >= sent.endsAt).to.eql(true);",
|
||
" if (sent.nextPeriodId) pm.expect(data.nextPeriodId).to.eql(sent.nextPeriodId);",
|
||
" });",
|
||
"}"
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{testPeriodRequestBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/admin",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"admin"
|
||
]
|
||
},
|
||
"description": "参数在配套 Environment 中配置。tempPeriodId/tempStartsAt/tempEndsAt 留空时首次自动生成并保存。tempConfig 为完整业务配置 JSON,可修改门槛、价格及任务。tempNextPeriodId 可留空。已发布期不可修改;新建期时使用新的期 ID 及不重叠的时间。接口对应服务端 publish_test_period 动作,没有单独的 /test-period 路由。"
|
||
},
|
||
"response": []
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "07 旧 iOS 客服渠道",
|
||
"item": [
|
||
{
|
||
"name": "01 客服渠道预下单(服务端定价)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"create_order\",\n \"channel\": \"legacy_ios\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"itemid\": \"{{productId}}\",\n \"createRequestId\": \"{{createRequestId}}\",\n \"itemPrice\": 1,\n \"itemCount\": 999\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": "需服务端启用 GOLD_MINER_LEGACY_ENABLED。与原生下单使用不同账号或不同期;同一期不切换渠道。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['uid','token','gmInfo','productId','priceFen']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.status !== 'purchasable') stop('请先查询可购买的当期活动');",
|
||
"pm.variables.set('createRequestId','legacy-'+pm.variables.replaceIn('{{$guid}}'));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('旧渠道订单使用服务端快照', () => {",
|
||
" pm.expect(r.data.channel).to.eql('legacy_ios');",
|
||
" pm.expect(r.data.quantity).to.eql(1);",
|
||
" pm.expect(r.data.priceFen).to.eql(Number(pm.environment.get('priceFen')));",
|
||
" pm.expect(r.data.productId).to.eql(pm.environment.get('productId'));",
|
||
" pm.expect(r.data.periodId).to.eql(JSON.parse(pm.environment.get('gmInfo')).periodId);",
|
||
" const session = JSON.parse(r.data.sessionFrom);",
|
||
" pm.expect(session.outTradeNo).to.eql(r.data.outTradeNo);",
|
||
" pm.expect(session.propName).to.eql(r.data.productId);",
|
||
" pm.expect(typeof session.goldMinerTicket).to.eql('string');",
|
||
"});",
|
||
"if (r.code === 1) { pm.environment.set('outTradeNo',r.data.outTradeNo); pm.environment.set('orderPeriodId',r.data.periodId); pm.environment.set('legacySessionFrom',r.data.sessionFrom); }"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 重复预下单复用原订单",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"action\": \"create_order\",\n \"channel\": \"legacy_ios\",\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"itemid\": \"{{productId}}\",\n \"createRequestId\": \"{{createRequestId}}\",\n \"itemPrice\": 1,\n \"itemCount\": 999\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/index",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"index"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['uid','token','gmInfo','productId','priceFen']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.status !== 'purchasable') stop('请先查询可购买的当期活动');",
|
||
"pm.variables.set('createRequestId','legacy-'+pm.variables.replaceIn('{{$guid}}'));",
|
||
"need(['outTradeNo','legacySessionFrom']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('旧渠道订单使用服务端快照', () => {",
|
||
" pm.expect(r.data.channel).to.eql('legacy_ios');",
|
||
" pm.expect(r.data.quantity).to.eql(1);",
|
||
" pm.expect(r.data.priceFen).to.eql(Number(pm.environment.get('priceFen')));",
|
||
" pm.expect(r.data.productId).to.eql(pm.environment.get('productId'));",
|
||
" pm.expect(r.data.periodId).to.eql(JSON.parse(pm.environment.get('gmInfo')).periodId);",
|
||
" const session = JSON.parse(r.data.sessionFrom);",
|
||
" pm.expect(session.outTradeNo).to.eql(r.data.outTradeNo);",
|
||
" pm.expect(session.propName).to.eql(r.data.productId);",
|
||
" pm.expect(typeof session.goldMinerTicket).to.eql('string');",
|
||
"});",
|
||
"pm.test('复用原订单', () => pm.expect(r.data.outTradeNo).to.eql(pm.environment.get('outTradeNo')));",
|
||
"if (r.code === 1) pm.environment.set('legacySessionFrom',r.data.sessionFrom);"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "03 客服回调发送支付链接(手动开启)",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{{legacyCustomerBody}}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/KeFuInfo",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"KeFuInfo"
|
||
]
|
||
},
|
||
"description": "需测试账号在微信有效客服会话窗口内,服务端已有 wxaccess_token;此请求会真实发送消息,勿在 Runner 中批量执行。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['openid','legacySessionFrom']);",
|
||
"if (pm.environment.get('allowCustomerMessage') !== 'true') stop('此请求会向测试账号发送客服消息;确认后填写 allowCustomerMessage=true');",
|
||
"pm.variables.set('legacyCustomerBody',JSON.stringify({Event:'user_enter_tempsession',FromUserName:pm.environment.get('openid'),SessionFrom:pm.environment.get('legacySessionFrom')}));"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('业务成功', () => pm.expect(r.code).to.eql(1));",
|
||
"pm.test('仍为原订单', () => pm.expect(r.data.outTradeNo).to.eql(pm.environment.get('outTradeNo')));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "04 登录态转单可重复调用",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"outTradeNo\": \"{{outTradeNo}}\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/checkIos",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"checkIos"
|
||
]
|
||
},
|
||
"description": "创建订单后即可调用;只校验/关联快照,不确认付款。支付页使用签名 time 票据而非登录态。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['uid','token','outTradeNo']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('转单明确成功', () => pm.expect(pm.response.json()).to.eql(true));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "05 无效转单票据拒绝",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"openid\": \"{{openid}}\",\n \"outTradeNo\": \"{{outTradeNo}}\",\n \"time\": \"invalid-ticket\"\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/checkIos",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"checkIos"
|
||
]
|
||
},
|
||
"description": ""
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['openid','outTradeNo']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"pm.test('未授权转单拒绝', () => pm.expect(pm.response.json()).to.eql(false));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "06 无签名商户通知拒绝",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"event_type\": \"TRANSACTION.SUCCESS\",\n \"resource\": {}\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/goldMiner/merchantNotify",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"goldMiner",
|
||
"merchantNotify"
|
||
]
|
||
},
|
||
"description": "之后再次查单,确认未解锁。不提供伪造成功通知或支付密钥。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
""
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"pm.test('HTTP 500', () => pm.response.to.have.status(500));",
|
||
"pm.test('无签名通知拒绝', () => pm.expect(pm.response.json().code).to.eql('FAIL'));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "07 旧渠道订单禁止再创建原生订单",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"uid\": \"{{uid}}\",\n \"token\": \"{{token}}\",\n \"itemid\": \"{{productId}}\",\n \"createRequestId\": \"{{createRequestId}}\",\n \"itemPrice\": 1,\n \"itemCount\": 999\n}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
},
|
||
"url": {
|
||
"raw": "{{baseUrl}}/wx/orderPaySig",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"wx",
|
||
"orderPaySig"
|
||
]
|
||
},
|
||
"description": "仅在旧渠道订单尚未付款时执行;原生支付签名配置也需已就绪。"
|
||
},
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"function stop(message) { console.error(message); pm.execution.skipRequest(); throw new Error(message); }",
|
||
"function need(keys) { for (const key of keys) if (String(pm.environment.get(key) ?? '').trim() === '') stop('请先填写/取得变量:' + key); }",
|
||
"function integer(key, min = 0) { need([key]); const value = Number(pm.environment.get(key)); if (!Number.isSafeInteger(value) || value < min) stop(key + ' 必须为有效整数'); return value; }",
|
||
"",
|
||
"need(['uid','token','gmInfo','productId','priceFen']);",
|
||
"const info = JSON.parse(pm.environment.get('gmInfo'));",
|
||
"if (info.status !== 'purchasable') stop('请先查询可购买的当期活动');",
|
||
"pm.variables.set('createRequestId','legacy-'+pm.variables.replaceIn('{{$guid}}'));",
|
||
"need(['outTradeNo','legacySessionFrom']);"
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('渠道冲突', () => pm.expect(r.errorCode).to.eql('PAYMENT_CHANNEL_CONFLICT'));"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "08 公共活动日程(无需登录,可单独 Runner)",
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。",
|
||
"item": [
|
||
{
|
||
"name": "01 公共活动日程(GET,无需登录)",
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": []
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('公共日程查询成功', () => pm.expect(r.code).to.eql(1));",
|
||
"let valid = false;",
|
||
"if (r.code === 1) pm.test('公共日程字段、时间窗口和排序', () => {",
|
||
" const d = r.data;",
|
||
" pm.expect(Object.keys(d).sort()).to.eql(['schemaVersion','serverNow','windowEndsAt','refreshAt','activities'].sort());",
|
||
" pm.expect(d.schemaVersion).to.eql(1);",
|
||
" pm.expect(Number.isSafeInteger(d.serverNow)).to.eql(true);",
|
||
" pm.expect(d.windowEndsAt).to.eql(d.serverNow + 7 * 86400000);",
|
||
" pm.expect(Array.isArray(d.activities)).to.eql(true);",
|
||
" const seen = new Set();",
|
||
" let refreshAt = d.serverNow + 30000;",
|
||
" d.activities.forEach(a => {",
|
||
" pm.expect(['goldMiner','cloudRise'].includes(a.activityId)).to.eql(true);",
|
||
" const fields = ['activityId','periodId','configVersion','startsAt','endsAt','unlockLevel','phase'];",
|
||
" if (a.activityId === 'goldMiner') fields.push('purchaseEnabled');",
|
||
" pm.expect(Object.keys(a).sort()).to.eql(fields.sort());",
|
||
" pm.expect(typeof a.periodId === 'string' && !!a.periodId && typeof a.configVersion === 'string' && !!a.configVersion).to.eql(true);",
|
||
" pm.expect(Number.isSafeInteger(a.startsAt) && Number.isSafeInteger(a.endsAt) && a.startsAt < a.endsAt).to.eql(true);",
|
||
" pm.expect(a.startsAt < d.windowEndsAt && a.endsAt > d.serverNow).to.eql(true);",
|
||
" pm.expect(Number.isSafeInteger(a.unlockLevel) && a.unlockLevel >= 0).to.eql(true);",
|
||
" pm.expect(a.phase).to.eql(a.startsAt <= d.serverNow ? 'active' : 'upcoming');",
|
||
" if (a.activityId === 'goldMiner') pm.expect(typeof a.purchaseEnabled).to.eql('boolean');",
|
||
" const key = JSON.stringify([a.activityId,a.periodId]);",
|
||
" pm.expect(seen.has(key)).to.eql(false);seen.add(key);",
|
||
" for (const boundary of [a.startsAt,a.endsAt]) if (boundary > d.serverNow) refreshAt = Math.min(refreshAt,boundary);",
|
||
" });",
|
||
" pm.expect(d.refreshAt).to.eql(refreshAt);",
|
||
" const sorted = [...d.activities].sort((a,b) => a.activityId < b.activityId ? -1 : a.activityId > b.activityId ? 1",
|
||
" : b.startsAt-a.startsAt || (a.periodId < b.periodId ? -1 : a.periodId > b.periodId ? 1 : 0));",
|
||
" pm.expect(d.activities).to.eql(sorted);",
|
||
" const expected = pm.environment.get('expectedListedPeriodId');",
|
||
" if (expected) pm.expect(d.activities.some(a=>a.activityId==='goldMiner' && a.periodId===expected)).to.eql(true);",
|
||
" valid = true;",
|
||
"});",
|
||
"// Cache only a valid success. Empty activities is valid; errors must preserve the previous cache.",
|
||
"if (valid) pm.environment.set('gmActivitySchedule',JSON.stringify(r.data));"
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"request": {
|
||
"method": "GET",
|
||
"header": [],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。"
|
||
},
|
||
"response": [
|
||
{
|
||
"name": "成功:临时期日程",
|
||
"originalRequest": {
|
||
"method": "GET",
|
||
"header": [],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。"
|
||
},
|
||
"status": "OK",
|
||
"code": 200,
|
||
"_postman_previewlanguage": "json",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"cookie": [],
|
||
"body": "{\n \"code\": 1,\n \"msg\": \"ok\",\n \"data\": {\n \"schemaVersion\": 1,\n \"serverNow\": 1789956000000,\n \"windowEndsAt\": 1790560800000,\n \"refreshAt\": 1789956030000,\n \"activities\": [\n {\n \"activityId\": \"goldMiner\",\n \"periodId\": \"goldMiner:test:20260921_1000\",\n \"configVersion\": \"temporaryV1\",\n \"startsAt\": 1789956000000,\n \"endsAt\": 1789959600000,\n \"unlockLevel\": 41,\n \"phase\": \"active\",\n \"purchaseEnabled\": true\n }\n ]\n }\n}"
|
||
},
|
||
{
|
||
"name": "成功:无开放或预告活动",
|
||
"originalRequest": {
|
||
"method": "GET",
|
||
"header": [],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。"
|
||
},
|
||
"status": "OK",
|
||
"code": 200,
|
||
"_postman_previewlanguage": "json",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"cookie": [],
|
||
"body": "{\n \"code\": 1,\n \"msg\": \"ok\",\n \"data\": {\n \"schemaVersion\": 1,\n \"serverNow\": 1789956000000,\n \"windowEndsAt\": 1790560800000,\n \"refreshAt\": 1789956030000,\n \"activities\": []\n }\n}"
|
||
},
|
||
{
|
||
"name": "查询失败:保留旧缓存",
|
||
"originalRequest": {
|
||
"method": "GET",
|
||
"header": [],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。"
|
||
},
|
||
"status": "OK",
|
||
"code": 200,
|
||
"_postman_previewlanguage": "json",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"cookie": [],
|
||
"body": "{\n \"code\": 0,\n \"msg\": \"活动信息暂时无法获取,请稍后重试\",\n \"data\": null\n}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"name": "02 公共活动日程(POST,无需登录)",
|
||
"event": [
|
||
{
|
||
"listen": "prerequest",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": []
|
||
}
|
||
},
|
||
{
|
||
"listen": "test",
|
||
"script": {
|
||
"type": "text/javascript",
|
||
"exec": [
|
||
"const r = pm.response.json();",
|
||
"pm.test('HTTP 200', () => pm.response.to.have.status(200));",
|
||
"pm.test('公共日程查询成功', () => pm.expect(r.code).to.eql(1));",
|
||
"let valid = false;",
|
||
"if (r.code === 1) pm.test('公共日程字段、时间窗口和排序', () => {",
|
||
" const d = r.data;",
|
||
" pm.expect(Object.keys(d).sort()).to.eql(['schemaVersion','serverNow','windowEndsAt','refreshAt','activities'].sort());",
|
||
" pm.expect(d.schemaVersion).to.eql(1);",
|
||
" pm.expect(Number.isSafeInteger(d.serverNow)).to.eql(true);",
|
||
" pm.expect(d.windowEndsAt).to.eql(d.serverNow + 7 * 86400000);",
|
||
" pm.expect(Array.isArray(d.activities)).to.eql(true);",
|
||
" const seen = new Set();",
|
||
" let refreshAt = d.serverNow + 30000;",
|
||
" d.activities.forEach(a => {",
|
||
" pm.expect(['goldMiner','cloudRise'].includes(a.activityId)).to.eql(true);",
|
||
" const fields = ['activityId','periodId','configVersion','startsAt','endsAt','unlockLevel','phase'];",
|
||
" if (a.activityId === 'goldMiner') fields.push('purchaseEnabled');",
|
||
" pm.expect(Object.keys(a).sort()).to.eql(fields.sort());",
|
||
" pm.expect(typeof a.periodId === 'string' && !!a.periodId && typeof a.configVersion === 'string' && !!a.configVersion).to.eql(true);",
|
||
" pm.expect(Number.isSafeInteger(a.startsAt) && Number.isSafeInteger(a.endsAt) && a.startsAt < a.endsAt).to.eql(true);",
|
||
" pm.expect(a.startsAt < d.windowEndsAt && a.endsAt > d.serverNow).to.eql(true);",
|
||
" pm.expect(Number.isSafeInteger(a.unlockLevel) && a.unlockLevel >= 0).to.eql(true);",
|
||
" pm.expect(a.phase).to.eql(a.startsAt <= d.serverNow ? 'active' : 'upcoming');",
|
||
" if (a.activityId === 'goldMiner') pm.expect(typeof a.purchaseEnabled).to.eql('boolean');",
|
||
" const key = JSON.stringify([a.activityId,a.periodId]);",
|
||
" pm.expect(seen.has(key)).to.eql(false);seen.add(key);",
|
||
" for (const boundary of [a.startsAt,a.endsAt]) if (boundary > d.serverNow) refreshAt = Math.min(refreshAt,boundary);",
|
||
" });",
|
||
" pm.expect(d.refreshAt).to.eql(refreshAt);",
|
||
" const sorted = [...d.activities].sort((a,b) => a.activityId < b.activityId ? -1 : a.activityId > b.activityId ? 1",
|
||
" : b.startsAt-a.startsAt || (a.periodId < b.periodId ? -1 : a.periodId > b.periodId ? 1 : 0));",
|
||
" pm.expect(d.activities).to.eql(sorted);",
|
||
" const expected = pm.environment.get('expectedListedPeriodId');",
|
||
" if (expected) pm.expect(d.activities.some(a=>a.activityId==='goldMiner' && a.periodId===expected)).to.eql(true);",
|
||
" valid = true;",
|
||
"});",
|
||
"// Cache only a valid success. Empty activities is valid; errors must preserve the previous cache.",
|
||
"if (valid) pm.environment.set('gmActivitySchedule',JSON.stringify(r.data));"
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。",
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"response": [
|
||
{
|
||
"name": "成功:临时期日程",
|
||
"originalRequest": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。",
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"status": "OK",
|
||
"code": 200,
|
||
"_postman_previewlanguage": "json",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"cookie": [],
|
||
"body": "{\n \"code\": 1,\n \"msg\": \"ok\",\n \"data\": {\n \"schemaVersion\": 1,\n \"serverNow\": 1789956000000,\n \"windowEndsAt\": 1790560800000,\n \"refreshAt\": 1789956030000,\n \"activities\": [\n {\n \"activityId\": \"goldMiner\",\n \"periodId\": \"goldMiner:test:20260921_1000\",\n \"configVersion\": \"temporaryV1\",\n \"startsAt\": 1789956000000,\n \"endsAt\": 1789959600000,\n \"unlockLevel\": 41,\n \"phase\": \"active\",\n \"purchaseEnabled\": true\n }\n ]\n }\n}"
|
||
},
|
||
{
|
||
"name": "成功:无开放或预告活动",
|
||
"originalRequest": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。",
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"status": "OK",
|
||
"code": 200,
|
||
"_postman_previewlanguage": "json",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"cookie": [],
|
||
"body": "{\n \"code\": 1,\n \"msg\": \"ok\",\n \"data\": {\n \"schemaVersion\": 1,\n \"serverNow\": 1789956000000,\n \"windowEndsAt\": 1790560800000,\n \"refreshAt\": 1789956030000,\n \"activities\": []\n }\n}"
|
||
},
|
||
{
|
||
"name": "查询失败:保留旧缓存",
|
||
"originalRequest": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"url": {
|
||
"raw": "{{baseUrl}}/activityConfig/list",
|
||
"host": [
|
||
"{{baseUrl}}"
|
||
],
|
||
"path": [
|
||
"activityConfig",
|
||
"list"
|
||
]
|
||
},
|
||
"description": "公开只读,无需 uid/token/adminToken,不传 action。GET 无请求体;POST 请求体为 {}。返回 schemaVersion、serverNow、windowEndsAt、refreshAt、activities。活动条目为 activityId/periodId/configVersion/startsAt/endsAt/unlockLevel/phase;黄金矿工另含 purchaseEnabled。phase=active/upcoming。含当前和未来七天的黄金矿工/百人赛日程;不表示玩家已达资格或已付费。成功空列表是正常结果;code=0/data=null 表示查询失败,保留缓存并重试。脚本只保存 gmActivitySchedule,不覆盖玩家 info 的 periodId 或奖励状态。可选 expectedListedPeriodId 断言指定黄金矿工期存在(必须落在查询窗口内)。",
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{}",
|
||
"options": {
|
||
"raw": {
|
||
"language": "json"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"status": "OK",
|
||
"code": 200,
|
||
"_postman_previewlanguage": "json",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"cookie": [],
|
||
"body": "{\n \"code\": 0,\n \"msg\": \"活动信息暂时无法获取,请稍后重试\",\n \"data\": null\n}"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|