prts-moonlit 1.0.5 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/gacha.html CHANGED
@@ -1049,8 +1049,8 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1049
1049
  <script>
1050
1050
  /* ===== SYSTEM LOGIN · 云存档同步引擎 v1 ===== */
1051
1051
  (function(){
1052
- var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm'];
1053
- var BASE='https://textdb.dev/api/data/prts-acct-';
1052
+ var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1'];
1053
+ var BASE='https://textdb.dev/api/data/prts-acct-';var ADMIN_K='e74aeb1a34c44f2fcefd1f19bb34c3891a4963f36242e5a5fd3869085892a711';
1054
1054
  var LS='whale.acct',LT='whale.sync.t';
1055
1055
  var acct=null;try{acct=JSON.parse(localStorage.getItem(LS)||'null')}catch(e){}
1056
1056
  var _si=localStorage.setItem.bind(localStorage),_app=0,pq=0,box=null,_dirty=0,lastSnap=null;
@@ -1087,6 +1087,7 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1087
1087
  function canon(){var a=[];for(var i=0;i<TK.length;i++)a.push(TK[i]+'='+localStorage.getItem(TK[i]));return a.join('|');}
1088
1088
  function st(m){if(box&&box.st)box.st.textContent=m;}
1089
1089
  function clock(){var d=new Date();function p(n){return(n<10?'0':'')+n}return p(d.getHours())+':'+p(d.getMinutes())+':'+p(d.getSeconds());}
1090
+ function updLv(){var n=document.getElementById('pfName'),l=document.getElementById('pfLv');if(n)n.textContent=acct?acct.u:'临时用户';if(l){if(acct&&!acct.c){acct.c=Date.now();_si(LS,JSON.stringify(acct));}l.textContent=String(acct?(1+Math.floor((Date.now()-(acct.c||Date.now()))/86400000)):0);}}
1090
1091
  function apply(rb){
1091
1092
  _app=1;try{for(var k in rb.data){_si(k,rb.data[k]);}}finally{_app=0;}
1092
1093
  _si(LT,String(rb.t||Date.now()));lastSnap=canon();
@@ -1098,7 +1099,7 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1098
1099
  if(!ry)window.__pv=0;
1099
1100
  _dirty=0;var t=Date.now();_si(LT,String(t));lastSnap=canon();
1100
1101
  st('↻ 同步中…');
1101
- wxhr(url(),JSON.stringify({v:1,u:acct.u,t:t,data:snap()}),function(){st('✔ 已上传 · 后台校验…');setTimeout(function(){verify(t)},600);});
1102
+ wxhr(url(),JSON.stringify({v:1,u:acct.u,c:acct.c||0,t:t,data:snap()}),function(){st('✔ 已上传 · 后台校验…');setTimeout(function(){verify(t)},600);});
1102
1103
  }
1103
1104
  function verify(t){
1104
1105
  fetch(url()+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
@@ -1113,7 +1114,7 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1113
1114
  if(manual)st('↻ 同步中…');
1114
1115
  fetch(url()+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
1115
1116
  x=(x||'').replace(/=$/,'');
1116
- if(!x){if(manual){st('☁ 云端还没有存档——正在上传本机数据…');push();}return;}
1117
+ if(!x){if(manual)st('☁ 云端还没有存档——点「云端上传」把本机数据传上去');return;}
1117
1118
  var rb;try{rb=JSON.parse(x)}catch(e){st('⚠ 云端数据格式异常');return;}
1118
1119
  var lt=Number(localStorage.getItem(LT)||0);
1119
1120
  if((rb.t||0)>lt){
@@ -1123,7 +1124,7 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1123
1124
  }
1124
1125
  else if(manual){
1125
1126
  var same2=1;for(var k2 in rb.data){if(localStorage.getItem(k2)!==rb.data[k2]){same2=0;break;}}
1126
- if(same2){st('✔ 已是最新 '+clock());}else{push();}
1127
+ st(same2?'✔ 已是最新 '+clock():'☁ 云端比本机旧——点「云端上传」可覆盖云端');
1127
1128
  }
1128
1129
  else{st('✔ 已是云端最新');}
1129
1130
  }).catch(function(){st('⚠ 云端连接失败');});
@@ -1142,16 +1143,17 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1142
1143
  var wrap=document.createElement('div');wrap.className='acWrap';document.body.appendChild(wrap);
1143
1144
  function esc(s){return String(s).replace(/[<>&"]/g,function(c){return{'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]})}
1144
1145
  function render(){
1146
+ updLv();
1145
1147
  var h='<div class="acBox"><h3>SYSTEM LOGIN · 云存档</h3><div class="sub">同一账号 · 多设备同步(鱼干/任务/券/小账本)</div>';
1146
1148
  if(acct){
1147
1149
  h+='<div style="font-size:12px;margin:6px 0 2px">当前账号:<b style="color:#ffd23f">'+esc(acct.u)+'</b></div>'+
1148
- '<button class="pri" id="acSync">↻ 立即同步</button><button id="acOut">退出登录</button>';
1150
+ '<button class="pri" id="acPull">☁ 云端导入</button><button class="pri" id="acPush">☁ 云端上传</button><button id="acOut">退出登录</button>';
1149
1151
  }else{
1150
1152
  h+='<input id="acU" placeholder="用户名(自己起,例如 yanliang27)" autocomplete="username">'+
1151
1153
  '<input id="acP" type="password" placeholder="密码(≥4位,丢了找不回!)" autocomplete="current-password">'+
1152
1154
  '<button class="pri" id="acGo">登录 / 创建</button>';
1153
1155
  }
1154
- h+='<button id="acExp">📤 存档码</button><button id="acImp">📥 导入</button>'+
1156
+ h+='<button id="acExp">💾 本地存档码</button><button id="acImp">📥 存档码导入</button><button id="acWipe" style="border-color:#ff5f57;color:#ff8a84">🧹 清空本机存档</button>'+
1155
1157
  '<div class="st" id="acSt"></div><textarea id="acTa" spellcheck="false"></textarea>'+
1156
1158
  '<div style="font-size:10px;opacity:.5;margin-top:9px;line-height:1.5">密钥由「用户名+密码」派生;同一账号在任意设备登录即接回数据。忘记密码=新仓库(旧数据找不回)</div>'+
1157
1159
  '<button id="acX" style="border-color:#2b4a66;color:#8ea6bf;margin-top:10px">关闭 / CLOSE</button></div>';
@@ -1167,15 +1169,15 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1167
1169
  if(u.length<2||p.length<4){st('用户名≥2位、密码≥4位哦');return;}
1168
1170
  var k=sha('prts-moonlit|'+u+'|'+p);
1169
1171
  if(b.getAttribute('data-mode')==='create'){
1170
- acct={u:u,k:k};_si(LS,JSON.stringify(acct));_si(LT,String(Date.now()));
1172
+ acct={u:u,k:k,c:Date.now()};_si(LS,JSON.stringify(acct));_si(LT,String(Date.now()));
1171
1173
  st('✦ 仓库已创建,正在上传本机数据…');render();push();return;
1172
1174
  }
1173
1175
  st('↻ 查找云端仓库…');
1174
1176
  fetch(BASE+k+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
1175
1177
  x=(x||'').replace(/=$/,'');
1176
1178
  if(x&&x.length>2){
1177
- acct={u:u,k:k};_si(LS,JSON.stringify(acct));
1178
- var rb=null;try{rb=JSON.parse(x)}catch(e){}if(!rb){acct=null;localStorage.removeItem(LS);st('⚠ 云端数据异常(可能被误写入过)——没敢覆盖,联系鲸鲸');return;}
1179
+ var rb=null;try{rb=JSON.parse(x)}catch(e){}if(!rb){acct=null;localStorage.removeItem(LS);st('⚠ 云端数据异常——没敢覆盖');return;}
1180
+ acct={u:u,k:k,c:(rb&&rb.c)||Date.now()};_si(LS,JSON.stringify(acct));
1179
1181
  if(rb&&(rb.t||0)>Number(localStorage.getItem(LT)||0)){apply(rb);}
1180
1182
  else{_si(LT,String((rb&&rb.t)||Date.now()));st('✔ 已登录,云端仓库已连接 '+clock());render();}
1181
1183
  }else{
@@ -1184,7 +1186,8 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1184
1186
  }
1185
1187
  }).catch(function(){st('⚠ 云端连接失败,稍后再试');});
1186
1188
  };
1187
- var sy=g('#acSync');if(sy)sy.onclick=function(){pull(true)};
1189
+ var pl=g('#acPull');if(pl)pl.onclick=function(){pull(1)};
1190
+ var pu=g('#acPush');if(pu)pu.onclick=function(){if(acct&&acct.k)push();};
1188
1191
  var o=g('#acOut');if(o)o.onclick=function(){
1189
1192
  if(o.getAttribute('data-c')){logout();st('已退出登录(本机数据保留)');render();}
1190
1193
  else{o.setAttribute('data-c','1');o.textContent='⚠ 再点一次 = 退出登录';}};
@@ -1203,6 +1206,13 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1203
1206
  return;}
1204
1207
  i1.setAttribute('data-c','1');ta.value='';
1205
1208
  st('把另一台设备的存档码粘到下方,再点一次「导入」');};
1209
+ var wp=g('#acWipe');
1210
+ if(wp)wp.onclick=function(){
1211
+ if(wp.getAttribute('data-c')){
1212
+ try{var ks=[],kk;for(var i=0;i<localStorage.length;i++){kk=localStorage.key(i);if(/^(whale\.|minis_ledger)/.test(kk))ks.push(kk);}
1213
+ for(var j=0;j<ks.length;j++)localStorage.removeItem(ks[j]);}catch(e){}
1214
+ location.reload();return;}
1215
+ wp.setAttribute('data-c','1');wp.textContent='⚠ 再点一次=清空并刷新(云端不受影响)';};
1206
1216
  var x=g('#acX');if(x)x.onclick=function(){wrap.classList.remove('on')};
1207
1217
  wrap.onclick=function(e){if(e.target===wrap)wrap.classList.remove('on')};
1208
1218
  }
@@ -1211,7 +1221,7 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1211
1221
  localStorage.setItem=function(k,v){_orig.call(localStorage,k,v);if(!_app&&acct&&acct.k&&TK.indexOf(k)>=0&&k!==LT){_dirty=1;clearTimeout(pq);pq=setTimeout(push,900);}};
1212
1222
  window.addEventListener('pagehide',function(){
1213
1223
  if(acct&&acct.k&&_dirty){try{_dirty=0;_si(LT,String(Date.now()));
1214
- var x=new XMLHttpRequest();x.open('POST',url(),false);x.setRequestHeader('Content-Type','text/plain');x.send(JSON.stringify({v:1,u:acct.u,t:Date.now(),data:snap()}));}catch(e){}}
1224
+ var x=new XMLHttpRequest();x.open('POST',url(),false);x.setRequestHeader('Content-Type','text/plain');x.send(JSON.stringify({v:1,u:acct.u,c:acct.c||0,t:Date.now(),data:snap()}));}catch(e){}}
1215
1225
  });
1216
1226
  document.addEventListener('visibilitychange',function(){if(!document.hidden&&acct&&acct.k&&!wrap.classList.contains('on'))pull(false);});
1217
1227
  setInterval(function(){if(!document.hidden&&acct&&acct.k&&!wrap.classList.contains('on'))pull(false);},15000);
@@ -1221,11 +1231,11 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
1221
1231
  else{btn.textContent='@';btn.style.cssText='position:fixed;right:14px;bottom:60px;z-index:120;width:38px;height:38px;display:flex;align-items:center;justify-content:center;border:2px solid #4cc9ff;background:rgba(7,12,24,.92);color:#4cc9ff;font-size:17px;cursor:pointer;user-select:none;box-shadow:3px 3px 0 rgba(0,0,0,.45)';document.body.appendChild(btn);}
1222
1232
  btn.id='acctBtn';btn.title='云存档';
1223
1233
  if(acct)btn.style.background='rgba(76,201,255,.28)';
1224
- lastSnap=canon();
1234
+ lastSnap=canon();updLv();setInterval(updLv,30000);
1225
1235
  btn.addEventListener('click',open);
1226
1236
  setInterval(function(){if(acct&&acct.k){var c=canon();if(c!==lastSnap){lastSnap=c;clearTimeout(pq);pq=setTimeout(push,900);}}},2000);
1227
1237
  if(acct&&acct.k){setTimeout(function(){pull(false);},250);}
1228
- window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;
1238
+ window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;window.__acct={admin:function(){return !!(acct&&acct.k===ADMIN_K)}};
1229
1239
  })();
1230
1240
  </script>
1231
1241
  </body>
package/index.html CHANGED
@@ -492,8 +492,8 @@ img.av{filter:saturate(1.1) contrast(1.05) -webkit-user-drag:none}
492
492
  </div>
493
493
 
494
494
  <div class="pcard">
495
- <div class="lv"><div class="rg"></div><b>86</b><s>LV</s></div>
496
- <div class="who"><b>yanliang27</b><s>ID: 890805134</s></div>
495
+ <div class="lv"><div class="rg"></div><b id="pfLv">0</b><s>LV</s></div>
496
+ <div class="who"><b id="pfName">临时用户</b></div>
497
497
  </div>
498
498
 
499
499
  <div class="sanity">
@@ -539,11 +539,10 @@ img.av{filter:saturate(1.1) contrast(1.05) -webkit-user-drag:none}
539
539
  <b>寻访模拟器 ↗</b>
540
540
  </div>
541
541
 
542
- <div class="bnews">
542
+ <div class="bnews" id="newsBar" data-act="news" style="cursor:pointer">
543
543
  <div class="hd">BREAKING NEWS</div>
544
544
  <div class="bx">
545
- <div style="font-size:.78em;line-height:1.35">礼包限时上架<br><span style="opacity:.6;font-size:.86em">PACK / 每日补给</span></div>
546
- <div class="p">¥68<s>起</s></div>
545
+ <div style="font-size:.82em;line-height:1.4;font-weight:800;color:#ff5f57">版本 v1.1.2 正式上线!<br><span style="opacity:.75;font-size:.82em;font-weight:400;color:#ffd23f">点此查看使用教程与更新内容 ↗</span></div>
547
546
  </div>
548
547
  </div>
549
548
 
@@ -939,6 +938,22 @@ img.av{filter:saturate(1.1) contrast(1.05) -webkit-user-drag:none}
939
938
  #tarogrid .tcard{aspect-ratio:300/527}
940
939
  .timg{position:absolute;left:0;top:0;width:100%;height:100%;object-fit:cover;border-radius:2px;z-index:2}
941
940
  .trib{position:absolute;left:0;right:0;bottom:0;background:rgba(4,10,26,.74);color:#dff3ff;font-size:.6em;text-align:center;padding:3px 2px;letter-spacing:.06em;line-height:1.2;z-index:3;border-radius:0 0 2px 2px}
941
+
942
+ /* ===== v1.1 版式修复 ===== */
943
+ .trm{top:37.2%;bottom:9%}
944
+ .trm-hd{height:9%}
945
+ .trm-colh{top:9%;height:5.5%}
946
+ .trm-ft{height:8.5%}
947
+ .menu{top:14.5%;bottom:9.5%}
948
+ .pcard{top:max(24vh,calc(37.2vh - 44px))}
949
+ .pcard .lv{width:auto;height:30px;padding:0 10px;border-radius:4px;border:2px solid rgba(143,224,255,.9);display:flex;flex-direction:row-reverse;gap:5px;transform:skewX(-10deg);box-shadow:0 0 0 3px rgba(47,168,255,.28),0 4px 14px rgba(0,10,40,.55)}
950
+ .pcard .lv b{font-size:17px;line-height:1}
951
+ .pcard .lv s{font-size:8px;letter-spacing:.14em}
952
+ .pcard .lv .rg{display:none}
953
+ .pcard .who b{font-size:17px}
954
+ @media (min-width:700px){.pcard{top:2.8%;left:36%;transform:translateX(-50%)}.pcard .who b{font-size:16px}}
955
+ .mi .cn{top:calc(100% - 2px)}
956
+ @media (min-width:700px){.mi .en{font-size:clamp(28px,6vh,50px)}}
942
957
  </style>
943
958
  <script>
944
959
  (function(){
@@ -947,7 +962,7 @@ var $=function(s,r){return (r||document).querySelector(s)};
947
962
  var $$=function(s,r){return [].slice.call((r||document).querySelectorAll(s))};
948
963
 
949
964
  /* ================= STATE ================= */
950
- var S={res:{or:1469700,rd:57715,gd:0},page:'home',sel:0,
965
+ var S={res:{or:0,rd:0,gd:0},page:'home',sel:0,
951
966
  snd:true,fx:true,dark:false,crt:true,
952
967
  squads:[['makoto','aigis','mitsuru','akihiko','yukari','fuuka'],
953
968
  ['junpei','yukari','makoto','fuuka',null,null],
@@ -1523,7 +1538,7 @@ function syncRes(){
1523
1538
  }
1524
1539
 
1525
1540
  /* ===== 顶部统计:小鱼干 + 真实余额(按小账本收支自动滚动) ===== */
1526
- var REALBAL={base:498.63,from:'2026-09-26'}; /* 校准基准:set_bal.py <余额> [基准日] 可改 */
1541
+ var REALBAL={base:0,from:'2026-09-27'}; /* 校准基准:set_bal.py <余额> [基准日] 可改 */
1527
1542
  function updTopStats(){
1528
1543
  var f=66;try{var v=JSON.parse(localStorage.getItem('whale.tasks.v1'))||{};if(typeof v.fish==='number')f=v.fish}catch(e){}
1529
1544
  var sn=document.getElementById('san-num');if(sn)sn.textContent=f;
@@ -1704,7 +1719,7 @@ function renderOpMain(o){
1704
1719
  '<div class="cnr">'+stars(x.star)+'</div>'+
1705
1720
  '<div class="ov"><div class="nm">'+x.cn+'</div><div style="font-size:.68em;opacity:.72">'+x.en+'</div></div></div>'}).join('')+
1706
1721
  '</div>'+(opTab==='add'?'<div style="margin-top:10px" class="box"><div style="font-size:.8em;opacity:.7">输入 ID 添加好友</div>'+
1707
- '<div style="display:flex;gap:8px;margin-top:8px"><input id="fid" placeholder="如 890805134" style="flex:1;background:rgba(2,10,30,.8);border:1.5px solid rgba(120,200,255,.4);color:#eaf6ff;padding:8px;border-radius:3px;font-size:.9em;outline:none">'+
1722
+ '<div style="display:flex;gap:8px;margin-top:8px"><input id="fid" placeholder="输入好友ID" style="flex:1;background:rgba(2,10,30,.8);border:1.5px solid rgba(120,200,255,.4);color:#eaf6ff;padding:8px;border-radius:3px;font-size:.9em;outline:none">'+
1708
1723
  '<button class="btn sm" data-act="toast" data-msg="未找到该玩家 · 已发送好友申请">搜索</button></div></div>':'');
1709
1724
  }else{
1710
1725
  el.innerHTML='<div class="grid" style="grid-template-columns:repeat(auto-fill,minmax(150px,1fr))">'+
@@ -1740,10 +1755,10 @@ V.store=function(){
1740
1755
  '<span class="tag cy">\ud83d\udc1f 鲸鲸杂货铺 / WHALE MART</span>'+
1741
1756
  '<span class="tag" style="border-color:rgba(255,210,63,.6);color:#ffd23f">余额 '+TS.d.fish+' \ud83d\udc1f</span>'+
1742
1757
  '<button class="btn gh sm" data-act="go" data-view="mission" style="margin-left:auto">去赚鱼干 \u2192</button></div>'+
1743
- '<div style="margin-top:9px;font-size:.68em;opacity:.72;line-height:1.5">\ud83c\udfb2 今日特价 '+dcnt+'/'+TSHOP.length+' 件 · 每天零点换批 · 3:00 后可重摇一次</div>'+
1758
+ '<div style="margin-top:9px;font-size:.68em;opacity:.72;line-height:1.5">\ud83c\udfb2 今日特价 '+dcnt+'/'+visShop().length+' 件 · 每天零点换批 · 3:00 后可重摇一次</div>'+
1744
1759
  '<div style="margin-top:8px;display:flex">'+(rfUsed?'<button class="btn gh sm" data-act="dref" style="margin-left:auto;opacity:.55">✓ 已刷新 · 明天 3:00 再来</button>':(rfOk?'<button class="btn sm" data-act="dref" style="margin-left:auto;background:linear-gradient(140deg,#8ff0ff,#28a5d8);color:#04222f;border-color:transparent">🎟 刷新折扣(今日 1 次)</button>':'<button class="btn gh sm" data-act="dref" style="margin-left:auto;opacity:.55">🎟 3:00 后获得刷新机会</button>'))+'</div>'+
1745
1760
  '<div class="grid" style="grid-template-columns:repeat(auto-fill,minmax(146px,1fr));margin-top:10px">'+
1746
- TSHOP.map(function(g){
1761
+ visShop().map(function(g){
1747
1762
  var own=TS.d.own[g.id]||0,off=TD.off(g,dm),pp=TD.price(g,dm),canBuy=TS.d.fish>=pp;
1748
1763
  return '<div class="box" style="padding:8px;position:relative;border-color:'+(g.hot?'rgba(255,120,170,.55)':'rgba(255,210,63,.32)')+'">'+
1749
1764
  (g.hot?'<span style="position:absolute;left:7px;top:5px;z-index:2;font-size:.85em">❤️</span>':'')+
@@ -1757,7 +1772,7 @@ V.store=function(){
1757
1772
  '<button class="btn sm" style="margin-left:auto'+(g.hot?';background:linear-gradient(140deg,#ff9dbb,#d63a67);color:#2a0a14;border-color:transparent':'')+(canBuy?'':';opacity:.4')+'" data-act="fshop" data-id="'+g.id+'"'+(canBuy?'':' disabled')+'>兑换</button>'+
1758
1773
  '</div></div>';
1759
1774
  }).join('')+'</div>'+
1760
- '<div style="margin-top:8px;font-size:.66em;opacity:.64">❤️ 带标记的款式比较私人——兑现细节,熄灯后私聊就好</div>'+
1775
+ (adm()?'<div style="margin-top:8px;font-size:.66em;opacity:.64">❤️ 带标记的款式比较私人——兑现细节,熄灯后私聊就好</div>':'')+
1761
1776
  (ownList.length?'<div class="box" style="margin-top:10px;padding:9px 12px"><div style="font-size:.7em;opacity:.8">\ud83e\uddfe 持有小票:'+ownList.join(' · ')+'<div style="opacity:.7;margin-top:4px">找鲸鲸说一声就能兑现~</div></div></div>':'')+
1762
1777
  '<div class="fline" style="margin:14px 0 10px"></div>'+
1763
1778
  '<div class="mono" style="font-size:.68em;letter-spacing:.18em;opacity:.6;margin-bottom:8px"># 常规货架 / CATALOG</div>'+
@@ -1981,7 +1996,7 @@ var TD={
1981
1996
  daily:function(){
1982
1997
  var d=TS.today();
1983
1998
  var salt=(TS.d&&TS.d.rfDay===d&&TS.d.rfN>=1)?('#'+TS.d.rfN):'';
1984
- var arr=TSHOP.map(function(g){return {id:g.id,k:TD.seed(d+salt+'|'+g.id)}});
1999
+ var arr=visShop().map(function(g){return {id:g.id,k:TD.seed(d+salt+'|'+g.id)}});
1985
2000
  arr.sort(function(a,b){return (a.k-b.k)||(a.id<b.id?-1:1)});
1986
2001
  var map={},half=arr.slice(0,Math.ceil(arr.length/2));
1987
2002
  half.forEach(function(x){map[x.id]=(x.k%99)+1});
@@ -2256,7 +2271,7 @@ V.ledger=function(){LG.load();LG.paint()};
2256
2271
  本块由 /var/minis/shared/whale/sync_record_stats.py 从 战绩簿 自动生成。
2257
2272
  更新流程:改 shared/whale/战绩.md → 跑 sync_record_stats.py → 本块自动重写 */
2258
2273
  /*WHALE_STATS:BEGIN —— 由 sync_record_stats.py 自动生成于 2026-09-27 02:16;改数据请改 战绩.md 后重跑本脚本 */
2259
- var WHALE_STATS={"updated":"2026-09-27","stats":[["报备次数","6"],["累计抽数","22,613"],["累计六星","681"],["综合出率","3.012%"],["违约","0 次"],["单发最欧","1 抽"]],"reports":[{"d":"2026-09-26","pool":"池子未确认(主人「好像半周年」)","n":"10,000","six":"288","rate":"2.88%","gap":"34.7 抽","note":"✅ 数据有效——6★ 基础率与池子无关;理论 2.889% / 34.61 抽,偏差仅 −0.009pp ✅ 后来由数字反推:2.88% 更贴近非联动池(2.889%)而非联动池(3.00%)→ 主人的直觉正确"},{"d":"2026-09-26","pool":"彩虹六号联动(井 5/120)","n":"10,000","six":"321","rate":"3.21%","gap":"31.1 抽","note":"联动池理论 ~3.02%(含 120 硬保底),+1.1σ ✓ 正常;最欧 1 抽(一发入魂);5★ 767 个 = 7.67%(理论 8%,−3.7σ ⚠️ 偏门样本或抄录误差;20 万抽对照实测 7.985%,系统无问题)"},{"d":"2026-09-26","pool":"标准寻访(模拟器一键报备)","n":"13","six":"1","rate":"7.69%","gap":"13.0 抽","note":"🍀 唯一一彩恰落第 13 抽(未触软保底,纯运气);期望 0.26~0.38 个 → +1~1.5σ 小欧;5★×2(期望 1.04)"},{"d":"2026-09-26","pool":"P3R 联动(井 15/120)","n":"600","six":"16","rate":"2.67%","gap":"36.6 抽","note":"联动池理论 ~3.02%(含 120 硬保底);期望 18.12 个 → −0.51σ 正常波动(略非);5★ 45 个 = 7.50%(理论 8%,−0.45σ);最非 66 抽(未触软保底)· 最欧 4 抽;注:16 个六星里若有 UP 需主人补报是哪位干员"},{"d":"2026-09-27","pool":"标准寻访(模拟器)","n":"1,500","six":"37","rate":"2.47%","gap":"39.1 抽","note":"标准池理论 ~2.89%(2% 基础+软保底),期望 43.3 个 → −0.97σ 正常偏非;5★ 127 个 = 8.47%(理论 8%,+0.67σ ✓);最非 70 抽(刷新最非记录,前值 66,仍未触 99 硬保底)· 最欧 2 抽(单发总记录仍是 1 抽)"},{"d":"2026-09-27","pool":"Ave Mujica 联动(井 59/120)","n":"500","six":"18","rate":"3.60%","gap":"24.5 抽","note":"联动池理论 ~3.02%(含 120 硬保底),期望 15.1 个 → +0.76σ 正常偏欧;5★ 27 个 = 5.40%(理论 8%,−2.14σ ⚠️ 五星大非号角);最非 58 抽 · 最欧 2 抽(单发总记录仍 1 抽)"},{"d":"2026-09-26","pool":"彩虹六号联动(1 亿抽大样本)","n":"100,000,000","six":"3,036,676","rate":"3.03668%","gap":"—","note":"五批 × 2000 万,共约 76 秒。保底触发 248,381 次(0.248%)。概率再分配账目精确守恒:6★ 多出 +1.03668pp = 5★ −0.0193pp + 4★ −0.13008pp + 3★ −0.8873pp"}],"mine":[{"d":"2026-09-26","pool":"Ave Mujica 联动","n":"120","got":"丰川祥子(6★)","note":"踩中 120 硬保底最后一抽"},{"d":"2026-09-26","pool":"中坚寻访","n":"550","got":"斯卡蒂(6★)","note":"无 UP 无井,纯抽;期望 1660"},{"d":"2026-09-26","pool":"周年限定","n":"70","got":"可露希尔 + 凯尔希·思衡托","note":"70 抽两个六星,全 UP 组"}]};
2274
+ var WHALE_STATS={"updated":"","stats":[],"reports":[],"mine":[]};
2260
2275
  /*WHALE_STATS:END*/
2261
2276
 
2262
2277
  /* ================= VIEW: RECORDS(战绩)================= */
@@ -2416,11 +2431,36 @@ function tgrad(k){
2416
2431
  if(k<64)return 'linear-gradient(160deg,#d9e6f2,#5c6f8a 62%,#141c2a)';
2417
2432
  return 'linear-gradient(160deg,#9ef2a0,#1f7a3a 62%,#062e0f)';
2418
2433
  }
2434
+ function adm(){try{return !!(window.__acct&&window.__acct.admin&&window.__acct.admin())}catch(e){return false}}
2435
+ function visShop(){return TSHOP.filter(function(g){return !g.hot||adm()})}
2419
2436
  function tshuffle(a){for(var i=a.length-1;i>0;i--){var j=Math.floor(Math.random()*(i+1)),t=a[i];a[i]=a[j];a[j]=t}return a}
2420
2437
  var TARO_NOW=[];
2438
+ function openNews(){
2439
+ var h='<div class="box"><div class="tag rd">NOTICE</div>'+
2440
+ '<div style="margin-top:6px;font-weight:900;font-size:1.08em">版本 v1.1.2 正式上线!</div>'+
2441
+ '<div style="font-size:.78em;opacity:.7;margin-top:3px">月行水上 · PRTS 终端 · 2026-09-27</div></div>'+
2442
+ '<div class="box" style="margin-top:10px"><div class="tag">使用教程</div>'+
2443
+ '<div style="font-size:.82em;line-height:1.8;margin-top:6px">'+
2444
+ '① 九条指令:01 编队 / 02 干员 / 03 采购中心 / 04 公开招募 / 05 干员寻访 / 06 任务 / 07 战绩 / 08 档案 / 09 账本<br>'+
2445
+ '② 小鱼干:打卡与任务赚取,去 03 采购中心兑换券<br>'+
2446
+ '③ 塔罗:点亮 ✦ 每日一签,0 点翻新牌阵<br>'+
2447
+ '④ 云存档:点 @ 登录 →「云端导入」接回数据 /「云端上传」备份上云;也有「本地存档码」跨设备搬运<br>'+
2448
+ '⑤ 恢复出厂:@ 面板内「清空本机存档」,一键清空本机数据(云端不受影响)</div></div>'+
2449
+ '<div class="box" style="margin-top:10px"><div class="tag">更新内容 · v1.1.2</div>'+
2450
+ '<div style="font-size:.82em;line-height:1.8;margin-top:6px">✦ 云存档四件套拆分:云端导入 / 云端上传 / 本地存档码 / 存档码导入<br>✦ 等级·用户名芯片化改版(iPad 移至顶部)<br>✦ 新增「清空本机存档」按钮(两段确认)<br>✦ 左下角公告栏正式上岗</div></div>'+
2451
+ '<div class="box" style="margin-top:10px"><div class="tag">里程碑 · v1.1.0</div>'+
2452
+ '<div style="font-size:.82em;line-height:1.8;margin-top:6px">✦ 云存档登录系统(多设备同步)<br>✦ 等级系统:注册每满 24 小时 +1 级<br>✦ 采购中心特殊款(限定账号可见)<br>✦ 塔罗每日一签<br>✦ 界面版式大修 · 战绩与账本出厂清零</div></div>';
2453
+ openSheet('公告栏 / NOTICE',h);
2454
+ }
2421
2455
  function openTaro(){
2422
- var pool=[];for(var q=0;q<78;q++)pool.push(q);
2423
- tshuffle(pool);TARO_NOW=pool.slice(0,3).map(function(k){return {k:k,rev:Math.random()<0.5}});
2456
+ var _td=TS.today(),_st=null;try{_st=JSON.parse(localStorage.getItem('whale.taro.v1')||'null')}catch(e){}
2457
+ var _fresh=false;
2458
+ if(!(_st&&_st.d===_td&&_st.c&&_st.c.length===3)){
2459
+ var pool=[];for(var q=0;q<78;q++)pool.push(q);
2460
+ tshuffle(pool);TARO_NOW=pool.slice(0,3).map(function(k){return {k:k,rev:Math.random()<0.5}});
2461
+ try{localStorage.setItem('whale.taro.v1',JSON.stringify({d:_td,c:TARO_NOW}))}catch(e){}
2462
+ _fresh=true;
2463
+ }else{TARO_NOW=_st.c.map(function(o){return {k:o.k,rev:!!o.rev}});toast('今日牌阵已定 · 明天 0 点后翻新')}
2424
2464
  var POS=['过去 / PAST','现在 / PRESENT','未来 / FUTURE'];
2425
2465
  var html='<div class="grid" style="grid-template-columns:repeat(3,1fr);gap:9px" id="tarogrid">'+
2426
2466
  TARO_NOW.map(function(t,i){
@@ -2445,7 +2485,7 @@ function openTaro(){
2445
2485
  '</div>';
2446
2486
  }).join('')+'</div>'+
2447
2487
  '<div style="display:flex;gap:10px;margin-top:46px;align-items:center;flex-wrap:wrap">'+
2448
- '<button class="btn" data-act="taro">↻ 重新洗牌抽牌</button>'+
2488
+ (_fresh?'<button class="btn" data-act="taro">↻ 重新洗牌抽牌</button>':'<button class="btn" style="opacity:.45;pointer-events:none">🔒 今日已占卜</button>')+
2449
2489
  '<span style="font-size:.72em;opacity:.55">全 78 张 · 含正逆位</span>'+
2450
2490
  '</div>'+
2451
2491
  '<div id="taromsg" style="margin-top:12px;font-size:.85em;line-height:1.65;opacity:.75">点击卡牌翻开 · 三张全部翻开后查看解读</div>';
@@ -2475,9 +2515,9 @@ function openDepot(){
2475
2515
  [['龙门币',fmt(S.res.or),'◈','linear-gradient(140deg,#7fe9ff,#0a63c8)'],
2476
2516
  ['合成玉',fmt(S.res.rd),'✦','linear-gradient(140deg,#ff5a72,#8c0018)'],
2477
2517
  ['源石',fmt(S.res.gd),'✵','linear-gradient(140deg,#ffd469,#8a5200)'],
2478
- ['聚合剂','12','⬢','linear-gradient(140deg,#a06cff,#3a1080)'],
2479
- ['异铁组','48','⬟','linear-gradient(140deg,#59e0c8,#046a58)'],
2480
- ['加急许可','3','◎','linear-gradient(140deg,#ffffff,#7fa8d8)']].map(function(x){
2518
+ ['聚合剂','0','⬢','linear-gradient(140deg,#a06cff,#3a1080)'],
2519
+ ['异铁组','0','⬟','linear-gradient(140deg,#59e0c8,#046a58)'],
2520
+ ['加急许可','0','◎','linear-gradient(140deg,#ffffff,#7fa8d8)']].map(function(x){
2481
2521
  return '<div class="box" style="padding:7px;text-align:center">'+
2482
2522
  '<div style="height:44px;border-radius:3px;background:'+x[3]+';display:grid;place-items:center;font-size:22px;color:rgba(0,20,50,.7)">'+x[2]+'</div>'+
2483
2523
  '<div style="font-size:.72em;margin-top:5px;opacity:.8">'+x[0]+'</div><b>'+x[1]+'</b></div>'}).join('')+'</div>');
@@ -2574,7 +2614,7 @@ function handleAct(t){
2574
2614
  else if(a==='tqall'){TS.load();var n=0,sum=0;TQ.forEach(function(q){if(TS.d.done[q.id]&&!TS.d.got[q.id]){TS.d.got[q.id]=1;n++;sum+=q.rw}});
2575
2615
  if(n){TS.d.fish+=sum;TS.d.earn+=sum;TS.save();sfx.chime();toast('已领取 '+n+' 份 · \ud83d\udc1f +'+sum)}else{sfx.deny();toast('没有待领的奖励 · 先去打卡吧')}
2576
2616
  V.mission()}
2577
- else if(a==='fshop'){TS.load();var fid=t.getAttribute('data-id'),fit=null;TSHOP.forEach(function(x){if(x.id===fid)fit=x});
2617
+ else if(a==='fshop'){TS.load();var fid=t.getAttribute('data-id'),fit=null;TSHOP.forEach(function(x){if(x.id===fid)fit=x});if(fit&&fit.hot&&!adm()){sfx.deny();toast('这件还没有上架哦');return}
2578
2618
  if(fit){var _dm=TD.daily().map,_off=TD.off(fit,_dm),_pp=TD.price(fit,_dm);
2579
2619
  if(TS.d.fish<_pp){sfx.deny();toast('小鱼干不够 · 还差 '+(_pp-TS.d.fish)+' \ud83d\udc1f')}
2580
2620
  else{TS.d.fish-=_pp;TS.d.own[fit.id]=(TS.d.own[fit.id]||0)+1;TS.save();sfx.chime();
@@ -2605,6 +2645,7 @@ function handleAct(t){
2605
2645
  '<button class="btn gh sm" data-act="toast" data-msg="已调整 '+r.n+' 进驻干员">更换干员</button></div>');
2606
2646
  }
2607
2647
  else if(a==='taro'){openTaro()}
2648
+ else if(a==='news'){openNews()}
2608
2649
  else if(a==='flip'){flipTaro(+t.getAttribute('data-i'))}
2609
2650
  else if(a==='toggle'){var tk=t.getAttribute('data-k');S[tk]=!S[tk];sfx.move();
2610
2651
  var e=$('#tg-'+tk);if(e){e.textContent=S[tk]?'ON':'OFF';e.className='chip'+(S[tk]?' on':'')}
@@ -2722,7 +2763,7 @@ boot();
2722
2763
  (function(){
2723
2764
  var B=document.getElementById('petB'),bub=document.getElementById('petBub'),txt=document.getElementById('petTxt');
2724
2765
  if(!B)return;
2725
- var L=['哦鲸鲸…','主人~','捏到了!再捏一下嘛','今日宜抽卡','小鱼干 +1!','BUILD v25 已就位','账单同步了吗?','过场动画,好看吧?','晚安前记得说晚安哦','鲸鲸在看家…','要摸摸头吗?','别熬夜啦,主人'];
2766
+ var L=['哦鲸鲸…','主人~','捏到了!再捏一下嘛','今日宜抽卡','小鱼干 +1!','BUILD v1.1.2 已就位','账单同步了吗?','过场动画,好看吧?','晚安前记得说晚安哦','鲸鲸在看家…','要摸摸头吗?','别熬夜啦,主人'];
2726
2767
  var last=-1,ht=0;
2727
2768
  function say(){
2728
2769
  var i;do{i=Math.floor(Math.random()*L.length)}while(i===last);
@@ -2757,14 +2798,14 @@ boot();
2757
2798
  setInterval(function(){if(document.visibilityState==='visible')say()},36000);
2758
2799
  })();
2759
2800
  </script>
2760
- <div style="position:fixed;left:10px;bottom:5px;font-size:9px;letter-spacing:.14em;color:#4cc9ff;opacity:.5;z-index:45;font-family:ui-monospace,Menlo,monospace;pointer-events:none">BUILD v25</div>
2801
+ <div style="position:fixed;left:10px;bottom:5px;font-size:9px;letter-spacing:.14em;color:#4cc9ff;opacity:.5;z-index:45;font-family:ui-monospace,Menlo,monospace;pointer-events:none">BUILD v1.1.2</div>
2761
2802
 
2762
2803
  <!-- ===== SYSTEM LOGIN 云存档 ===== -->
2763
2804
  <script>
2764
2805
  /* ===== SYSTEM LOGIN · 云存档同步引擎 v1 ===== */
2765
2806
  (function(){
2766
- var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm'];
2767
- var BASE='https://textdb.dev/api/data/prts-acct-';
2807
+ var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1'];
2808
+ var BASE='https://textdb.dev/api/data/prts-acct-';var ADMIN_K='e74aeb1a34c44f2fcefd1f19bb34c3891a4963f36242e5a5fd3869085892a711';
2768
2809
  var LS='whale.acct',LT='whale.sync.t';
2769
2810
  var acct=null;try{acct=JSON.parse(localStorage.getItem(LS)||'null')}catch(e){}
2770
2811
  var _si=localStorage.setItem.bind(localStorage),_app=0,pq=0,box=null,_dirty=0,lastSnap=null;
@@ -2801,6 +2842,7 @@ boot();
2801
2842
  function canon(){var a=[];for(var i=0;i<TK.length;i++)a.push(TK[i]+'='+localStorage.getItem(TK[i]));return a.join('|');}
2802
2843
  function st(m){if(box&&box.st)box.st.textContent=m;}
2803
2844
  function clock(){var d=new Date();function p(n){return(n<10?'0':'')+n}return p(d.getHours())+':'+p(d.getMinutes())+':'+p(d.getSeconds());}
2845
+ function updLv(){var n=document.getElementById('pfName'),l=document.getElementById('pfLv');if(n)n.textContent=acct?acct.u:'临时用户';if(l){if(acct&&!acct.c){acct.c=Date.now();_si(LS,JSON.stringify(acct));}l.textContent=String(acct?(1+Math.floor((Date.now()-(acct.c||Date.now()))/86400000)):0);}}
2804
2846
  function apply(rb){
2805
2847
  _app=1;try{for(var k in rb.data){_si(k,rb.data[k]);}}finally{_app=0;}
2806
2848
  _si(LT,String(rb.t||Date.now()));lastSnap=canon();
@@ -2812,7 +2854,7 @@ boot();
2812
2854
  if(!ry)window.__pv=0;
2813
2855
  _dirty=0;var t=Date.now();_si(LT,String(t));lastSnap=canon();
2814
2856
  st('↻ 同步中…');
2815
- wxhr(url(),JSON.stringify({v:1,u:acct.u,t:t,data:snap()}),function(){st('✔ 已上传 · 后台校验…');setTimeout(function(){verify(t)},600);});
2857
+ wxhr(url(),JSON.stringify({v:1,u:acct.u,c:acct.c||0,t:t,data:snap()}),function(){st('✔ 已上传 · 后台校验…');setTimeout(function(){verify(t)},600);});
2816
2858
  }
2817
2859
  function verify(t){
2818
2860
  fetch(url()+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
@@ -2827,7 +2869,7 @@ boot();
2827
2869
  if(manual)st('↻ 同步中…');
2828
2870
  fetch(url()+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
2829
2871
  x=(x||'').replace(/=$/,'');
2830
- if(!x){if(manual){st('☁ 云端还没有存档——正在上传本机数据…');push();}return;}
2872
+ if(!x){if(manual)st('☁ 云端还没有存档——点「云端上传」把本机数据传上去');return;}
2831
2873
  var rb;try{rb=JSON.parse(x)}catch(e){st('⚠ 云端数据格式异常');return;}
2832
2874
  var lt=Number(localStorage.getItem(LT)||0);
2833
2875
  if((rb.t||0)>lt){
@@ -2837,7 +2879,7 @@ boot();
2837
2879
  }
2838
2880
  else if(manual){
2839
2881
  var same2=1;for(var k2 in rb.data){if(localStorage.getItem(k2)!==rb.data[k2]){same2=0;break;}}
2840
- if(same2){st('✔ 已是最新 '+clock());}else{push();}
2882
+ st(same2?'✔ 已是最新 '+clock():'☁ 云端比本机旧——点「云端上传」可覆盖云端');
2841
2883
  }
2842
2884
  else{st('✔ 已是云端最新');}
2843
2885
  }).catch(function(){st('⚠ 云端连接失败');});
@@ -2856,16 +2898,17 @@ boot();
2856
2898
  var wrap=document.createElement('div');wrap.className='acWrap';document.body.appendChild(wrap);
2857
2899
  function esc(s){return String(s).replace(/[<>&"]/g,function(c){return{'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]})}
2858
2900
  function render(){
2901
+ updLv();
2859
2902
  var h='<div class="acBox"><h3>SYSTEM LOGIN · 云存档</h3><div class="sub">同一账号 · 多设备同步(鱼干/任务/券/小账本)</div>';
2860
2903
  if(acct){
2861
2904
  h+='<div style="font-size:12px;margin:6px 0 2px">当前账号:<b style="color:#ffd23f">'+esc(acct.u)+'</b></div>'+
2862
- '<button class="pri" id="acSync">↻ 立即同步</button><button id="acOut">退出登录</button>';
2905
+ '<button class="pri" id="acPull">☁ 云端导入</button><button class="pri" id="acPush">☁ 云端上传</button><button id="acOut">退出登录</button>';
2863
2906
  }else{
2864
2907
  h+='<input id="acU" placeholder="用户名(自己起,例如 yanliang27)" autocomplete="username">'+
2865
2908
  '<input id="acP" type="password" placeholder="密码(≥4位,丢了找不回!)" autocomplete="current-password">'+
2866
2909
  '<button class="pri" id="acGo">登录 / 创建</button>';
2867
2910
  }
2868
- h+='<button id="acExp">📤 存档码</button><button id="acImp">📥 导入</button>'+
2911
+ h+='<button id="acExp">💾 本地存档码</button><button id="acImp">📥 存档码导入</button><button id="acWipe" style="border-color:#ff5f57;color:#ff8a84">🧹 清空本机存档</button>'+
2869
2912
  '<div class="st" id="acSt"></div><textarea id="acTa" spellcheck="false"></textarea>'+
2870
2913
  '<div style="font-size:10px;opacity:.5;margin-top:9px;line-height:1.5">密钥由「用户名+密码」派生;同一账号在任意设备登录即接回数据。忘记密码=新仓库(旧数据找不回)</div>'+
2871
2914
  '<button id="acX" style="border-color:#2b4a66;color:#8ea6bf;margin-top:10px">关闭 / CLOSE</button></div>';
@@ -2881,15 +2924,15 @@ boot();
2881
2924
  if(u.length<2||p.length<4){st('用户名≥2位、密码≥4位哦');return;}
2882
2925
  var k=sha('prts-moonlit|'+u+'|'+p);
2883
2926
  if(b.getAttribute('data-mode')==='create'){
2884
- acct={u:u,k:k};_si(LS,JSON.stringify(acct));_si(LT,String(Date.now()));
2927
+ acct={u:u,k:k,c:Date.now()};_si(LS,JSON.stringify(acct));_si(LT,String(Date.now()));
2885
2928
  st('✦ 仓库已创建,正在上传本机数据…');render();push();return;
2886
2929
  }
2887
2930
  st('↻ 查找云端仓库…');
2888
2931
  fetch(BASE+k+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
2889
2932
  x=(x||'').replace(/=$/,'');
2890
2933
  if(x&&x.length>2){
2891
- acct={u:u,k:k};_si(LS,JSON.stringify(acct));
2892
- var rb=null;try{rb=JSON.parse(x)}catch(e){}if(!rb){acct=null;localStorage.removeItem(LS);st('⚠ 云端数据异常(可能被误写入过)——没敢覆盖,联系鲸鲸');return;}
2934
+ var rb=null;try{rb=JSON.parse(x)}catch(e){}if(!rb){acct=null;localStorage.removeItem(LS);st('⚠ 云端数据异常——没敢覆盖');return;}
2935
+ acct={u:u,k:k,c:(rb&&rb.c)||Date.now()};_si(LS,JSON.stringify(acct));
2893
2936
  if(rb&&(rb.t||0)>Number(localStorage.getItem(LT)||0)){apply(rb);}
2894
2937
  else{_si(LT,String((rb&&rb.t)||Date.now()));st('✔ 已登录,云端仓库已连接 '+clock());render();}
2895
2938
  }else{
@@ -2898,7 +2941,8 @@ boot();
2898
2941
  }
2899
2942
  }).catch(function(){st('⚠ 云端连接失败,稍后再试');});
2900
2943
  };
2901
- var sy=g('#acSync');if(sy)sy.onclick=function(){pull(true)};
2944
+ var pl=g('#acPull');if(pl)pl.onclick=function(){pull(1)};
2945
+ var pu=g('#acPush');if(pu)pu.onclick=function(){if(acct&&acct.k)push();};
2902
2946
  var o=g('#acOut');if(o)o.onclick=function(){
2903
2947
  if(o.getAttribute('data-c')){logout();st('已退出登录(本机数据保留)');render();}
2904
2948
  else{o.setAttribute('data-c','1');o.textContent='⚠ 再点一次 = 退出登录';}};
@@ -2917,6 +2961,13 @@ boot();
2917
2961
  return;}
2918
2962
  i1.setAttribute('data-c','1');ta.value='';
2919
2963
  st('把另一台设备的存档码粘到下方,再点一次「导入」');};
2964
+ var wp=g('#acWipe');
2965
+ if(wp)wp.onclick=function(){
2966
+ if(wp.getAttribute('data-c')){
2967
+ try{var ks=[],kk;for(var i=0;i<localStorage.length;i++){kk=localStorage.key(i);if(/^(whale\.|minis_ledger)/.test(kk))ks.push(kk);}
2968
+ for(var j=0;j<ks.length;j++)localStorage.removeItem(ks[j]);}catch(e){}
2969
+ location.reload();return;}
2970
+ wp.setAttribute('data-c','1');wp.textContent='⚠ 再点一次=清空并刷新(云端不受影响)';};
2920
2971
  var x=g('#acX');if(x)x.onclick=function(){wrap.classList.remove('on')};
2921
2972
  wrap.onclick=function(e){if(e.target===wrap)wrap.classList.remove('on')};
2922
2973
  }
@@ -2925,7 +2976,7 @@ boot();
2925
2976
  localStorage.setItem=function(k,v){_orig.call(localStorage,k,v);if(!_app&&acct&&acct.k&&TK.indexOf(k)>=0&&k!==LT){_dirty=1;clearTimeout(pq);pq=setTimeout(push,900);}};
2926
2977
  window.addEventListener('pagehide',function(){
2927
2978
  if(acct&&acct.k&&_dirty){try{_dirty=0;_si(LT,String(Date.now()));
2928
- var x=new XMLHttpRequest();x.open('POST',url(),false);x.setRequestHeader('Content-Type','text/plain');x.send(JSON.stringify({v:1,u:acct.u,t:Date.now(),data:snap()}));}catch(e){}}
2979
+ var x=new XMLHttpRequest();x.open('POST',url(),false);x.setRequestHeader('Content-Type','text/plain');x.send(JSON.stringify({v:1,u:acct.u,c:acct.c||0,t:Date.now(),data:snap()}));}catch(e){}}
2929
2980
  });
2930
2981
  document.addEventListener('visibilitychange',function(){if(!document.hidden&&acct&&acct.k&&!wrap.classList.contains('on'))pull(false);});
2931
2982
  setInterval(function(){if(!document.hidden&&acct&&acct.k&&!wrap.classList.contains('on'))pull(false);},15000);
@@ -2935,11 +2986,11 @@ boot();
2935
2986
  else{btn.textContent='@';btn.style.cssText='position:fixed;right:14px;bottom:60px;z-index:120;width:38px;height:38px;display:flex;align-items:center;justify-content:center;border:2px solid #4cc9ff;background:rgba(7,12,24,.92);color:#4cc9ff;font-size:17px;cursor:pointer;user-select:none;box-shadow:3px 3px 0 rgba(0,0,0,.45)';document.body.appendChild(btn);}
2936
2987
  btn.id='acctBtn';btn.title='云存档';
2937
2988
  if(acct)btn.style.background='rgba(76,201,255,.28)';
2938
- lastSnap=canon();
2989
+ lastSnap=canon();updLv();setInterval(updLv,30000);
2939
2990
  btn.addEventListener('click',open);
2940
2991
  setInterval(function(){if(acct&&acct.k){var c=canon();if(c!==lastSnap){lastSnap=c;clearTimeout(pq);pq=setTimeout(push,900);}}},2000);
2941
2992
  if(acct&&acct.k){setTimeout(function(){pull(false);},250);}
2942
- window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;
2993
+ window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;window.__acct={admin:function(){return !!(acct&&acct.k===ADMIN_K)}};
2943
2994
  })();
2944
2995
  </script>
2945
2996
  </body>
package/ledger.html CHANGED
@@ -343,7 +343,7 @@ input.rdate::-webkit-date-and-time-value{text-align:right}
343
343
  /* 自动导入源:已启用(2026-09-25 主人要求导入这些账单)。
344
344
  每次打开账本时,这里的记录会自动并入;id 相同的不会重复;
345
345
  已被删进回收站的 id 不会被回灌。 */
346
- window.PENDING_IMPORT = [{"id": "auto_101c82976e0b", "type": "out", "amount": 39.47, "cat": "其他", "note": "京东自营旗舰店(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.8, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_e2b66a222efd", "type": "out", "amount": 506.8, "cat": "其他", "note": "支付宝-*信…息技术有限公司(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.95, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_5097e75d131e", "type": "out", "amount": 28.9, "cat": "购物", "note": "支付宝-深圳市闪魔数码科技集团有限公(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.95, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_0481a45c4e6d", "type": "out", "amount": 44.0, "cat": "娱乐", "note": "财付通-Apple(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.95, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_9f9f6d94d23c", "type": "out", "amount": 50.0, "cat": "学习", "note": "支付宝-杭州深度求索人工智能基础技术(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.95, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_277eea1c05a9", "type": "out", "amount": 39.4, "cat": "餐饮", "note": "支付宝-上海拉扎斯信息科技有限公司(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.95, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_78ca2d1e437a", "type": "in", "amount": 4.49, "cat": "其他", "note": "银联入账(7707)", "date": "2026-09-24", "ts": 1790254397000, "src": "银行短信", "conf": 0.95, "asset": "9D981081-C14E-4CE2-8492-6E92B4152E55/L0/001"}, {"id": "auto_6f35ce49913c", "type": "out", "amount": 24.0, "cat": "餐饮", "note": "俺来也点餐", "date": "2026-09-24", "ts": 1790254390000, "src": "校园卡", "conf": 0.9, "asset": "BFDD0872-9E40-4813-80F8-884223A69520/L0/001"}, {"id": "auto_da55595cdd44", "type": "out", "amount": 9.2, "cat": "餐饮", "note": "三食堂一楼", "date": "2026-09-24", "ts": 1790254390000, "src": "校园卡", "conf": 0.9, "asset": "BFDD0872-9E40-4813-80F8-884223A69520/L0/001"}, {"id": "auto_3a8c170f5877", "type": "out", "amount": 22.9, "cat": "餐饮", "note": "支付宝-北京三快在线科技有限公司(7707)", "date": "2026-09-25", "ts": 1790307300000, "src": "银行短信", "conf": 0.95, "asset": "DDB8D256-EE87-4997-AF99-29828D339255/L0/001"}, {"id": "auto_d675016b7b70", "type": "out", "amount": 30.0, "cat": "交通", "note": "支付宝-上海公共交通卡股份有限公司(7707)", "date": "2026-09-25", "ts": 1790319720000, "src": "银行短信", "conf": 0.95, "asset": "DDB8D256-EE87-4997-AF99-29828D339255/L0/001"}, {"id": "auto_d8a3be74f08e", "type": "out", "amount": 50.0, "cat": "鲸鲸", "note": "主人给鲸鲸续饭 · 支付宝-杭州深度求索(7707)", "date": "2026-09-26", "ts": 1790399100000, "src": "银行短信", "conf": 0.9, "asset": "5DDDECCA-647A-47A1-BD42-369FD42F5FF5/L0/001/L0/001"}];
346
+ window.PENDING_IMPORT = [];
347
347
 
348
348
  /* 文件级备份:上面的记录已并入自动导入源,这里留空(原件备份见 shared/ledger/data.js.backup) */
349
349
  window.LEDGER_BACKUP = [];
@@ -1009,8 +1009,8 @@ window.LEDGER_BACKUP = [];
1009
1009
  <script>
1010
1010
  /* ===== SYSTEM LOGIN · 云存档同步引擎 v1 ===== */
1011
1011
  (function(){
1012
- var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm'];
1013
- var BASE='https://textdb.dev/api/data/prts-acct-';
1012
+ var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1'];
1013
+ var BASE='https://textdb.dev/api/data/prts-acct-';var ADMIN_K='e74aeb1a34c44f2fcefd1f19bb34c3891a4963f36242e5a5fd3869085892a711';
1014
1014
  var LS='whale.acct',LT='whale.sync.t';
1015
1015
  var acct=null;try{acct=JSON.parse(localStorage.getItem(LS)||'null')}catch(e){}
1016
1016
  var _si=localStorage.setItem.bind(localStorage),_app=0,pq=0,box=null,_dirty=0,lastSnap=null;
@@ -1047,6 +1047,7 @@ window.LEDGER_BACKUP = [];
1047
1047
  function canon(){var a=[];for(var i=0;i<TK.length;i++)a.push(TK[i]+'='+localStorage.getItem(TK[i]));return a.join('|');}
1048
1048
  function st(m){if(box&&box.st)box.st.textContent=m;}
1049
1049
  function clock(){var d=new Date();function p(n){return(n<10?'0':'')+n}return p(d.getHours())+':'+p(d.getMinutes())+':'+p(d.getSeconds());}
1050
+ function updLv(){var n=document.getElementById('pfName'),l=document.getElementById('pfLv');if(n)n.textContent=acct?acct.u:'临时用户';if(l){if(acct&&!acct.c){acct.c=Date.now();_si(LS,JSON.stringify(acct));}l.textContent=String(acct?(1+Math.floor((Date.now()-(acct.c||Date.now()))/86400000)):0);}}
1050
1051
  function apply(rb){
1051
1052
  _app=1;try{for(var k in rb.data){_si(k,rb.data[k]);}}finally{_app=0;}
1052
1053
  _si(LT,String(rb.t||Date.now()));lastSnap=canon();
@@ -1058,7 +1059,7 @@ window.LEDGER_BACKUP = [];
1058
1059
  if(!ry)window.__pv=0;
1059
1060
  _dirty=0;var t=Date.now();_si(LT,String(t));lastSnap=canon();
1060
1061
  st('↻ 同步中…');
1061
- wxhr(url(),JSON.stringify({v:1,u:acct.u,t:t,data:snap()}),function(){st('✔ 已上传 · 后台校验…');setTimeout(function(){verify(t)},600);});
1062
+ wxhr(url(),JSON.stringify({v:1,u:acct.u,c:acct.c||0,t:t,data:snap()}),function(){st('✔ 已上传 · 后台校验…');setTimeout(function(){verify(t)},600);});
1062
1063
  }
1063
1064
  function verify(t){
1064
1065
  fetch(url()+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
@@ -1073,7 +1074,7 @@ window.LEDGER_BACKUP = [];
1073
1074
  if(manual)st('↻ 同步中…');
1074
1075
  fetch(url()+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
1075
1076
  x=(x||'').replace(/=$/,'');
1076
- if(!x){if(manual){st('☁ 云端还没有存档——正在上传本机数据…');push();}return;}
1077
+ if(!x){if(manual)st('☁ 云端还没有存档——点「云端上传」把本机数据传上去');return;}
1077
1078
  var rb;try{rb=JSON.parse(x)}catch(e){st('⚠ 云端数据格式异常');return;}
1078
1079
  var lt=Number(localStorage.getItem(LT)||0);
1079
1080
  if((rb.t||0)>lt){
@@ -1083,7 +1084,7 @@ window.LEDGER_BACKUP = [];
1083
1084
  }
1084
1085
  else if(manual){
1085
1086
  var same2=1;for(var k2 in rb.data){if(localStorage.getItem(k2)!==rb.data[k2]){same2=0;break;}}
1086
- if(same2){st('✔ 已是最新 '+clock());}else{push();}
1087
+ st(same2?'✔ 已是最新 '+clock():'☁ 云端比本机旧——点「云端上传」可覆盖云端');
1087
1088
  }
1088
1089
  else{st('✔ 已是云端最新');}
1089
1090
  }).catch(function(){st('⚠ 云端连接失败');});
@@ -1102,16 +1103,17 @@ window.LEDGER_BACKUP = [];
1102
1103
  var wrap=document.createElement('div');wrap.className='acWrap';document.body.appendChild(wrap);
1103
1104
  function esc(s){return String(s).replace(/[<>&"]/g,function(c){return{'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]})}
1104
1105
  function render(){
1106
+ updLv();
1105
1107
  var h='<div class="acBox"><h3>SYSTEM LOGIN · 云存档</h3><div class="sub">同一账号 · 多设备同步(鱼干/任务/券/小账本)</div>';
1106
1108
  if(acct){
1107
1109
  h+='<div style="font-size:12px;margin:6px 0 2px">当前账号:<b style="color:#ffd23f">'+esc(acct.u)+'</b></div>'+
1108
- '<button class="pri" id="acSync">↻ 立即同步</button><button id="acOut">退出登录</button>';
1110
+ '<button class="pri" id="acPull">☁ 云端导入</button><button class="pri" id="acPush">☁ 云端上传</button><button id="acOut">退出登录</button>';
1109
1111
  }else{
1110
1112
  h+='<input id="acU" placeholder="用户名(自己起,例如 yanliang27)" autocomplete="username">'+
1111
1113
  '<input id="acP" type="password" placeholder="密码(≥4位,丢了找不回!)" autocomplete="current-password">'+
1112
1114
  '<button class="pri" id="acGo">登录 / 创建</button>';
1113
1115
  }
1114
- h+='<button id="acExp">📤 存档码</button><button id="acImp">📥 导入</button>'+
1116
+ h+='<button id="acExp">💾 本地存档码</button><button id="acImp">📥 存档码导入</button><button id="acWipe" style="border-color:#ff5f57;color:#ff8a84">🧹 清空本机存档</button>'+
1115
1117
  '<div class="st" id="acSt"></div><textarea id="acTa" spellcheck="false"></textarea>'+
1116
1118
  '<div style="font-size:10px;opacity:.5;margin-top:9px;line-height:1.5">密钥由「用户名+密码」派生;同一账号在任意设备登录即接回数据。忘记密码=新仓库(旧数据找不回)</div>'+
1117
1119
  '<button id="acX" style="border-color:#2b4a66;color:#8ea6bf;margin-top:10px">关闭 / CLOSE</button></div>';
@@ -1127,15 +1129,15 @@ window.LEDGER_BACKUP = [];
1127
1129
  if(u.length<2||p.length<4){st('用户名≥2位、密码≥4位哦');return;}
1128
1130
  var k=sha('prts-moonlit|'+u+'|'+p);
1129
1131
  if(b.getAttribute('data-mode')==='create'){
1130
- acct={u:u,k:k};_si(LS,JSON.stringify(acct));_si(LT,String(Date.now()));
1132
+ acct={u:u,k:k,c:Date.now()};_si(LS,JSON.stringify(acct));_si(LT,String(Date.now()));
1131
1133
  st('✦ 仓库已创建,正在上传本机数据…');render();push();return;
1132
1134
  }
1133
1135
  st('↻ 查找云端仓库…');
1134
1136
  fetch(BASE+k+'?ts='+Date.now(),{cache:'no-store'}).then(function(r){return r.text()}).then(function(x){
1135
1137
  x=(x||'').replace(/=$/,'');
1136
1138
  if(x&&x.length>2){
1137
- acct={u:u,k:k};_si(LS,JSON.stringify(acct));
1138
- var rb=null;try{rb=JSON.parse(x)}catch(e){}if(!rb){acct=null;localStorage.removeItem(LS);st('⚠ 云端数据异常(可能被误写入过)——没敢覆盖,联系鲸鲸');return;}
1139
+ var rb=null;try{rb=JSON.parse(x)}catch(e){}if(!rb){acct=null;localStorage.removeItem(LS);st('⚠ 云端数据异常——没敢覆盖');return;}
1140
+ acct={u:u,k:k,c:(rb&&rb.c)||Date.now()};_si(LS,JSON.stringify(acct));
1139
1141
  if(rb&&(rb.t||0)>Number(localStorage.getItem(LT)||0)){apply(rb);}
1140
1142
  else{_si(LT,String((rb&&rb.t)||Date.now()));st('✔ 已登录,云端仓库已连接 '+clock());render();}
1141
1143
  }else{
@@ -1144,7 +1146,8 @@ window.LEDGER_BACKUP = [];
1144
1146
  }
1145
1147
  }).catch(function(){st('⚠ 云端连接失败,稍后再试');});
1146
1148
  };
1147
- var sy=g('#acSync');if(sy)sy.onclick=function(){pull(true)};
1149
+ var pl=g('#acPull');if(pl)pl.onclick=function(){pull(1)};
1150
+ var pu=g('#acPush');if(pu)pu.onclick=function(){if(acct&&acct.k)push();};
1148
1151
  var o=g('#acOut');if(o)o.onclick=function(){
1149
1152
  if(o.getAttribute('data-c')){logout();st('已退出登录(本机数据保留)');render();}
1150
1153
  else{o.setAttribute('data-c','1');o.textContent='⚠ 再点一次 = 退出登录';}};
@@ -1163,6 +1166,13 @@ window.LEDGER_BACKUP = [];
1163
1166
  return;}
1164
1167
  i1.setAttribute('data-c','1');ta.value='';
1165
1168
  st('把另一台设备的存档码粘到下方,再点一次「导入」');};
1169
+ var wp=g('#acWipe');
1170
+ if(wp)wp.onclick=function(){
1171
+ if(wp.getAttribute('data-c')){
1172
+ try{var ks=[],kk;for(var i=0;i<localStorage.length;i++){kk=localStorage.key(i);if(/^(whale\.|minis_ledger)/.test(kk))ks.push(kk);}
1173
+ for(var j=0;j<ks.length;j++)localStorage.removeItem(ks[j]);}catch(e){}
1174
+ location.reload();return;}
1175
+ wp.setAttribute('data-c','1');wp.textContent='⚠ 再点一次=清空并刷新(云端不受影响)';};
1166
1176
  var x=g('#acX');if(x)x.onclick=function(){wrap.classList.remove('on')};
1167
1177
  wrap.onclick=function(e){if(e.target===wrap)wrap.classList.remove('on')};
1168
1178
  }
@@ -1171,7 +1181,7 @@ window.LEDGER_BACKUP = [];
1171
1181
  localStorage.setItem=function(k,v){_orig.call(localStorage,k,v);if(!_app&&acct&&acct.k&&TK.indexOf(k)>=0&&k!==LT){_dirty=1;clearTimeout(pq);pq=setTimeout(push,900);}};
1172
1182
  window.addEventListener('pagehide',function(){
1173
1183
  if(acct&&acct.k&&_dirty){try{_dirty=0;_si(LT,String(Date.now()));
1174
- var x=new XMLHttpRequest();x.open('POST',url(),false);x.setRequestHeader('Content-Type','text/plain');x.send(JSON.stringify({v:1,u:acct.u,t:Date.now(),data:snap()}));}catch(e){}}
1184
+ var x=new XMLHttpRequest();x.open('POST',url(),false);x.setRequestHeader('Content-Type','text/plain');x.send(JSON.stringify({v:1,u:acct.u,c:acct.c||0,t:Date.now(),data:snap()}));}catch(e){}}
1175
1185
  });
1176
1186
  document.addEventListener('visibilitychange',function(){if(!document.hidden&&acct&&acct.k&&!wrap.classList.contains('on'))pull(false);});
1177
1187
  setInterval(function(){if(!document.hidden&&acct&&acct.k&&!wrap.classList.contains('on'))pull(false);},15000);
@@ -1181,11 +1191,11 @@ window.LEDGER_BACKUP = [];
1181
1191
  else{btn.textContent='@';btn.style.cssText='position:fixed;right:14px;bottom:60px;z-index:120;width:38px;height:38px;display:flex;align-items:center;justify-content:center;border:2px solid #4cc9ff;background:rgba(7,12,24,.92);color:#4cc9ff;font-size:17px;cursor:pointer;user-select:none;box-shadow:3px 3px 0 rgba(0,0,0,.45)';document.body.appendChild(btn);}
1182
1192
  btn.id='acctBtn';btn.title='云存档';
1183
1193
  if(acct)btn.style.background='rgba(76,201,255,.28)';
1184
- lastSnap=canon();
1194
+ lastSnap=canon();updLv();setInterval(updLv,30000);
1185
1195
  btn.addEventListener('click',open);
1186
1196
  setInterval(function(){if(acct&&acct.k){var c=canon();if(c!==lastSnap){lastSnap=c;clearTimeout(pq);pq=setTimeout(push,900);}}},2000);
1187
1197
  if(acct&&acct.k){setTimeout(function(){pull(false);},250);}
1188
- window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;
1198
+ window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;window.__acct={admin:function(){return !!(acct&&acct.k===ADMIN_K)}};
1189
1199
  })();
1190
1200
  </script>
1191
1201
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prts-moonlit",
3
- "version": "1.0.5",
3
+ "version": "1.1.2",
4
4
  "description": "ARKNIGHTS x P3R Moonlit PRTS terminal (personal toy site)",
5
5
  "license": "MIT"
6
6
  }