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 +24 -14
- package/index.html +87 -36
- package/ledger.html +25 -15
- package/package.json +1 -1
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)
|
|
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
|
-
|
|
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{'<':'<','>':'>','&':'&','"':'"'}[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="
|
|
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"
|
|
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
|
-
|
|
1178
|
-
|
|
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
|
|
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>
|
|
496
|
-
<div class="who"><b
|
|
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:.
|
|
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:
|
|
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:
|
|
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="
|
|
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+'/'+
|
|
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
|
-
|
|
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=
|
|
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":"
|
|
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
|
|
2423
|
-
|
|
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
|
-
['聚合剂','
|
|
2479
|
-
['异铁组','
|
|
2480
|
-
['加急许可','
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
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{'<':'<','>':'>','&':'&','"':'"'}[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="
|
|
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"
|
|
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
|
-
|
|
2892
|
-
|
|
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
|
|
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 = [
|
|
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)
|
|
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
|
-
|
|
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{'<':'<','>':'>','&':'&','"':'"'}[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="
|
|
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"
|
|
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
|
-
|
|
1138
|
-
|
|
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
|
|
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>
|