# Game Interface 接口新增完成时间 ## ✅ 修改完成 在 `/api/link/{codeNo}/game-interface` 接口响应中新增了 `completedAt`(完成时间)和 `status`(任务状态)字段。 ## 📦 修改的文件 1. **GameInterfaceResponse.java** - 响应DTO - 新增 `status` 字段(任务状态) - 新增 `completedAt` 字段(完成时间) 2. **QrProxyController.java** - 控制器 - 设置 `status` 字段 - 仅当任务完成时设置 `completedAt` 字段 ## 📊 接口响应示例 ### 任务进行中(NEW / USING / LOGGED_IN) ```json { "codeNo": "MYNM5JHA", "totalPoints": 1000, "quantity": 100, "times": 10, "region": "Q", "regionDesc": "QQ区", "machineId": "rr3", "completedPoints": null, "status": "LOGGED_IN", "completedAt": null, "qrCodeUrl": "https://uzi1.cn/api/link/image/MYNM5JHA/qr.png", "homepageUrl": "https://uzi1.cn/api/link/image/MYNM5JHA/homepage.png", "firstRewardUrl": "https://uzi1.cn/api/link/image/MYNM5JHA/first-reward.png", "midRewardUrl": "https://uzi1.cn/api/link/image/MYNM5JHA/mid-reward.png", "endRewardUrl": "https://uzi1.cn/api/link/image/MYNM5JHA/end-reward.png", "progressDisplayFormat": "percent" } ``` ### 任务已完成(COMPLETED)✨ ```json { "codeNo": "MYNM5JHA", "totalPoints": 1000, "quantity": 100, "times": 10, "region": "Q", "regionDesc": "QQ区", "machineId": "rr3", "completedPoints": 1000, "status": "COMPLETED", "completedAt": 1730644245, "qrCodeUrl": "https://uzi1.cn/api/link/image/MYNM5JHA/qr.png", "homepageUrl": "https://uzi1.cn/api/link/completion/MYNM5JHA/homepage.png", "firstRewardUrl": "https://uzi1.cn/api/link/completion/MYNM5JHA/first-reward.png", "midRewardUrl": "https://uzi1.cn/api/link/completion/MYNM5JHA/mid-reward.png", "endRewardUrl": "https://uzi1.cn/api/link/completion/MYNM5JHA/end-reward.png", "progressDisplayFormat": "percent" } ``` ## 🎯 新增字段说明 ### status(任务状态) | 字段名 | 类型 | 说明 | 示例 | |--------|------|------|------| | `status` | String | 任务当前状态 | `"COMPLETED"` | **可能的值**: - `NEW`: 新建 - `USING`: 使用中 - `LOGGED_IN`: 已登录 - `COMPLETED`: 已完成 ✨ - `REFUNDED`: 已退款 - `EXPIRED`: 已过期 --- ### completedAt(完成时间戳) | 字段名 | 类型 | 说明 | 示例 | |--------|------|------|------| | `completedAt` | Long | 任务完成时间戳(秒级) | `1730644245` | **特点**: - ✅ 仅当 `status` 为 `COMPLETED` 时有值 - ✅ 使用 Unix 时间戳(秒级,10位数字) - ✅ 其他状态下为 `null` - ✅ 可直接用于前端时间处理 --- ## 🔧 实现逻辑 ```java // 设置状态 response.setStatus(linkTask.getStatus()); // 设置完成时间戳-秒级(仅当任务完成时) if ("COMPLETED".equals(linkTask.getStatus()) && linkTask.getUpdatedAt() != null) { // 转换为秒级时间戳 long epochSecond = linkTask.getUpdatedAt() .atZone(java.time.ZoneId.systemDefault()) .toEpochSecond(); response.setCompletedAt(epochSecond); } ``` ## 💡 前端使用示例 ### JavaScript/TypeScript ```javascript // 获取游戏界面数据 fetch(`/api/link/${codeNo}/game-interface`) .then(res => res.json()) .then(data => { console.log('任务状态:', data.status); // 判断任务是否完成 if (data.status === 'COMPLETED' && data.completedAt) { console.log('完成时间戳:', data.completedAt); // 将秒级时间戳转换为毫秒(JavaScript Date需要毫秒) const completedTime = new Date(data.completedAt * 1000); console.log('格式化时间:', completedTime.toLocaleString('zh-CN')); // 输出: 2025/11/3 20:30:45 // 计算完成了多久 const now = new Date(); const diffMs = now - completedTime; const diffMins = Math.floor(diffMs / 60000); console.log(`${diffMins} 分钟前完成`); // 显示完成图片 document.getElementById('homepage').src = data.homepageUrl; document.getElementById('firstReward').src = data.firstRewardUrl; document.getElementById('midReward').src = data.midRewardUrl; document.getElementById('endReward').src = data.endRewardUrl; } else { console.log('任务进行中...'); } }); ``` ### Vue/React 组件示例 ```javascript // Vue 3 Composition API import { ref, computed } from 'vue'; const gameData = ref(null); // 格式化完成时间 const formattedCompletedTime = computed(() => { if (gameData.value?.completedAt) { // 秒级时间戳转毫秒 const date = new Date(gameData.value.completedAt * 1000); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); } return null; }); // 计算完成多久 const completedAgo = computed(() => { if (gameData.value?.completedAt) { // 秒级时间戳转毫秒 const completedTime = new Date(gameData.value.completedAt * 1000); const now = new Date(); const diffMs = now - completedTime; const diffMins = Math.floor(diffMs / 60000); if (diffMins < 1) return '刚刚完成'; if (diffMins < 60) return `${diffMins} 分钟前`; const diffHours = Math.floor(diffMins / 60); if (diffHours < 24) return `${diffHours} 小时前`; const diffDays = Math.floor(diffHours / 24); return `${diffDays} 天前`; } return null; }); ``` ## 📱 UI 显示建议 ### 完成状态显示 ```html
✅ 已完成 完成时间: {{ formattedCompletedTime }} ({{ completedAgo }})
完成点数: {{ gameData.completedPoints }} / {{ gameData.totalPoints }}
``` ### 不同状态的UI提示 ```javascript const statusDisplay = { 'NEW': { text: '等待开始', color: 'gray', icon: '⏳' }, 'USING': { text: '使用中', color: 'blue', icon: '🎮' }, 'LOGGED_IN': { text: '已登录', color: 'green', icon: '✓' }, 'COMPLETED': { text: '已完成', color: 'success', icon: '✅' }, 'REFUNDED': { text: '已退款', color: 'warning', icon: '↩️' }, 'EXPIRED': { text: '已过期', color: 'danger', icon: '⏰' } }; const currentStatus = statusDisplay[gameData.status]; ``` ## 🎨 样式建议 ```css .completion-banner { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 16px; border-radius: 8px; margin-bottom: 16px; display: flex; align-items: center; gap: 12px; } .status-badge { background: rgba(255, 255, 255, 0.2); padding: 4px 12px; border-radius: 20px; font-weight: 600; } .completion-time { flex: 1; font-size: 14px; } .time-ago { opacity: 0.8; font-size: 12px; } .points-display { background: #f8f9fa; padding: 16px; border-radius: 8px; margin-bottom: 16px; } .points-display progress { width: 100%; height: 8px; margin-top: 8px; } ``` ## 📊 字段对比 | 场景 | status | completedAt | completedPoints | 图片URL前缀 | |------|--------|-------------|-----------------|-------------| | 新建任务 | `NEW` | `null` | `null` | `/api/link/image/` | | 使用中 | `USING` | `null` | `null` | `/api/link/image/` | | 已登录 | `LOGGED_IN` | `null` | 可能有值 | `/api/link/image/` | | 已完成 ✨ | `COMPLETED` | **有值** | **有值** | `/api/link/completion/` | | 已退款 | `REFUNDED` | `null` | 可能有值 | `/api/link/image/` | | 已过期 | `EXPIRED` | `null` | `null` | `/api/link/image/` | ## ⚙️ 时间戳格式说明 ### Unix 时间戳(秒级) ``` 1730644245 │ └─ 10位数字,表示自1970-01-01 00:00:00 UTC以来的秒数 ``` **示例值**: - `1730644245` = 2025-11-03 20:30:45 (北京时间) ### 解析示例 ```javascript // JavaScript - 秒级时间戳需要乘以1000转换为毫秒 const completedAt = 1730644245; const date = new Date(completedAt * 1000); // 注意:乘以1000 console.log(date.toLocaleString('zh-CN')); // 输出: 2025/11/3 20:30:45 console.log(date.toLocaleDateString('zh-CN')); // 输出: 2025/11/3 console.log(date.toLocaleTimeString('zh-CN')); // 输出: 20:30:45 // 或者使用时间库(如 dayjs) import dayjs from 'dayjs'; console.log(dayjs.unix(completedAt).format('YYYY-MM-DD HH:mm:ss')); // 输出: 2025-11-03 20:30:45 ``` ## 🧪 测试验证 ### 1. 任务进行中 ```bash curl "http://localhost:18080/api/link/MYNM5JHA/game-interface" | jq . # 预期结果 { "status": "LOGGED_IN", "completedAt": null, ... } ``` ### 2. 任务完成后 ```bash curl "http://localhost:18080/api/link/MYNM5JHA/game-interface" | jq . # 预期结果 { "status": "COMPLETED", "completedAt": 1730644245, "completedPoints": 1000, ... } ``` ## 📖 相关文档 - 完成图片保存功能: `COMPLETION_IMAGE_FEATURE_SUMMARY.md` - 图片URL优化: `GAME_INTERFACE_IMAGE_UPDATE.md` - 所有完成触发点: `COMPLETION_IMAGE_ALL_TRIGGERS.md` --- **更新时间**: 2025-11-03 **版本**: v1.3.0 **状态**: ✅ 已完成