function eventIdSet(chapter) { return new Set( Array.isArray(chapter && chapter.events) ? chapter.events.map((event) => event.hotspotId) : [], ) } function normalizeCompletedIds(chapter, completedIds) { const knownIds = eventIdSet(chapter) const seen = new Set() return (Array.isArray(completedIds) ? completedIds : []).filter((id) => { if (!knownIds.has(id) || seen.has(id)) return false seen.add(id) return true }) } function getPeopleProgress(chapter, completedIds) { const knownIds = eventIdSet(chapter) const completed = new Set(normalizeCompletedIds(chapter, completedIds)) const people = Array.isArray(chapter && chapter.people) ? chapter.people : [] return people .map((person) => { const personEventIds = (Array.isArray(person.eventIds) ? person.eventIds : [] ).filter((id) => knownIds.has(id)) const completedForPerson = personEventIds.filter((id) => completed.has(id)) const remaining = personEventIds.length - completedForPerson.length if (!personEventIds.length) return null let markerStatus = '看看' let statusAria = `${person.name}有1处故事细节,可以看看发生了什么` if (remaining === 0) { markerStatus = '看过' statusAria = `${person.name}这一处已经看过` } else if (completedForPerson.length > 0) { markerStatus = '再看看' statusAria = `${person.name}还有${remaining}处细节,可以再看看` } else if (remaining > 1) { markerStatus = `${remaining}处` statusAria = `${person.name}有${remaining}处故事细节` } return { ...person, eventIds: personEventIds, completed: remaining === 0, completedEvents: completedForPerson.length, remaining, markerStatus, statusAria, } }) .filter(Boolean) } function selectNextPerson(people, activeInstanceId) { const active = people.find( (person) => person.instanceId === activeInstanceId && person.remaining > 0, ) if (active) return active const partiallyCompleted = people.find( (person) => person.completedEvents > 0 && person.remaining > 0, ) return partiallyCompleted || people.find((person) => person.remaining > 0) || null } function getChapterProgress( chapter, completedIds, activeInstanceId = '', chapterFinished = false, ) { const normalizedIds = normalizeCompletedIds(chapter, completedIds) const totalEvents = Array.isArray(chapter && chapter.events) ? chapter.events.length : 0 const completedCount = normalizedIds.length const remainingCount = Math.max(0, totalEvents - completedCount) const complete = totalEvents > 0 && remainingCount === 0 const people = getPeopleProgress(chapter, normalizedIds) const nextPerson = complete ? null : selectNextPerson(people, activeInstanceId) const repeatPerson = Boolean( nextPerson && ( nextPerson.completedEvents > 0 || ( activeInstanceId && nextPerson.instanceId === activeInstanceId ) ), ) let nextStepLabel = '下一步' let nextStepText = '看看画中的人物和手边物件,跟着这一回往下走。' let continueLabel = '完成后继续' if (complete) { nextStepLabel = chapterFinished ? '本回已收好' : '4处线索已经看过' nextStepText = chapterFinished ? '这一回已经收进画册,也可以再次打开情感互动。' : '情感互动已经开启,点右侧按钮打开这一页。' continueLabel = '4处线索看完,打开情感互动' } else if (nextPerson && repeatPerson) { nextStepText = `还差${remainingCount}处。再看看${nextPerson.name}的手边。` continueLabel = `下一步:再看看${nextPerson.name}` } else if (nextPerson) { const multiEventNote = nextPerson.remaining > 1 ? ` ${nextPerson.name}身边还有${nextPerson.remaining}处细节。` : '' nextStepText = `还差${remainingCount}处。接着看看${nextPerson.name}。${multiEventNote}` continueLabel = `下一步:看看${nextPerson.name}` } const emotionStatusText = complete ? ( chapterFinished ? '本回已收进画册,可再次打开' : `${totalEvents}处线索已经看过,可以打开` ) : `还差${remainingCount}处线索,看完后开启` return { completedIds: normalizedIds, completedCount, totalEvents, remainingCount, complete, people, nextPerson, nextAction: complete ? 'complete' : (repeatPerson ? 'repeat' : 'next'), nextStepLabel, nextStepText, continueLabel, emotionStatusText, } } module.exports = { normalizeCompletedIds, getPeopleProgress, getChapterProgress, }