Files
pk-lab-xhs/pages/test/test.js
T
codex-bot 36aee09dfa
Verify mini program and deploy preview / verify-deploy (push) Successful in 50s
feat: add animated choice modes and bracket editor
2026-09-19 04:11:21 +08:00

115 lines
4.4 KiB
JavaScript

var api = require('../../utils/api');
var bracket = require('../../utils/bracket');
Page({
data: { loading: true, error: '', test: null, left: null, right: null, matches: [], mode: 'single', round: 1, progress: 0, completed: 0, totalDecisions: 0 },
onLoad: function (options) {
this.slug = options.slug;
this.load();
},
load: function () {
var self = this;
api.request('/api/v1/tests/' + this.slug).then(function (test) {
self.test = test;
self.state = bracket.create(test.candidates);
self.totalDecisions = test.candidates.length - 1;
self.refreshPair();
self.setData({ loading: false, test: test, totalDecisions: self.totalDecisions });
}).catch(function (error) { self.setData({ loading: false, error: error.message || '加载失败' }); });
},
refreshPair: function () {
var pair = bracket.current(this.state);
if (this.visibleRound !== this.state.round) {
this.visibleRound = this.state.round;
this.multiOffset = 0;
}
var offset = this.multiOffset || 0;
var matches = this.state.matches.slice(offset, offset + 4).map(function (match, index) {
return { index: offset + index, left: match.left, right: match.right, winner: match.winner };
});
this.setData({
left: pair && pair[0],
right: pair && pair[1],
matches: matches,
round: this.state.round,
completed: this.state.decisions.length,
progress: Math.round(this.state.decisions.length / this.totalDecisions * 100)
});
},
setMode: function (event) {
this.setData({ mode: event.currentTarget.dataset.mode });
},
choose: function (event) {
if (this.choosing) return;
this.choosing = true;
var side = event.currentTarget.dataset.side;
var winner = side === 'left' ? this.data.left : this.data.right;
var finished = bracket.choose(this.state, winner);
if (finished) this.complete();
else {
this.refreshPair();
var self = this;
setTimeout(function () { self.choosing = false; }, 220);
}
},
chooseMatch: function (event) {
if (this.choosing) return;
var matchIndex = Number(event.currentTarget.dataset.match);
var side = event.currentTarget.dataset.side;
var match = this.state.matches[matchIndex];
if (!match || match.winner || !match.right) return;
this.choosing = true;
var winner = side === 'left' ? match.left : match.right;
var beforeRound = this.state.round;
var finished = bracket.chooseAt(this.state, matchIndex, winner);
if (finished) this.complete();
else {
this.refreshPair();
var self = this;
setTimeout(function () {
if (beforeRound === self.state.round) {
var offset = self.multiOffset || 0;
var block = self.state.matches.slice(offset, offset + 4);
if (block.length && block.every(function (item) { return item.winner; })) self.multiOffset = offset + 4;
}
self.refreshPair();
self.choosing = false;
}, 360);
}
},
touchStart: function (event) { this.touchX = event.touches[0].clientX; },
touchEnd: function (event) {
if (this.data.mode !== 'swipe' || this.touchX == null) return;
var delta = event.changedTouches[0].clientX - this.touchX;
this.touchX = null;
if (Math.abs(delta) < 55) return;
this.choose({ currentTarget: { dataset: { side: delta < 0 ? 'left' : 'right' } } });
},
complete: function () {
var self = this;
var champion = this.state.pool[0];
var finalDecision = this.state.decisions[this.state.decisions.length - 1];
var runnerUpId = finalDecision.left_id === champion.id ? finalDecision.right_id : finalDecision.left_id;
this.setData({ progress: 100, submitting: true });
api.ensureLogin().then(function () {
return api.request('/api/v1/tests/' + self.slug + '/runs', {
method: 'POST',
data: {
app_key: 'hub',
champion_id: champion.id,
runner_up_id: runnerUpId,
ranking_ids: bracket.ranking(self.state),
decisions: self.state.decisions
}
});
}).then(function (result) {
xhs.setStorageSync('pk_last_result', result);
xhs.redirectTo({ url: '/pages/result/result?id=' + result.id });
}).catch(function (error) {
self.choosing = false;
self.setData({ submitting: false });
xhs.showModal({ title: '结果保存失败', content: error.message || '请检查网络后重试', showCancel: false });
});
}
});