/* Standalone interaction prototype. All task/reward data stays in this browser. */ 'use strict'; const $ = (selector) => document.querySelector(selector); const icon = (name) => ``; const escapeHTML = (value) => String(value).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const DAY = 86400000; const STORAGE_KEY = 'pixshaft-referral-prototype-v3'; const tasks = [ {id:'invite', title:'邀请首位好友', category:'好友邀请', tag:'7 天 PRO', days:7, plan:'PRO', icon:'user', color:'lime', description:'好友安装并完成使用要求后,双方各获 7 天 PRO。', target:1, caption:'完成使用要求的好友', steps:['把 Pixiv-Shaft 专属邀请入口分享给一位还没用过 App 的朋友。','好友安装 App、登录并主动绑定邀请,在 7 天内于两个不同自然日使用核心功能;至少完成一次收藏。','系统验证通过后,你与好友各获得一张 7 天体验卡。'], condition:'仅限首次有效邀请。好友无需付费;每位新用户只能绑定一位邀请人。仅复制链接或下载未使用不算完成。'}, {id:'recommend', title:'发布 App 推荐帖', category:'内容推荐', tag:'7 天 PRO', days:7, plan:'PRO', icon:'stack', color:'', description:'发布使用体验,附 App 截图和下载入口。审核通过可获 7 天 PRO。', target:1, caption:'App 推荐帖审核', steps:['在允许推广的社交平台或公开社区,发布一篇 Pixiv-Shaft App 推荐帖。','包含 App 名称、至少 100 字真实使用体验、1 张 App 功能截图,以及官方下载安装入口或专属邀请入口。','说明参与推荐活动可获得体验卡,提交帖子公开链接。审核通过即可领取,无点赞或粉丝数门槛。'], condition:'审核重点是 App 介绍是否真实、下载入口是否有效、推荐帖是否原创且公开可访问。可用官方产品素材配合个人体验;预计 2 个工作日内反馈。'}, {id:'circle', title:'邀请 3 位活跃好友', category:'持续使用', tag:'7 天 MAX', days:7, plan:'MAX', icon:'heart', color:'blue', description:'3 位新用户均达到持续活跃要求后,可获 7 天 MAX。', target:3, caption:'好友达成持续活跃', steps:['通过专属邀请入口,邀请 3 位不同的新用户安装 App 并完成有效体验。','每位好友在加入后的前 14 天内,至少 3 个不同自然日使用核心功能,且有 1 天发生在第 8–14 天。','3 位好友均达标后,领取一张 7 天 MAX 体验卡。'], condition:'首位有效邀请可计入本任务,但需额外满足持续活跃条件。本期仅可完成一次。'}, {id:'tutorial', title:'发布 App 使用教程', category:'使用教程', tag:'7 天 MAX', days:7, plan:'MAX', icon:'play', color:'peach', description:'以图文或视频介绍安装与操作步骤。审核通过可获 7 天 MAX。', target:1, caption:'App 教程审核', steps:['介绍 Pixiv-Shaft 的适用场景、下载安装步骤,以及一项核心功能的操作过程。','发布原创图文(至少 300 字与 3 张 App 操作截图),或不少于 60 秒的 App 实操视频。','附官方下载安装入口或专属邀请入口,说明活动奖励关系,提交公开链接等待审核。'], condition:'不限平台,不要求正面评价或点赞数。教程必须真实可复现,与 App 推荐帖任务不得使用同一份内容。预计 2 个工作日内反馈。'} ]; function freshState(){return {version:3, theme:'light', accent:'violet', effective:1, retained:0, status:{invite:'ready',recommend:'new',tutorial:'new',circle:'progress'}, submissions:{}, wallet:[], activeUntil:0};} let state = freshState(); try {const saved=JSON.parse(localStorage.getItem(STORAGE_KEY)); if(saved?.version===3 && Array.isArray(saved.wallet) && tasks.every(t => ['new','progress','pending','rejected','ready','claimed'].includes(saved.status?.[t.id]))) state={...state,...saved};} catch {} let currentFilter='all', toastTimer, lastTrigger; const sheet=$('#sheet'); function persist(){try{localStorage.setItem(STORAGE_KEY,JSON.stringify(state));}catch{}} function applyTheme(){document.documentElement.dataset.theme=state.theme;document.documentElement.dataset.accent=state.accent;$('[data-action="theme"]').setAttribute('aria-label',state.theme==='dark'?'切换浅色模式':'切换深色模式');$('meta[name="theme-color"]').content=state.theme==='dark'?'#101014':'#f8f7fc';} function toast(message){$('#toast').textContent=message;$('#toast').classList.add('show');clearTimeout(toastTimer);toastTimer=setTimeout(()=>$('#toast').classList.remove('show'),3200);} function openSheet(html){if(!sheet.open)lastTrigger=document.activeElement;$('#sheet-content').innerHTML=html;if(!sheet.open)sheet.showModal();sheet.scrollTop=0;} function closeSheet(){sheet.close();} sheet.addEventListener('close',()=>{if(lastTrigger?.isConnected)lastTrigger.focus({preventScroll:true});}); sheet.addEventListener('click',event=>{if(event.target===sheet){const r=sheet.getBoundingClientRect();if(event.clientXr.right||event.clientYr.bottom)closeSheet();}}); const statusText={new:'未开始',progress:'进行中',pending:'审核中',rejected:'需补充',ready:'可领取',claimed:'已领取'}; const ctaText={new:'查看任务',progress:'查看进度',pending:'查看审核',rejected:'补充内容',ready:'领取奖励',claimed:'查看奖励'}; function taskProgress(task){if(task.id==='invite')return Math.min(state.effective,1);if(task.id==='circle')return Math.min(state.retained,3);return ['ready','claimed'].includes(state.status[task.id])?1:0;} function render(){ applyTheme(); const ready=tasks.filter(t=>state.status[t.id]==='ready').length; $('#earned-days').textContent=state.wallet.reduce((sum,c)=>sum+c.days,0); $('#invited-count').textContent=state.effective; const unused=state.wallet.filter(c=>!c.activatedAt&&c.expiresAt>Date.now()).length; $('#wallet-count').textContent=unused;$('#claimable-count').textContent=ready;$('#ready-count').textContent=ready; document.querySelectorAll('[data-filter]').forEach(button=>{const selected=button.dataset.filter===currentFilter;button.setAttribute('aria-selected',String(selected));button.tabIndex=selected?0:-1;}); $('#task-list').setAttribute('aria-labelledby',`tab-${currentFilter}`); const visible=tasks.filter(t=>currentFilter==='all'||(currentFilter==='ready'?state.status[t.id]==='ready':['progress','pending','rejected'].includes(state.status[t.id]))); $('#task-list').innerHTML=visible.length?visible.map((task,index)=>{ const status=state.status[task.id], progress=taskProgress(task); const caption=status==='pending'?'已提交,等待审核':status==='rejected'?'请补充 App 下载入口与说明':status==='claimed'?'奖励已存入卡包':task.caption; return `
${icon(task.icon)}
${task.category}·${statusText[status]}

${task.title}

${task.description}

${task.days}天${task.plan}
${caption}${progress}/${task.target}
`; }).join(''):`
${icon('spark')}

${currentFilter==='ready'?'暂无可领取奖励':'暂无进行中的任务'}

${currentFilter==='ready'?'任务完成并通过验证后,可在此领取。':'在全部任务中查看参与条件。'}

`; renderWallet();persist(); } function dateText(time){return new Date(time).toLocaleDateString('zh-CN',{year:'numeric',month:'numeric',day:'numeric'});} function dateTimeText(time){return new Date(time).toLocaleString('zh-CN',{year:'numeric',month:'numeric',day:'numeric',hour:'2-digit',minute:'2-digit',hour12:false});} function renderWallet(){ $('#wallet-total').textContent=String(state.wallet.length).padStart(2,'0'); const active=state.activeUntil>Date.now()?`
当前会员体验至 ${dateTimeText(state.activeUntil)}。激活新卡将从此时间顺延。
`:''; $('#wallet-list').innerHTML=state.wallet.length?active+state.wallet.map(card=>{ const expired=!card.activatedAt&&card.expiresAt<=Date.now(); return `

${card.plan} ${card.days} 天体验卡

${card.days} 天

来自「${tasks.find(t=>t.id===card.taskId)?.title||'推荐任务'}」

${card.activatedAt?`已于 ${dateText(card.activatedAt)} 激活 · 权益已顺延`:expired?'已过激活期限':`请于 ${dateTimeText(card.expiresAt)} 前激活`}

${card.activatedAt||expired?`${expired?'已过期':'已激活'}`:``}
`; }).join(''):`
${icon('ticket')}

暂无体验卡

完成推荐任务后即可领取体验卡。
领取后 30 天内激活。

`; } function scrollToSection(section){ const heading=$(section==='wallet'?'#wallet-title':'#section-title'); // Same-page navigation: keep both sections visible and move focus after closing the sheet. lastTrigger=heading; if(sheet.open)closeSheet(); heading.focus({preventScroll:true}); heading.scrollIntoView({behavior:matchMedia('(prefers-reduced-motion: reduce)').matches?'instant':'smooth',block:'start'}); } function showTask(id){ const task=tasks.find(t=>t.id===id);if(!task)return; const status=state.status[id]; if(status==='claimed'){scrollToSection('wallet');return;} if(status==='ready'){showClaim(id);return;} const progress=id==='circle'?`
已有效邀请 ${state.effective} 人,其中 ${state.retained} / 3 人达成持续活跃。仅展示汇总状态,保护好友隐私。
`:''; const review=status==='pending'?'
内容已提交,预计 2 个工作日内反馈。通过后即可领取;若需补充,会展示具体原因。原型中可在「演示控制台」模拟审核结果。
':status==='rejected'?'
需补充:请明确标注 Pixiv-Shaft 名称,补充有效的 App 下载安装入口与活动奖励说明。补充后可重新提交。
':''; openSheet(`
${task.category} · ${task.tag}

${task.title}

${task.days} 天
${task.plan} 体验卡

完成后领取,30 天内自主激活

${progress}${review}

完成条件

    ${task.steps.map(s=>`
  1. ${s}
  2. `).join('')}
${task.condition}
${['recommend','tutorial'].includes(id)?status==='pending'?'':``:``}`); } function showClaim(id){const task=tasks.find(t=>t.id===id);openSheet(`
${icon('check')}
EXPERIENCE PASS

任务已完成

「${task.title}」已完成
可领取 ${task.days} 天 ${task.plan} 体验卡。

${task.days} 天
${task.plan} ${task.days} 天体验卡

激活后开始计时 · 不自动续费

领取后 30 天内激活,可顺延现有体验权益。

`);} function claim(id){if(state.status[id]!=='ready')return;const task=tasks.find(t=>t.id===id);state.status[id]='claimed';state.wallet.push({id:`${id}-${Date.now()}`,taskId:id,plan:task.plan,days:task.days,claimedAt:Date.now(),expiresAt:Date.now()+30*DAY,activatedAt:0});render();openSheet(`
${icon('ticket')}
REWARD CLAIMED

已存入卡包

${task.days} 天 ${task.plan} 体验卡已领取。
激活期限:${dateTimeText(state.wallet.at(-1).expiresAt)}

`);} function showActivate(id){const card=state.wallet.find(c=>c.id===id);if(!card||card.activatedAt)return;if(card.expiresAt<=Date.now()){render();return toast('这张卡已过激活期限');}const end=Math.max(Date.now(),state.activeUntil)+card.days*DAY;openSheet(`
ACTIVATE ${card.plan}

激活 ${card.days} 天 ${card.plan}

${state.activeUntil>Date.now()?'你已有体验权益,新卡会从当前结束时间顺延。':'激活后开始计时。'}
预计体验至 ${dateTimeText(end)}。

本原型只演示权益状态,不会更改真实账号。正式版激活需服务端确认;体验卡不自动续费。
`);} function activate(id){const card=state.wallet.find(c=>c.id===id);if(!card||card.activatedAt)return;if(card.expiresAt<=Date.now()){closeSheet();render();return toast('这张卡已过激活期限');}card.activatedAt=Date.now();state.activeUntil=Math.max(Date.now(),state.activeUntil)+card.days*DAY;render();openSheet(`
${icon('spark')}

已激活

${card.days} 天 ${card.plan} 体验已激活(演示)。
体验至 ${dateTimeText(state.activeUntil)}。

`);} function showInvite(){openSheet(`
INVITE A FRIEND

邀请好友使用 Pixiv-Shaft

首次邀请达标后,双方各获 7 天 PRO。
好友需为新用户,无需付费。

${icon('user')}
双方各获 7 天 PRO

新用户在 7 天内使用 2 天,并完成一次收藏

邀请功能暂未开放。以下文案仅供预览,分享不会计入奖励。
`);} async function copy(textValue){try{await navigator.clipboard.writeText(textValue);const old=$('#copy-status');if(old)old.remove();if(sheet.open){const status=document.createElement('p');status.id='copy-status';status.role='status';status.textContent='文案已复制';status.style.cssText='text-align:center;margin-top:12px;color:var(--primary)';$('#sheet-content').append(status);}else toast('文案已复制');}catch{const box=document.createElement('textarea');box.value=textValue;box.readOnly=true;box.setAttribute('aria-label','可手动复制的文案');box.style.cssText='width:100%;min-height:120px;margin-top:18px';(sheet.open?$('#sheet-content'):document.body).append(box);box.select();if(!sheet.open)toast('无法自动复制,请手动选择复制');}} function showForm(id){const task=tasks.find(t=>t.id===id);const previous=state.submissions[id]||{};openSheet(`
${task.category} · ${task.plan} ${task.days} 天

提交推荐内容

请提供公开链接和内容说明。预计 2 个工作日内完成审核。

`);} document.addEventListener('submit',event=>{if(event.target.id!=='submission-form')return;event.preventDefault();const form=event.target, id=form.dataset.id;let url;try{url=new URL(form.elements.url.value.trim());if(!['https:','http:'].includes(url.protocol)||!url.hostname.includes('.')||url.username||url.password)throw Error();}catch{$('#form-error').textContent='请填写完整、可公开访问的 HTTP 或 HTTPS 推广链接。';return;}const description=form.elements.description.value.trim();if(description.length<20){$('#form-error').textContent='请至少填写 20 字内容介绍。';return;}state.submissions[id]={url:url.href,description,submittedAt:Date.now()};state.status[id]='pending';render();openSheet(`
${icon('check')}

已提交

预计 2 个工作日内反馈,审核通过后即可领取。
原型可在页尾「演示控制台」模拟审核。

`);}); function showRules(){openSheet(`
PROGRAM RULES

活动规则

以下为提议的运营规则,供设计评审确认;原型中的数据和权益均为演示。

`);} function showMaterials(){openSheet(`
SHARE PIXIV-SHAFT

推荐内容参考

可参考以下结构,结合自己的使用体验撰写。发布时需附下载入口,并注明活动奖励。

01 / App 推荐帖

介绍一个用过的功能,附 App 截图、下载入口和活动说明。

02 / 使用教程

说明下载安装步骤,演示至少一项核心功能的操作过程。

03 / 好友邀请

介绍 App 用途,附邀请入口与使用要求。

`);} function showDemo(){openSheet(`
PROTOTYPE CONTROLS

演示控制台

仅改变本浏览器的示例数据,用于评审完整流程。不会发出邀请、提交审核或发放真实会员权益。

有效邀请 ${state.effective} 人新好友达到首次体验条件
持续活跃 ${state.retained} / 3 人不得超过有效邀请人数
${tasks.filter(t=>['recommend','tutorial'].includes(t.id)).map(t=>`
${t.title}${statusText[state.status[t.id]]}
`).join('')}`);} document.addEventListener('click',event=>{ const button=event.target.closest('button');if(!button||button.disabled)return;const d=button.dataset; if(d.scroll){scrollToSection(d.scroll);return;} if(d.filter){currentFilter=d.filter;render();document.querySelector(`[role="tab"][data-filter="${currentFilter}"]`)?.focus();return;} if(d.task){showTask(d.task);return;}if(d.claim){claim(d.claim);return;}if(d.activate){showActivate(d.activate);return;}if(d.confirmActivate){activate(d.confirmActivate);return;}if(d.submitForm){showForm(d.submitForm);return;} if(d.sim){if(d.sim==='invite'){state.effective++;if(state.status.invite!=='claimed')state.status.invite='ready';}else if(state.retained=3&&state.status.circle!=='claimed')state.status.circle='ready';}render();showDemo();return;} if(d.review){const [id,status]=d.review.split(':');if(state.status[id]==='pending')state.status[id]=status;render();showDemo();return;} switch(d.action){ case 'close':closeSheet();break; case 'theme':state.theme=state.theme==='light'?'dark':'light';applyTheme();persist();break; case 'palette':state.accent=['violet','rose','teal'][(['violet','rose','teal'].indexOf(state.accent)+1)%3];applyTheme();persist();toast('已切换主题配色');break; case 'rules':showRules();break; case 'invite':showInvite();break; case 'copy-invite':copy('Pixiv-Shaft 支持浏览插画、管理收藏。首次通过邀请完成使用要求,双方可各获 7 天 PRO。\n[示例文案,邀请活动暂未开放。]');break; case 'invite-progress':openSheet(`
INVITATION STATUS

邀请进度

${state.effective} 人完成有效体验,${state.retained} 人达成持续活跃。
系统仅展示汇总进度,不公开好友的使用明细。

首次有效邀请:${Math.min(state.effective,1)} / 1
3 位好友持续活跃:${state.retained} / 3
邀请进度由服务端验证;本页为演示数据。
`);break; case 'materials':showMaterials();break; case 'copy-promo':copy('Pixiv-Shaft 使用体验\n功能:[介绍实际使用过的功能]\n体验:[优点、不足和适用场景]\n截图:[添加 App 功能截图]\n下载:[填写官方下载或邀请入口]\n活动说明:参与 App 推荐计划,内容审核通过可获得 PRO 体验卡。\n[请补全后发布。当前活动尚未开放。]');break; case 'demo':showDemo();break; case 'reset-confirm':openSheet('
RESET DEMO

重置演示数据?

清空本浏览器的演示推广记录、体验卡与激活记录,恢复初始示例任务。

');break; case 'reset':{const {theme,accent}=state;state={...freshState(),theme,accent};currentFilter='all';render();closeSheet();toast('已恢复初始演示数据');break;} } }); $('.tabs').addEventListener('keydown',event=>{if(!['ArrowLeft','ArrowRight','Home','End'].includes(event.key))return;event.preventDefault();const filters=['all','progress','ready'];let i=filters.indexOf(currentFilter);i=event.key==='Home'?0:event.key==='End'?2:(i+(event.key==='ArrowRight'?1:2))%3;currentFilter=filters[i];render();$(`#tab-${currentFilter}`).focus();}); document.addEventListener('visibilitychange',()=>{if(!document.hidden)render();}); render();