mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-08-12 17:10:37 +00:00
Merge branch 'pr/215'
This commit is contained in:
commit
d298025d7c
@ -16,15 +16,9 @@ module.exports = (query, request) => {
|
|||||||
activityId: query.activityId || '6501202',
|
activityId: query.activityId || '6501202',
|
||||||
drawCount: query.drawCount || '1',
|
drawCount: query.drawCount || '1',
|
||||||
}
|
}
|
||||||
// TODO: 如何传递 checkToken
|
|
||||||
const optionQuery = { ...query }
|
|
||||||
if (query.checkToken) {
|
|
||||||
data.checkToken = query.checkToken
|
|
||||||
delete query.checkToken
|
|
||||||
}
|
|
||||||
return request(
|
return request(
|
||||||
`/api/middle/play/do/lottery`,
|
`/api/middle/play/do/lottery`,
|
||||||
data,
|
data,
|
||||||
createOption(optionQuery, 'eapi', 'v2'),
|
createOption(query, 'eapi', 'v3'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
28
module/rep_ugc_exam_info_get.js
Normal file
28
module/rep_ugc_exam_info_get.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 云小编考试状态
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
'/api/rep/ugc/exam/info/get',
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
32
module/rep_ugc_exam_question_single_get.js
Normal file
32
module/rep_ugc_exam_question_single_get.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 云小编考试取题
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
//
|
||||||
|
// taskId:
|
||||||
|
// 首次调用 rep/ugc/exam/start 获取,之后调用 rep/ugc/exam/info/get 获取
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType || !query.taskId)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
taskId: query.taskId,
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
'/api/rep/ugc/exam/question/single/get',
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
32
module/rep_ugc_exam_result_get.js
Normal file
32
module/rep_ugc_exam_result_get.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 云小编考试结果
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
//
|
||||||
|
// taskId:
|
||||||
|
// 首次调用 rep/ugc/exam/start 获取,之后调用 rep/ugc/exam/info/get 获取
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType || !query.taskId)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
taskId: query.taskId,
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
'/api/rep/ugc/exam/result/get',
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
24
module/rep_ugc_exam_start.js
Normal file
24
module/rep_ugc_exam_start.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 云小编考试开始
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
}
|
||||||
|
return request('/api/rep/ugc/exam/start', data, createOption(query, 'eapi'))
|
||||||
|
}
|
||||||
36
module/rep_ugc_exam_submit.js
Normal file
36
module/rep_ugc_exam_submit.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 云小编考试提交
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
//
|
||||||
|
// taskId:
|
||||||
|
// 首次调用 rep/ugc/exam/start 获取,之后调用 rep/ugc/exam/info/get 获取
|
||||||
|
//
|
||||||
|
// questionId:
|
||||||
|
// 调用 rep/ugc/exam/question/single/get 获取
|
||||||
|
//
|
||||||
|
// answer:
|
||||||
|
// A 对, B 错
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType || !query.taskId || !query.questionId || !query.answer)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
taskId: query.taskId,
|
||||||
|
questionId: query.questionId,
|
||||||
|
answer: query.answer,
|
||||||
|
}
|
||||||
|
return request('/api/rep/ugc/exam/submit', data, createOption(query, 'eapi'))
|
||||||
|
}
|
||||||
@ -5604,6 +5604,37 @@ let data = encodeURIComponent(
|
|||||||
|
|
||||||
**调用例子:** `/rep/ugc/user/collect-vip?activityId=5001`
|
**调用例子:** `/rep/ugc/user/collect-vip?activityId=5001`
|
||||||
|
|
||||||
|
<<<<<<<<< Temporary merge branch 1
|
||||||
|
### 云小编 - 剩余抽奖次数
|
||||||
|
|
||||||
|
说明: 登录后调用此接口, 获取今日云小编抽奖剩余次数
|
||||||
|
|
||||||
|
**可选参数:**
|
||||||
|
|
||||||
|
`activityId`: 活动 ID, 默认 `6501202`
|
||||||
|
|
||||||
|
**接口地址:** `/middle/play/lottery/remain/chance`
|
||||||
|
|
||||||
|
**调用例子:** `/middle/play/lottery/remain/chance?activityId=6501202`
|
||||||
|
|
||||||
|
### 云小编 - 每日抽奖
|
||||||
|
|
||||||
|
说明: 登录后调用此接口, 消耗 200 积分进行抽奖, 每日最多抽 3 次
|
||||||
|
|
||||||
|
> 注意: 抽奖失败也消耗每日次数, 请先调用 `/rep/ugc/user/get` 查询可用积分
|
||||||
|
|
||||||
|
**可选参数:**
|
||||||
|
|
||||||
|
`activityId`: 活动 ID, 默认 `6501202`
|
||||||
|
|
||||||
|
`drawCount`: 未知, 默认 `1`
|
||||||
|
|
||||||
|
`checkToken`: 易盾反作弊 Token, 默认自动获取
|
||||||
|
|
||||||
|
**接口地址:** `/middle/play/do/lottery`
|
||||||
|
|
||||||
|
**调用例子:** `/middle/play/do/lottery?activityId=6501202&drawCount=1`
|
||||||
|
=========
|
||||||
### 发送/删除评论
|
### 发送/删除评论
|
||||||
|
|
||||||
说明 : 调用此接口,可发送评论或者删除评论
|
说明 : 调用此接口,可发送评论或者删除评论
|
||||||
@ -5726,36 +5757,7 @@ let data = encodeURIComponent(
|
|||||||
**接口地址 :** `/device/kickoff`
|
**接口地址 :** `/device/kickoff`
|
||||||
|
|
||||||
**调用例子 :** `/device/kickoff?key=00ALDFGEXXXXXXXXXXXXXXXXX&captcha=1234`
|
**调用例子 :** `/device/kickoff?key=00ALDFGEXXXXXXXXXXXXXXXXX&captcha=1234`
|
||||||
|
>>>>>>>>> Temporary merge branch 2
|
||||||
### 云小编 - 剩余抽奖次数
|
|
||||||
|
|
||||||
说明: 登录后调用此接口, 获取今日云小编抽奖剩余次数
|
|
||||||
|
|
||||||
**可选参数:**
|
|
||||||
|
|
||||||
`activityId`: 活动 ID, 默认 `6501202`
|
|
||||||
|
|
||||||
**接口地址:** `/middle/play/lottery/remain/chance`
|
|
||||||
|
|
||||||
**调用例子:** `/middle/play/lottery/remain/chance?activityId=6501202`
|
|
||||||
|
|
||||||
### 云小编 - 每日抽奖
|
|
||||||
|
|
||||||
说明: 登录后调用此接口, 消耗 200 积分进行抽奖, 每日最多抽 3 次
|
|
||||||
|
|
||||||
> 注意: 抽奖失败也消耗每日次数, 请先调用 `/rep/ugc/user/get` 查询可用积分
|
|
||||||
|
|
||||||
**可选参数:**
|
|
||||||
|
|
||||||
`activityId`: 活动 ID, 默认 `6501202`
|
|
||||||
|
|
||||||
`drawCount`: 未知, 默认 `1`
|
|
||||||
|
|
||||||
`checkToken`: 易盾反作弊 Token, 默认自动获取
|
|
||||||
|
|
||||||
**接口地址:** `/middle/play/do/lottery`
|
|
||||||
|
|
||||||
**调用例子:** `/middle/play/do/lottery?activityId=6501202&drawCount=1`
|
|
||||||
|
|
||||||
## 离线访问此文档
|
## 离线访问此文档
|
||||||
|
|
||||||
|
|||||||
185
public/ugc.html
185
public/ugc.html
@ -6,6 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="referrer" content="no-referrer" />
|
<meta name="referrer" content="no-referrer" />
|
||||||
<link rel="icon" href="docs/netease.png" />
|
<link rel="icon" href="docs/netease.png" />
|
||||||
|
<meta name="referrer" content="no-referrer" />
|
||||||
|
<link rel="icon" href="docs/netease.png" />
|
||||||
<title>云小编任务中心 - 网易云音乐 API Enhanced</title>
|
<title>云小编任务中心 - 网易云音乐 API Enhanced</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@ -327,6 +329,10 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#userPoint {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Song Review ---- */
|
/* ---- Song Review ---- */
|
||||||
.song-review {
|
.song-review {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
@ -379,7 +385,7 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
max-height: 120px;
|
max-height: 160px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
@ -419,6 +425,7 @@
|
|||||||
<div class="info-card" id="user">
|
<div class="info-card" id="user">
|
||||||
<img src="docs/netease.png" alt="头像" class="avatar" id="userAvatar" />
|
<img src="docs/netease.png" alt="头像" class="avatar" id="userAvatar" />
|
||||||
<span class="info-text" id="userName">未登录</span>
|
<span class="info-text" id="userName">未登录</span>
|
||||||
|
<span id="userPoint">0</span>
|
||||||
<button class="btn-sm green" id="userSign" disabled>签到</button>
|
<button class="btn-sm green" id="userSign" disabled>签到</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -440,7 +447,7 @@
|
|||||||
<button class="btn-sm" id="taskGet">获取任务详情</button>
|
<button class="btn-sm" id="taskGet">获取任务详情</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card" id="task">
|
<div class="info-card" id="task">
|
||||||
<span class="info-text" id="taskInfo">[<span id="taskCount">0</span>/<span id="taskGoal">0</span>] 审核歌曲赚贡献分 (+66)</span>
|
<span class="info-text" id="taskInfo">[<span id="taskCount">0</span>/<span id="taskGoal">0</span>] 审核歌曲赚贡献分 (+<span id="taskPoint">0</span>)</span>
|
||||||
<button class="btn-sm" id="taskStart" disabled>去完成</button>
|
<button class="btn-sm" id="taskStart" disabled>去完成</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -556,6 +563,7 @@
|
|||||||
/// 用户信息 ///
|
/// 用户信息 ///
|
||||||
var userAvatar = document.getElementById('userAvatar');
|
var userAvatar = document.getElementById('userAvatar');
|
||||||
var userName = document.getElementById('userName');
|
var userName = document.getElementById('userName');
|
||||||
|
var userPoint = document.getElementById('userPoint');
|
||||||
var userSign = document.getElementById('userSign');
|
var userSign = document.getElementById('userSign');
|
||||||
var userGet = document.getElementById('userGet');
|
var userGet = document.getElementById('userGet');
|
||||||
|
|
||||||
@ -564,6 +572,7 @@
|
|||||||
var d = res.data;
|
var d = res.data;
|
||||||
if (d.imgUrl) userAvatar.src = d.imgUrl + '?param=50y50';
|
if (d.imgUrl) userAvatar.src = d.imgUrl + '?param=50y50';
|
||||||
userName.textContent = d.name || '游客' + d.id;
|
userName.textContent = d.name || '游客' + d.id;
|
||||||
|
userPoint.textContent = d.availablePoints;
|
||||||
userSign.disabled = d.signed;
|
userSign.disabled = d.signed;
|
||||||
showResult('用户信息加载成功', 'success');
|
showResult('用户信息加载成功', 'success');
|
||||||
});
|
});
|
||||||
@ -576,6 +585,7 @@
|
|||||||
var d = res.data;
|
var d = res.data;
|
||||||
userSign.disabled = d;
|
userSign.disabled = d;
|
||||||
showResult('签到' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
showResult('签到' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
||||||
|
if (d) userGet.click();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -608,21 +618,36 @@
|
|||||||
/// 审核任务 ///
|
/// 审核任务 ///
|
||||||
var taskCount = document.getElementById('taskCount');
|
var taskCount = document.getElementById('taskCount');
|
||||||
var taskGoal = document.getElementById('taskGoal');
|
var taskGoal = document.getElementById('taskGoal');
|
||||||
|
var taskPoint = document.getElementById('taskPoint');
|
||||||
var taskStartBtn = document.getElementById('taskStart');
|
var taskStartBtn = document.getElementById('taskStart');
|
||||||
var taskGetBtn = document.getElementById('taskGet');
|
var taskGetBtn = document.getElementById('taskGet');
|
||||||
|
|
||||||
taskGetBtn.onclick = function () {
|
taskGetBtn.onclick = function () {
|
||||||
request('/rep/ugc/activity/get', {}, function (res) {
|
request('rep/ugc/activity/get', {}, function (res) {
|
||||||
var d = res.data;
|
var d = res.data;
|
||||||
taskCount.textContent = d.count;
|
taskCount.textContent = d.count;
|
||||||
taskGoal.textContent = d.goalCount;
|
taskGoal.textContent = d.goalCount;
|
||||||
taskStartBtn.disabled = d.activityId !== 5001;
|
taskPoint.textContent = d.points;
|
||||||
|
// 注:超过 100 可能有 bug,导致 thinktank/audit/resource/detail 获取的任务 ID 一直是 5002,目标数量也不对,暂时限制前两个任务
|
||||||
|
taskStartBtn.disabled = d.activityId !== 5001 && d.activityId !== 5002; // 5001: 1-50, 5002: 51-100
|
||||||
showResult('任务详情加载成功', 'success');
|
showResult('任务详情加载成功', 'success');
|
||||||
|
// 任务完成,领取积分
|
||||||
|
if (d.count >= d.goalCount) {
|
||||||
|
request('rep/ugc/activity/collect', { activityId: d.activityId }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
showResult('积分领取' + (d ? '成功,可以兑换会员了!' : '失败'), d ? 'success' : 'error');
|
||||||
|
// 刷新任务状态
|
||||||
|
if (d) loadAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
taskStartBtn.onclick = function () {
|
taskStartBtn.onclick = function () {
|
||||||
if (!taskStartBtn.disabled) taskStart();
|
if (!taskStartBtn.disabled) {
|
||||||
|
songAudio.pause();
|
||||||
|
examInit();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 歌曲审核区域 ///
|
/// 歌曲审核区域 ///
|
||||||
@ -636,12 +661,93 @@
|
|||||||
var songSkip = document.getElementById('songSkip');
|
var songSkip = document.getElementById('songSkip');
|
||||||
var songLyric = document.getElementById('songLyric');
|
var songLyric = document.getElementById('songLyric');
|
||||||
|
|
||||||
|
var examType = 'emotionEnter';
|
||||||
|
// 考试初始化、检查状态
|
||||||
|
function examInit() {
|
||||||
|
request('rep/ugc/exam/info/get', { examType: examType }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
switch (d.process) {
|
||||||
|
case 'whole_exam_end':
|
||||||
|
// 通过考试
|
||||||
|
if (d.hasPassExamination) {
|
||||||
|
taskStart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
request('rep/ugc/exam/result/get', { examType: examType, taskId: d.taskId }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
showResult('考试未通过:正确数:' + d.wrightNum + ',正确率:' + d.wrightRate, 'error');
|
||||||
|
});
|
||||||
|
case 'no':
|
||||||
|
// 未通过或未开始
|
||||||
|
request('rep/ugc/exam/start', { examType: examType }, function (res) {
|
||||||
|
examStart(res.data.taskId);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'process':
|
||||||
|
// 正在考试
|
||||||
|
examStart(d.taskId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showResult('未知考试进度:' + d.process, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 在上个信息不为异常时显示考试中提示
|
||||||
|
if (d.process !== 'whole_exam_end' && !resultDiv.className.endsWith('error')) showResult('正在考试,请认真审题!', 'info');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 考试取题开始
|
||||||
|
function examStart(taskId) {
|
||||||
|
request('rep/ugc/exam/question/single/get', { examType: examType, taskId: taskId }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
|
||||||
|
songCover.src = d.coverUrl + '?param=100y100';
|
||||||
|
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||||||
|
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.questionContent + '?';
|
||||||
|
songLyric.textContent = d.lyric ? d.transLyric ? lrctran(d.lyric, d.transLyric) : d.lyric : '[00:00.00] 暂无歌词';
|
||||||
|
songLyric.scrollTop = 0;
|
||||||
|
// 有时候就是没有播放链接,只能根据歌词硬审
|
||||||
|
if (d.songUrl) {
|
||||||
|
songAudio.src = d.songUrl;
|
||||||
|
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||||||
|
} else {
|
||||||
|
songAudio.src = ''; // 清理播放器
|
||||||
|
}
|
||||||
|
songApprove.onclick = function () { if (!songApprove.disabled) examSubmit(taskId, d.questionId, 'A') };
|
||||||
|
songReject.onclick = function () { if (!songReject.disabled) examSubmit(taskId, d.questionId, 'B') };
|
||||||
|
songSkip.onclick = null;
|
||||||
|
|
||||||
|
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||||
|
song.style.display = 'block';
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
songApprove.disabled = songReject.disabled = false;
|
||||||
|
}, 3e3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 考试提交
|
||||||
|
function examSubmit(taskId, questionId, answer) {
|
||||||
|
songAudio.pause();
|
||||||
|
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||||
|
request(
|
||||||
|
'rep/ugc/exam/submit',
|
||||||
|
{ examType: examType, taskId: taskId, questionId: questionId, answer: answer },
|
||||||
|
function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
if (d.result) {
|
||||||
|
showResult('回答正确,加载下一首...', 'success');
|
||||||
|
} else {
|
||||||
|
showResult('回答错误:' + d.analysis, 'error');
|
||||||
|
}
|
||||||
|
examInit();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取任务
|
* 获取任务
|
||||||
*/
|
*/
|
||||||
function taskStart() {
|
function taskStart() {
|
||||||
song.style.display = 'none';
|
request('thinktank/audit/resource/detail', { type: '4' }, function (res) {
|
||||||
request('/thinktank/audit/resource/detail', { type: '4' }, function (res) {
|
|
||||||
var d = res.data;
|
var d = res.data;
|
||||||
|
|
||||||
if (d.auditCount >= 50) {
|
if (d.auditCount >= 50) {
|
||||||
@ -661,8 +767,8 @@
|
|||||||
songCover.src = d.coverUrl + '?param=100y100';
|
songCover.src = d.coverUrl + '?param=100y100';
|
||||||
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||||||
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.initResult + '?';
|
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.initResult + '?';
|
||||||
songLyric.textContent = (d.lyric || '') + (d.transLyric || '');
|
songLyric.textContent = d.lyric ? d.transLyric ? lrctran(d.lyric, d.transLyric) : d.lyric : '[00:00.00] 暂无歌词';
|
||||||
if (!songLyric.textContent.trim()) songLyric.textContent = '[00:00.00] 暂无歌词';
|
songLyric.scrollTop = 0;
|
||||||
songAudio.src = d.songUrl;
|
songAudio.src = d.songUrl;
|
||||||
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||||||
|
|
||||||
@ -685,6 +791,7 @@
|
|||||||
* @param {'1'|'2'|'3'} judgement
|
* @param {'1'|'2'|'3'} judgement
|
||||||
*/
|
*/
|
||||||
function taskSubmit(taskId, judgement) {
|
function taskSubmit(taskId, judgement) {
|
||||||
|
songAudio.pause();
|
||||||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||||
request(
|
request(
|
||||||
'thinktank/audit/resource/update',
|
'thinktank/audit/resource/update',
|
||||||
@ -692,7 +799,10 @@
|
|||||||
function (res) {
|
function (res) {
|
||||||
var d = res.data;
|
var d = res.data;
|
||||||
if (d.result) {
|
if (d.result) {
|
||||||
showResult('审核提交成功,加载下一首...', 'success');
|
showResult((d.test ? '抽查' : '审核') + '提交成功,加载下一首...', 'success');
|
||||||
|
taskStart();
|
||||||
|
} else if (d.test) {
|
||||||
|
showResult('抽查失败: [' + d.dayErrorNum + '/' + d.dayErrorNumStandard + '] ' + d.errorAnalysis, 'error');
|
||||||
taskStart();
|
taskStart();
|
||||||
} else {
|
} else {
|
||||||
showResult('未知状态: ' + JSON.stringify(d), 'error');
|
showResult('未知状态: ' + JSON.stringify(d), 'error');
|
||||||
@ -701,6 +811,61 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**解析歌词时间戳和文本 */
|
||||||
|
function lrctrim(lyrics) {
|
||||||
|
var lines = lyrics.split('\n');
|
||||||
|
var data = [];
|
||||||
|
lines.forEach(function (line, index) {
|
||||||
|
var matches = line.match(/\[(\d{2}):(\d{2}[\.:]?\d*)\]/);
|
||||||
|
if (matches) {
|
||||||
|
var minutes = parseInt(matches[1], 10);
|
||||||
|
var seconds = parseFloat(matches[2].replace('.', ':')) || 0;
|
||||||
|
var timestamp = minutes * 6e4 + seconds * 1e3;
|
||||||
|
var text = line.replace(/\[\d{2}:\d{2}[\.:]?\d*\]/g, '').trim();
|
||||||
|
text = text.replace(/\s\s+/g, ' '); // Replace multiple spaces with a single space
|
||||||
|
data.push([timestamp, index, text]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
data.sort(function (a, b) {
|
||||||
|
return a[0] - b[0];
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/**合并原文歌词和翻译歌词 */
|
||||||
|
function lrctran(lyric, tlyric) {
|
||||||
|
lyric = lrctrim(lyric);
|
||||||
|
tlyric = lrctrim(tlyric);
|
||||||
|
var len1 = lyric.length;
|
||||||
|
var len2 = tlyric.length;
|
||||||
|
var result = '';
|
||||||
|
for (var i = 0, j = 0; i < len1 && j < len2; i++) {
|
||||||
|
while (lyric[i][0] > tlyric[j][0] && j + 1 < len2) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (lyric[i][0] === tlyric[j][0]) {
|
||||||
|
tlyric[j][2] = tlyric[j][2].replace('/', '');
|
||||||
|
if (tlyric[j][2]) {
|
||||||
|
lyric[i][2] += ' (' + tlyric[j][2] + ')';
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var k = 0; k < len1; k++) {
|
||||||
|
var t = lyric[k][0];
|
||||||
|
result += '['.concat(
|
||||||
|
String(Math.floor(t / 6e4)).padStart(2, '0'),
|
||||||
|
':',
|
||||||
|
String(Math.floor((t % 6e4) / 1e3)).padStart(2, '0'),
|
||||||
|
'.',
|
||||||
|
String(t % 1e3).padStart(3, '0'),
|
||||||
|
']',
|
||||||
|
lyric[k][2],
|
||||||
|
'\n',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// 一键载入 ///
|
/// 一键载入 ///
|
||||||
window.loadAll = function () {
|
window.loadAll = function () {
|
||||||
userGet.click();
|
userGet.click();
|
||||||
|
|||||||
@ -8,6 +8,16 @@
|
|||||||
<link rel="icon" href="docs/netease.png" />
|
<link rel="icon" href="docs/netease.png" />
|
||||||
<title>云小编每日抽奖 - 网易云音乐 API Enhanced</title>
|
<title>云小编每日抽奖 - 网易云音乐 API Enhanced</title>
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--gold: #fdcb6e;
|
||||||
|
--text-light: #636e72;
|
||||||
|
--fg: #333;
|
||||||
|
--muted: #666;
|
||||||
|
--border: #ddd;
|
||||||
|
--bg: #f5f5f5;
|
||||||
|
--panel: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -15,221 +25,83 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: 'Segoe UI', system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||||
|
background: linear-gradient(135deg, var(--bg-start) 0%, var(--bg-end) 50%, #fce4ec 100%);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f5f5f5;
|
display: flex;
|
||||||
padding: 20px;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 520px;
|
max-width: 520px;
|
||||||
margin: 40px auto;
|
|
||||||
background: white;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 32px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle b {
|
|
||||||
color: #d63031;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- Section ---- */
|
|
||||||
.section {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section:last-of-type {
|
|
||||||
border-bottom: none;
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
gap: 1.5rem;
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
/* 标题编辑卡片 */
|
||||||
font-size: 16px;
|
.card {
|
||||||
font-weight: 600;
|
background: var(--card-bg);
|
||||||
color: #333;
|
border-radius: var(--radius);
|
||||||
|
padding: 1.8rem 2rem;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
transition: var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Form Elements ---- */
|
.title-section {
|
||||||
.form-group {
|
text-align: center;
|
||||||
margin-bottom: 16px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
.title-input {
|
||||||
display: block;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #555;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label .tag {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 400;
|
|
||||||
padding: 1px 6px;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label .tag.o {
|
|
||||||
background: #fef3c7;
|
|
||||||
color: #92400e;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"],
|
|
||||||
input[type="number"],
|
|
||||||
textarea {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px 14px;
|
border: 2px solid transparent;
|
||||||
border: 1px solid #ddd;
|
border-radius: var(--radius-sm);
|
||||||
border-radius: 6px;
|
font-size: 1.6rem;
|
||||||
font-size: 14px;
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
color: var(--text);
|
||||||
|
background: #fafafa;
|
||||||
|
transition: var(--transition);
|
||||||
outline: none;
|
outline: none;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"]:focus,
|
.title-input:hover {
|
||||||
input[type="number"]:focus,
|
background: #f5f3ff;
|
||||||
textarea:focus {
|
|
||||||
border-color: #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
.title-input:focus {
|
||||||
resize: vertical;
|
border-color: var(--primary-light);
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 0 0 4px rgba(124, 108, 240, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.title-hint {
|
||||||
display: block;
|
font-size: 0.8rem;
|
||||||
width: 100%;
|
color: #b2bec3;
|
||||||
padding: 12px;
|
margin-top: 0.4rem;
|
||||||
background: #333;
|
}
|
||||||
color: white;
|
|
||||||
font-size: 15px;
|
/* 抽奖主卡片 */
|
||||||
font-weight: 500;
|
.lottery-card {
|
||||||
border-radius: 6px;
|
background: var(--card-bg);
|
||||||
cursor: pointer;
|
border-radius: var(--radius);
|
||||||
transition: background 0.2s ease;
|
padding: 2rem 2rem 2.2rem;
|
||||||
border: none;
|
box-shadow: var(--shadow);
|
||||||
|
border: 1px solid var(--border);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover {
|
|
||||||
background: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:disabled {
|
|
||||||
background: #ccc;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
display: inline-block;
|
|
||||||
width: auto;
|
|
||||||
padding: 6px 16px;
|
|
||||||
background: #333;
|
|
||||||
color: white;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.2s ease;
|
|
||||||
border: none;
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm:hover {
|
|
||||||
background: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm:disabled {
|
|
||||||
background: #ccc;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm.gray {
|
|
||||||
background: #6b7280;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm.gray:hover {
|
|
||||||
background: #4b5563;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm.gray:disabled {
|
|
||||||
background: #d1d5db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm.green {
|
|
||||||
background: #059669;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm.green:hover {
|
|
||||||
background: #047857;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm.green:disabled {
|
|
||||||
background: #a7f3d0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-fill {
|
|
||||||
margin-top: 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-fill span {
|
|
||||||
color: #0066cc;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-fill span:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- Lottery Display ---- */
|
|
||||||
.lottery-display {
|
|
||||||
text-align: center;
|
|
||||||
padding: 24px 16px;
|
|
||||||
background: #f9fafb;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.rolling-display {
|
.rolling-display {
|
||||||
font-size: 2.4rem;
|
font-size: 2.4rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #333;
|
color: var(--primary);
|
||||||
min-height: 4rem;
|
min-height: 4rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -239,19 +111,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rolling-display.idle {
|
.rolling-display.idle {
|
||||||
color: #999;
|
color: #c4b5fd;
|
||||||
font-size: 1.2rem;
|
font-size: 1.3rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Winner Result ---- */
|
/* ---- Winner Result ---- */
|
||||||
.winner-display {
|
.winner-display {
|
||||||
background: #f0fdf4;
|
background: linear-gradient(135deg, #fff9e6, #fff3cd);
|
||||||
border: 1px solid #86efac;
|
border: 2px solid var(--gold);
|
||||||
border-radius: 8px;
|
border-radius: var(--radius);
|
||||||
padding: 20px 16px;
|
padding: 1.5rem;
|
||||||
margin-top: 16px;
|
margin: 1rem 0 1.5rem;
|
||||||
text-align: center;
|
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
|
|
||||||
.winner-label {
|
.winner-label {
|
||||||
@ -269,6 +141,12 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.winner-img {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
.confetti-row {
|
.confetti-row {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -294,7 +172,60 @@
|
|||||||
to { transform: translateY(-8px); }
|
to { transform: translateY(-8px); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Status ---- */
|
/* 按钮 */
|
||||||
|
.btn {
|
||||||
|
padding: 0.9rem 2.5rem;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--transition);
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-lottery {
|
||||||
|
background: linear-gradient(135deg, #fd79a8, #e84393);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 6px 20px rgba(253, 121, 168, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-lottery:hover:not(:disabled) {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 10px 28px rgba(253, 121, 168, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-lottery:active:not(:disabled) {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-lottery:disabled {
|
||||||
|
background: #b2bec3;
|
||||||
|
box-shadow: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-reset {
|
||||||
|
background: transparent;
|
||||||
|
border: 2px solid var(--border);
|
||||||
|
color: var(--text-light);
|
||||||
|
margin-top: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-reset:hover {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
color: var(--primary);
|
||||||
|
background: #f8f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态提示 */
|
||||||
.status-bar {
|
.status-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -354,13 +285,14 @@
|
|||||||
|
|
||||||
/* ---- Responsive ---- */
|
/* ---- Responsive ---- */
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
.container {
|
|
||||||
padding: 20px 16px;
|
.card,
|
||||||
margin: 20px auto;
|
.lottery-card {
|
||||||
|
padding: 1.4rem 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
.title-input {
|
||||||
font-size: 20px;
|
font-size: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rolling-display {
|
.rolling-display {
|
||||||
@ -377,53 +309,33 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>云小编每日抽奖</h1>
|
<!-- 标题编辑区 -->
|
||||||
<p class="subtitle">每次抽奖消耗 <b>200 个曲库编辑部积分</b>,每日最多可抽奖 3 次</p>
|
<div class="card title-section">
|
||||||
|
<input type="text" class="title-input" id="titleInput" value="🎉 云小编每日抽奖 🎉" autocomplete="off" disabled>
|
||||||
<!-- Cookie 管理 -->
|
<div class="title-hint">每次抽奖消耗 <b>200 个曲库编辑部积分</b>,每日最多可抽奖 3 次</div>
|
||||||
<div class="form-group">
|
|
||||||
<label for="cookieInput">令牌 <span class="tag o">可选</span></label>
|
|
||||||
<input type="text" id="cookieInput" placeholder="留空则默认读取本地存储的令牌" autocomplete="off" />
|
|
||||||
<div class="quick-fill">
|
|
||||||
<span onclick="readLocalCookie()">读取本地令牌</span>
|
|
||||||
<span onclick="clearCookie()">清除令牌</span>
|
|
||||||
<span onclick="saveCookie()">保存令牌</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 抽奖区域 -->
|
<!-- 抽奖主区域 -->
|
||||||
<div class="section">
|
<div class="lottery-card">
|
||||||
<div class="section-header">
|
<div class="rolling-display idle" id="rollingDisplay">等待抽奖</div>
|
||||||
<span class="section-title">每日抽奖</span>
|
<div id="resultContainer"></div>
|
||||||
</div>
|
<button class="btn btn-lottery" id="lotteryBtn">
|
||||||
|
<span>🎲</span> 开始抽奖
|
||||||
<div class="lottery-display">
|
</button>
|
||||||
<div class="rolling-display idle" id="rollingDisplay">等待抽奖</div>
|
<button class="btn btn-reset" id="resetBtn">
|
||||||
<div id="resultContainer"></div>
|
<span>🔄</span> 编辑令牌
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="btn" id="lotteryBtn">
|
|
||||||
🎲 开始抽奖
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="status-bar" id="statusBar">
|
<div class="status-bar" id="statusBar">
|
||||||
<span class="status-dot idle" id="statusDot"></span>
|
<span class="status-dot idle" id="statusDot"></span>
|
||||||
<span class="status-text" id="statusText">就绪,点击按钮开始抽奖</span>
|
<span class="status-text" id="statusText">就绪,点击按钮开始抽奖</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 页脚 -->
|
|
||||||
<div class="footer-link">
|
|
||||||
<a href="/">← 返回首页</a>
|
|
||||||
<span style="margin: 0 8px; color: #ddd;">·</span>
|
|
||||||
<a href="/ugc.html">云小编任务中心</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
// ============ DOM 元素 ============
|
// ============ DOM 元素 ============
|
||||||
const cookieInput = document.getElementById('cookieInput');
|
const titleInput = document.getElementById('titleInput');
|
||||||
const rollingDisplay = document.getElementById('rollingDisplay');
|
const rollingDisplay = document.getElementById('rollingDisplay');
|
||||||
const resultContainer = document.getElementById('resultContainer');
|
const resultContainer = document.getElementById('resultContainer');
|
||||||
const lotteryBtn = document.getElementById('lotteryBtn');
|
const lotteryBtn = document.getElementById('lotteryBtn');
|
||||||
@ -540,18 +452,20 @@
|
|||||||
|
|
||||||
const res = await request('middle/play/do/lottery', '&activityId=6501202&drawCount=1');
|
const res = await request('middle/play/do/lottery', '&activityId=6501202&drawCount=1');
|
||||||
|
|
||||||
|
// 根据你的后端返回格式提取中奖者名称
|
||||||
const winner = res.data?.prizeDetailInfoMap?.['8186002']?.prizeName;
|
const winner = res.data?.prizeDetailInfoMap?.['8186002']?.prizeName;
|
||||||
if (!winner) {
|
if (!winner) {
|
||||||
throw new Error('无法解析响应数据');
|
throw new Error('无法解析响应数据');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [抽奖结果, 剩余机会]
|
||||||
return [winner, res.data.restChance];
|
return [winner, res.data.restChance];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ 滚动动画 ============
|
// ============ 滚动动画 ============
|
||||||
function startRollingAnimation(finalWinner) {
|
function startRollingAnimation(finalWinner, img) {
|
||||||
const placeholderNames = ['🎰', '🎲', '🎯', '✨', '💫', '🌟', '🎪', '🎭'];
|
const placeholderNames = ['🎰', '🎲', '🎯', '✨', '💫', '🌟', '🎪', '🎭'];
|
||||||
const totalDuration = 2800;
|
const totalDuration = 2000;
|
||||||
const startInterval = 50;
|
const startInterval = 50;
|
||||||
const endInterval = 280;
|
const endInterval = 280;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
@ -571,7 +485,8 @@
|
|||||||
if (progress >= 1.0) {
|
if (progress >= 1.0) {
|
||||||
clearTimeout(rollingTimer);
|
clearTimeout(rollingTimer);
|
||||||
rollingDisplay.textContent = finalWinner;
|
rollingDisplay.textContent = finalWinner;
|
||||||
showWinnerResult(finalWinner);
|
rollingDisplay.style.display = 'none';
|
||||||
|
showWinnerResult(finalWinner, img);
|
||||||
finishDrawing();
|
finishDrawing();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -583,16 +498,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showWinnerResult(winner) {
|
function showWinnerResult(winner) {
|
||||||
resultContainer.innerHTML =
|
resultContainer.innerHTML = `
|
||||||
'<div class="winner-display">' +
|
<div class="winner-display">
|
||||||
'<div class="winner-label">🏆 恭喜中奖</div>' +
|
<div class="winner-label">🏆 恭喜中奖</div>
|
||||||
'<div class="winner-name">' + escapeHTML(winner) + '</div>' +
|
<div class="winner-name">${escapeHTML(winner)}</div>
|
||||||
'<div class="confetti-row">' +
|
<div class="confetti-row">
|
||||||
'<span class="confetti-emoji">🎉</span>' +
|
<span class="confetti-emoji">🎉</span>
|
||||||
'<span class="confetti-emoji">🎊</span>' +
|
<span class="confetti-emoji">🎊</span>
|
||||||
'<span class="confetti-emoji">✨</span>' +
|
<span class="confetti-emoji">✨</span>
|
||||||
'</div>' +
|
</div>
|
||||||
'</div>';
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHTML(str) {
|
function escapeHTML(str) {
|
||||||
@ -615,11 +531,13 @@
|
|||||||
resultContainer.innerHTML = '';
|
resultContainer.innerHTML = '';
|
||||||
rollingDisplay.className = 'rolling-display';
|
rollingDisplay.className = 'rolling-display';
|
||||||
rollingDisplay.textContent = '🎰';
|
rollingDisplay.textContent = '🎰';
|
||||||
|
rollingDisplay.style.display = 'flex';
|
||||||
setStatus('info', '正在获取抽奖结果...');
|
setStatus('info', '正在获取抽奖结果...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetchLotteryResult();
|
const res = await fetchLotteryResult();
|
||||||
setStatus('info', '抽奖成功,剩余次数 ' + res[1]);
|
setStatus('info', '抽奖成功,剩余次数 ' + res[1]);
|
||||||
|
// 启动滚动动画,最终定格在中奖者
|
||||||
startRollingAnimation(res[0]);
|
startRollingAnimation(res[0]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
rollingDisplay.textContent = '抽奖失败';
|
rollingDisplay.textContent = '抽奖失败';
|
||||||
@ -633,8 +551,9 @@
|
|||||||
// ============ 事件绑定 ============
|
// ============ 事件绑定 ============
|
||||||
lotteryBtn.addEventListener('click', startLottery);
|
lotteryBtn.addEventListener('click', startLottery);
|
||||||
|
|
||||||
document.addEventListener('keydown', function (e) {
|
// 空格键快捷抽奖
|
||||||
if (e.key === ' ' && document.activeElement !== cookieInput) {
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === ' ' && document.activeElement !== titleInput) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!isDrawing && !lotteryBtn.disabled) {
|
if (!isDrawing && !lotteryBtn.disabled) {
|
||||||
startLottery();
|
startLottery();
|
||||||
@ -651,6 +570,12 @@
|
|||||||
|
|
||||||
// ============ 初始化 ============
|
// ============ 初始化 ============
|
||||||
resetResult();
|
resetResult();
|
||||||
|
|
||||||
|
window.demo = function (name, chance, img) {
|
||||||
|
rollingDisplay.style.display = 'flex';
|
||||||
|
setStatus('info', '抽奖成功,剩余次数 ' + (chance || '0'));
|
||||||
|
startRollingAnimation(name || '演示', img || 'https://p5.music.126.net/obj/worDmcOCw6HCnzzCmsKx/61891591760/8d1c/528a/e977/10cbaa3fb39e8057be5d2560182cc5c7.png');
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user