prts-moonlit 1.2.0 → 1.2.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 +200 -5
- package/index.html +237 -21
- package/ledger.html +227 -4
- package/package.json +1 -1
package/gacha.html
CHANGED
|
@@ -553,7 +553,7 @@ function buildUI(){
|
|
|
553
553
|
'<span class="chip'+(DEDUPE.on?' on':'')+'" data-act="dedupe" id="dedupe-chip">防重复 '+(DEDUPE.on?'ON':'OFF')+'</span>'+
|
|
554
554
|
'<button class="btn gh sm" data-act="newpool">开启新池</button>'+
|
|
555
555
|
'<button class="btn gh sm" data-act="reset">重置统计</button>'+
|
|
556
|
-
'<button class="btn gh sm" data-act="report"
|
|
556
|
+
'<button class="btn gh sm" data-act="report">📮 一键报备</button></span></div>'+
|
|
557
557
|
'<div style="display:flex;gap:9px;flex-wrap:wrap">'+
|
|
558
558
|
'<button class="btn gold" data-act="p1">寻访 ×1</button>'+
|
|
559
559
|
'<button class="btn gold" data-act="p10">寻访 ×10</button>'+
|
|
@@ -882,7 +882,7 @@ document.addEventListener('click',function(e){
|
|
|
882
882
|
if(!_ok && navigator.clipboard && navigator.clipboard.writeText){
|
|
883
883
|
try{ navigator.clipboard.writeText(_r); _ok=true; }catch(e){}
|
|
884
884
|
}
|
|
885
|
-
if(_ok){ toast('已复制 ✓
|
|
885
|
+
if(_ok){ sfx.tap(); mbPostG('战绩',_r,function(uok){ toast(uok?'📮 已一键报备 ✓ 鲸鲸会从云端收取(也复制了一份)':'已复制 ✓ 云端没送达——直接发鲸鲸也行'); }); }
|
|
886
886
|
else{
|
|
887
887
|
var _ov=document.createElement('div');
|
|
888
888
|
_ov.style.cssText='position:fixed;left:12px;right:12px;bottom:92px;z-index:9999;background:#0b1730;border:2px solid #4cc9ff;padding:12px;font-size:12px;color:#dff2ff;word-break:break-all;line-height:1.7';
|
|
@@ -1049,7 +1049,7 @@ 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','whale.taro.v1','whale.ai.cfg.v1','whale.ai.psn.v1','whale.ai.chat.v1','whale.ai.memo.v1'];
|
|
1052
|
+
var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1','whale.ai.cfg.v1','whale.ai.psn.v1','whale.ai.chat.v1','whale.ai.memo.v1','whale.bal.v1'];
|
|
1053
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){}
|
|
@@ -1083,6 +1083,52 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
|
|
|
1083
1083
|
}
|
|
1084
1084
|
function snap(){var d={};for(var i=0;i<TK.length;i++){var v=localStorage.getItem(TK[i]);if(v!==null)d[TK[i]]=v;}return d;}
|
|
1085
1085
|
function url(){return BASE+acct.k;}
|
|
1086
|
+
function mbFetch(cb){
|
|
1087
|
+
try{
|
|
1088
|
+
var x=new XMLHttpRequest();x.open('GET','https://textdb.dev/api/data/prts-myb-mailbox?ts='+Date.now(),true);x.timeout=20000;
|
|
1089
|
+
x.onload=function(){try{var cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[];if(!(cur instanceof Array))cur=[];cb(cur)}catch(e){cb(null)}};
|
|
1090
|
+
x.onerror=function(){cb(null)};x.send();
|
|
1091
|
+
}catch(e){cb(null)}
|
|
1092
|
+
}
|
|
1093
|
+
function mbEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
|
|
1094
|
+
function mbRender(){
|
|
1095
|
+
var In=document.getElementById('mbIn');if(!In)return;
|
|
1096
|
+
if(!(window.__acct&&window.__acct.admin&&window.__acct.admin())){
|
|
1097
|
+
In.innerHTML='<div style="font-size:10px;opacity:.65">📬 收件箱 · 仅主人可见(先用你的账号登录再来看)</div>';return;
|
|
1098
|
+
}
|
|
1099
|
+
In.innerHTML='<div style="font-size:10px;opacity:.7">⏳ 收信中…</div>';
|
|
1100
|
+
mbFetch(function(list){
|
|
1101
|
+
var In2=document.getElementById('mbIn');if(!In2)return;
|
|
1102
|
+
if(list===null){In2.innerHTML='<div style="font-size:10px;opacity:.7">⚠ 收信失败 <button id="mbRe" style="font-size:10px">重试</button></div>';bindRe();return;}
|
|
1103
|
+
var h='<div style="font-size:11px;opacity:.85;margin-bottom:6px">📬 收件箱 <span style="opacity:.55;font-size:10px">共 '+list.length+' 封</span><button id="mbRe" style="float:right;font-size:10px">↻ 刷新</button></div>';
|
|
1104
|
+
for(var i=0;i<list.length;i++){var m=list[i]||{};var d=new Date(m.ts||0);
|
|
1105
|
+
var ts=('0'+(d.getMonth()+1)).slice(-2)+'-'+('0'+d.getDate()).slice(-2)+' '+('0'+d.getHours()).slice(-2)+':'+('0'+d.getMinutes()).slice(-2);
|
|
1106
|
+
h+='<div style="border:1px solid #1d3550;border-radius:3px;padding:6px 8px;margin-bottom:5px;background:#0a1220"><div style="font-size:10px;opacity:.75"><b style="color:'+(m.k==='战绩'?'#ffd66b':'#8ff0d0')+'">'+(m.k==='战绩'?'⚔ 战绩':'📮 意见')+'</b> · '+ts+'</div><div style="font-size:11px;color:#dff1ff;margin-top:3px;white-space:pre-wrap;word-break:break-word">'+mbEsc(m.t||'')+'</div></div>';
|
|
1107
|
+
}
|
|
1108
|
+
if(!list.length)h+='<div style="font-size:10px;opacity:.6">还没有来信~</div>';
|
|
1109
|
+
In2.innerHTML=h;bindRe();
|
|
1110
|
+
function bindRe(){var r3=document.getElementById('mbRe');if(r3)r3.onclick=function(){mbRender();};}
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
function mbPost(kind,txt,cb){
|
|
1114
|
+
var u='https://textdb.dev/api/data/prts-myb-mailbox';
|
|
1115
|
+
try{
|
|
1116
|
+
var x=new XMLHttpRequest();x.open('GET',u+'?ts='+Date.now(),true);x.timeout=15000;
|
|
1117
|
+
x.onload=function(){
|
|
1118
|
+
var cur=[];try{cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[]}catch(e){cur=[]}
|
|
1119
|
+
if(!(cur instanceof Array))cur=[];
|
|
1120
|
+
cur.unshift({k:kind,t:txt,ts:Date.now()});
|
|
1121
|
+
if(cur.length>200)cur.length=200;
|
|
1122
|
+
try{
|
|
1123
|
+
var y=new XMLHttpRequest();y.open('POST',u,true);y.timeout=20000;y.setRequestHeader('Content-Type','text/plain');
|
|
1124
|
+
y.onload=y.onerror=y.ontimeout=function(){if(cb&&!y._d){y._d=1;cb(true)}};
|
|
1125
|
+
y.send(JSON.stringify(cur));
|
|
1126
|
+
}catch(e){if(cb)cb(false)}
|
|
1127
|
+
};
|
|
1128
|
+
x.onerror=function(){if(cb)cb(false)};
|
|
1129
|
+
x.send();
|
|
1130
|
+
}catch(e){if(cb)cb(false)}
|
|
1131
|
+
}
|
|
1086
1132
|
function wxhr(u,b,cb){try{var x=new XMLHttpRequest();x.open('POST',u,true);x.setRequestHeader('Content-Type','text/plain');x.onload=x.onerror=x.ontimeout=function(){if(cb)cb()};x.send(b);}catch(e){if(cb)cb();}}
|
|
1087
1133
|
function canon(){var a=[];for(var i=0;i<TK.length;i++)a.push(TK[i]+'='+localStorage.getItem(TK[i]));return a.join('|');}
|
|
1088
1134
|
function st(m){if(box&&box.st)box.st.textContent=m;}
|
|
@@ -1154,7 +1200,16 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
|
|
|
1154
1200
|
'<button class="pri" id="acGo">登录 / 创建</button>';
|
|
1155
1201
|
}
|
|
1156
1202
|
h+='<button id="acExp">💾 本地存档码</button><button id="acImp">📥 存档码导入</button><button id="acWipe" style="border-color:#ff5f57;color:#ff8a84">🧹 清空本机存档</button>'+
|
|
1203
|
+
'<button id="acFb" style="border-color:#ffd23f;color:#ffd66b">📮 意见箱</button>'+
|
|
1204
|
+
'<button id="vbBtn" style="border-color:#7fe0c0;color:#8ff0d0">🔐 本地密码本</button>'+
|
|
1205
|
+
(window.__acct&&window.__acct.admin&&window.__acct.admin()?'<button id="mbBtn" style="border-color:#9fd0ff;color:#c8e4ff">📬 收件箱</button>':'')+
|
|
1157
1206
|
'<div class="st" id="acSt"></div><textarea id="acTa" spellcheck="false"></textarea>'+
|
|
1207
|
+
'<div id="fbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px">'+
|
|
1208
|
+
'<div style="font-size:11px;opacity:.78;margin-bottom:5px">📮 意见箱 · 内容直达云端信箱(可匿名),鲸鲸会定期收信</div>'+
|
|
1209
|
+
'<textarea id="fbTxt" spellcheck="false" style="display:block;height:64px" placeholder="想说的话、想要的更新、发现的 bug……"></textarea>'+
|
|
1210
|
+
'<div style="margin-top:6px"><button id="fbSend" style="border-color:#ffd23f;color:#ffd66b">寄到云端</button><span id="fbSt" style="font-size:10px;opacity:.75;margin-left:8px"></span></div></div>'+
|
|
1211
|
+
'<div id="vbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px"><div id="vbIn"></div></div>'+
|
|
1212
|
+
'<div id="mbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px"><div id="mbIn"></div></div>'+
|
|
1158
1213
|
'<div style="font-size:10px;opacity:.5;margin-top:9px;line-height:1.5">密钥由「用户名+密码」派生;同一账号在任意设备登录即接回数据。忘记密码=新仓库(旧数据找不回)</div>'+
|
|
1159
1214
|
'<button id="acX" style="border-color:#2b4a66;color:#8ea6bf;margin-top:10px">关闭 / CLOSE</button></div>';
|
|
1160
1215
|
wrap.innerHTML=h;
|
|
@@ -1209,10 +1264,20 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
|
|
|
1209
1264
|
var wp=g('#acWipe');
|
|
1210
1265
|
if(wp)wp.onclick=function(){
|
|
1211
1266
|
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);}
|
|
1267
|
+
try{var ks=[],kk;for(var i=0;i<localStorage.length;i++){kk=localStorage.key(i);if(/^(whale\.|minis_ledger)/.test(kk)&&kk.indexOf('whale.vault')!==0)ks.push(kk);}
|
|
1213
1268
|
for(var j=0;j<ks.length;j++)localStorage.removeItem(ks[j]);}catch(e){}
|
|
1214
1269
|
location.reload();return;}
|
|
1215
1270
|
wp.setAttribute('data-c','1');wp.textContent='⚠ 再点一次=清空并刷新(云端不受影响)';};
|
|
1271
|
+
var fb=g('#acFb');if(fb)fb.onclick=function(){var b=g('#fbBox');if(b)b.style.display=(!b.style.display||b.style.display==='none')?'block':'none';};
|
|
1272
|
+
var fs=g('#fbSend');if(fs)fs.onclick=function(){
|
|
1273
|
+
var t=g('#fbTxt'),t2=t?String(t.value||'').trim():'',st2=g('#fbSt');
|
|
1274
|
+
if(!t2){if(st2)st2.textContent='先写点什么呀';return}
|
|
1275
|
+
if(t2.length>600)t2=t2.slice(0,600);
|
|
1276
|
+
if(st2)st2.textContent='寄送中…';
|
|
1277
|
+
mbPost('意见',t2,function(ok){if(st2)st2.textContent=ok?'✅ 已寄出,谢谢!鲸鲸会看到的':'⚠ 寄送失败,稍后再试';if(ok&&t)t.value='';});
|
|
1278
|
+
};
|
|
1279
|
+
var mbb=g('#mbBtn');if(mbb)mbb.onclick=function(){var b=g('#mbBox');if(!b)return;var op=(!b.style.display||b.style.display==='none');b.style.display=op?'block':'none';if(op)mbRender();};
|
|
1280
|
+
var vbb=g('#vbBtn');if(vbb)vbb.onclick=function(){var b=g('#vbBox');if(!b)return;var op=(!b.style.display||b.style.display==='none');b.style.display=op?'block':'none';if(op){vbLoad();vbRender();}};
|
|
1216
1281
|
var x=g('#acX');if(x)x.onclick=function(){wrap.classList.remove('on')};
|
|
1217
1282
|
wrap.onclick=function(e){if(e.target===wrap)wrap.classList.remove('on')};
|
|
1218
1283
|
}
|
|
@@ -1235,8 +1300,138 @@ document.addEventListener('pointerdown',function(){ac()},{once:true});
|
|
|
1235
1300
|
btn.addEventListener('click',open);
|
|
1236
1301
|
setInterval(function(){if(acct&&acct.k){var c=canon();if(c!==lastSnap){lastSnap=c;clearTimeout(pq);pq=setTimeout(push,900);}}},2000);
|
|
1237
1302
|
if(acct&&acct.k){setTimeout(function(){pull(false);},250);}
|
|
1238
|
-
|
|
1303
|
+
var APP_VER='1.2.2';
|
|
1304
|
+
function _verCmp(a,b){var x=String(a).split('.'),y=String(b).split('.');for(var i=0;i<3;i++){var p=parseInt(x[i]||'0',10),q=parseInt(y[i]||'0',10);if(p!==q)return p-q}return 0}
|
|
1305
|
+
function chkVer(){
|
|
1306
|
+
try{
|
|
1307
|
+
var x=new XMLHttpRequest();x.open('GET','https://unpkg.com/prts-moonlit/package.json?ts='+Date.now(),true);x.timeout=15000;
|
|
1308
|
+
x.onload=function(){
|
|
1309
|
+
try{
|
|
1310
|
+
var rv=(JSON.parse(x.responseText)||{}).version;if(!rv)return;
|
|
1311
|
+
if(_verCmp(rv,APP_VER)<=0)return;
|
|
1312
|
+
if(sessionStorage.getItem('verNag')===rv)return;sessionStorage.setItem('verNag',rv);
|
|
1313
|
+
var d=document.createElement('div');
|
|
1314
|
+
d.textContent='✨ 新版本 '+rv+' 已上线 —— 点此刷新更新';
|
|
1315
|
+
d.style.cssText='position:fixed;left:50%;top:max(10px,env(safe-area-inset-top));transform:translateX(-50%);z-index:9999;background:rgba(7,12,24,.96);border:2px solid #ffd23f;color:#ffe9a8;font:600 13px ui-monospace,Menlo,monospace;padding:10px 15px;box-shadow:0 8px 28px rgba(0,0,0,.55);cursor:pointer';
|
|
1316
|
+
d.onclick=function(){location.reload()};
|
|
1317
|
+
document.body.appendChild(d);
|
|
1318
|
+
}catch(e){}
|
|
1319
|
+
};
|
|
1320
|
+
x.send();
|
|
1321
|
+
}catch(e){}
|
|
1322
|
+
}
|
|
1323
|
+
setTimeout(chkVer,2600);
|
|
1324
|
+
setInterval(chkVer,600000);
|
|
1325
|
+
/* ===== 🔐 本地密码本(whale.vault.v1 · 只存本机 · 不入同步/存档码/清空存档)===== */
|
|
1326
|
+
var VBK='whale.vault.v1',vbMem=null,vbEdit=-1;
|
|
1327
|
+
function vbRead(){try{return JSON.parse(localStorage.getItem(VBK)||'null')}catch(e){return null}}
|
|
1328
|
+
function vbSave(o){try{localStorage.setItem(VBK,JSON.stringify(o));return 1}catch(e){return 0}}
|
|
1329
|
+
function vbCache(s){try{if(s===null)sessionStorage.removeItem('whale.vault.un');else sessionStorage.setItem('whale.vault.un',s)}catch(e){}}
|
|
1330
|
+
function vbCached(){try{return sessionStorage.getItem('whale.vault.un')||''}catch(e){return ''}}
|
|
1331
|
+
function vbSalt(){var s='',h='0123456789abcdef';for(var i=0;i<16;i++)s+=h.charAt(Math.floor(Math.random()*16));return s;}
|
|
1332
|
+
function vbKey(pass,salt,iter){var x=salt+'|'+pass;for(var i=0;i<iter;i++)x=sha(x);return x;}
|
|
1333
|
+
function vbXor(s,key){var o='';for(var b=0;b<s.length;b+=32){var blk=sha(key+'|'+(b/32|0));
|
|
1334
|
+
for(var j=0;j<32&&b+j<s.length;j++)o+=String.fromCharCode(s.charCodeAt(b+j)^parseInt(blk.substr(j*2,2),16));}return o;}
|
|
1335
|
+
function vbEnc(t,key){return btoa(vbXor(unescape(encodeURIComponent(t)),key));}
|
|
1336
|
+
function vbDec(c,key){return decodeURIComponent(escape(vbXor(atob(c),key)));}
|
|
1337
|
+
function vbEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}
|
|
1338
|
+
function vbMsg(t){var m=document.getElementById('vbMsg');if(m)m.textContent=t;}
|
|
1339
|
+
function vbCopy(t){var ok=0;try{navigator.clipboard.writeText(t);ok=1}catch(e){}
|
|
1340
|
+
if(!ok){try{var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.focus();ta.select();ok=document.execCommand('copy');document.body.removeChild(ta)}catch(e2){}}
|
|
1341
|
+
return ok;}
|
|
1342
|
+
function vbLoad(){
|
|
1343
|
+
var v=vbRead();if(!v){return}
|
|
1344
|
+
if(!v.lock){vbMem={list:(v.list||[]),key:''};return}
|
|
1345
|
+
var ck=vbCached();if(!ck){vbMem=null;return}
|
|
1346
|
+
try{vbMem={list:JSON.parse(vbDec(v.blob,ck)),key:ck}}catch(e){vbCache(null);vbMem=null}
|
|
1347
|
+
}
|
|
1348
|
+
function vbPersist(){
|
|
1349
|
+
var v=vbRead();if(!v||!vbMem)return;
|
|
1350
|
+
if(v.lock){v.blob=vbEnc(JSON.stringify(vbMem.list),vbMem.key)}
|
|
1351
|
+
else{v.list=vbMem.list}
|
|
1352
|
+
vbSave(v);
|
|
1353
|
+
}
|
|
1354
|
+
function vbRender(){
|
|
1355
|
+
var In=document.getElementById('vbIn');if(!In)return;
|
|
1356
|
+
var v=vbRead(),h='';
|
|
1357
|
+
if(!v){
|
|
1358
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:5px">🔐 本地密码本 · <span style="opacity:.55;font-size:10px">只存本机 · 永不云同步 · 不随存档导出</span></div>'
|
|
1359
|
+
+'<div style="font-size:10px;opacity:.6;margin-bottom:6px">第一次使用:设一个主口令(留空 = 不加锁)</div>'
|
|
1360
|
+
+'<input id="vbPass" type="password" placeholder="主口令(可留空)" style="width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:7px 9px;font:12px ui-monospace,Menlo,monospace">'
|
|
1361
|
+
+'<div style="margin-top:6px"><button id="vbGo" style="border-color:#7fe0c0;color:#8ff0d0">创建密码本</button><span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div>';
|
|
1362
|
+
In.innerHTML=h;
|
|
1363
|
+
document.getElementById('vbGo').onclick=function(){
|
|
1364
|
+
var p=(document.getElementById('vbPass')||{}).value||'';
|
|
1365
|
+
if(!p){vbSave({v:1,lock:0,list:[]});vbMem={list:[],key:''};vbRender();return}
|
|
1366
|
+
var salt=vbSalt(),iter=3000,key=vbKey(p,salt,iter);
|
|
1367
|
+
vbSave({v:1,lock:1,salt:salt,iter:iter,blob:vbEnc('[]',key)});
|
|
1368
|
+
vbCache(key);vbMem={list:[],key:key};vbRender();
|
|
1369
|
+
};
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
if(v.lock&&!vbMem){
|
|
1373
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:5px">🔐 本地密码本 · <b style="color:#ffd23f">已锁定</b></div>'
|
|
1374
|
+
+'<input id="vbPass" type="password" placeholder="主口令" style="width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:7px 9px;font:12px ui-monospace,Menlo,monospace">'
|
|
1375
|
+
+'<div style="margin-top:6px"><button id="vbGo" style="border-color:#7fe0c0;color:#8ff0d0">解锁</button><span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div>';
|
|
1376
|
+
In.innerHTML=h;
|
|
1377
|
+
document.getElementById('vbGo').onclick=function(){
|
|
1378
|
+
var p=(document.getElementById('vbPass')||{}).value||'';
|
|
1379
|
+
var key=vbKey(p,v.salt,v.iter||3000);
|
|
1380
|
+
try{vbMem={list:JSON.parse(vbDec(v.blob,key)),key:key};vbCache(key);vbRender();}
|
|
1381
|
+
catch(e){vbMsg('口令不对,再试试');}
|
|
1382
|
+
};
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
var L=(vbMem&&vbMem.list)||[],ed=vbEdit;
|
|
1386
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:6px">🔐 本地密码本 <span style="opacity:.55;font-size:10px">只存本机 · '+L.length+' 条'+(v.lock?' · 已上锁':'')+'</span>';
|
|
1387
|
+
if(v.lock)h+='<button id="vbLock" style="float:right;font-size:10px;border-color:#ffd23f;color:#ffd66b">🔒 锁定</button>';
|
|
1388
|
+
h+='</div>';
|
|
1389
|
+
for(var i=0;i<L.length;i++){var e=L[i];
|
|
1390
|
+
h+='<div style="border:1px solid #1d3550;border-radius:3px;padding:6px 8px;margin-bottom:5px;background:#0a1220">'
|
|
1391
|
+
+'<div style="font-size:11px;color:#dff1ff"><b>'+vbEsc(e.n||'(未命名)')+'</b>'+(e.a?' · <span style="opacity:.55">'+vbEsc(e.a)+'</span>':'')+'</div>'
|
|
1392
|
+
+'<div style="font:11px ui-monospace,Menlo,monospace;color:#8ff0d0;margin-top:2px;word-break:break-all">'+vbEsc(e.p||'')+'</div>'
|
|
1393
|
+
+(e.r?'<div style="font-size:10px;opacity:.6;margin-top:2px">'+vbEsc(e.r)+'</div>':'')
|
|
1394
|
+
+'<div style="margin-top:4px"><button data-vbc="'+i+'" style="font-size:10px">复制</button> <button data-vbe="'+i+'" style="font-size:10px">编辑</button> <button data-vbr="'+i+'" style="font-size:10px;border-color:#ff5f57;color:#ff8a84">删除</button></div></div>';
|
|
1395
|
+
}
|
|
1396
|
+
if(!L.length)h+='<div style="font-size:10px;opacity:.6;margin-bottom:6px">还空着——从下面加第一条吧</div>';
|
|
1397
|
+
var E=(ed>=0&&L[ed])?L[ed]:{n:'',a:'',p:'',r:''};
|
|
1398
|
+
var IS='width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:6px 8px;font:12px ui-monospace,Menlo,monospace;margin-top:4px';
|
|
1399
|
+
h+='<div style="border-top:1px dashed #2b4a66;padding-top:7px"><div style="font-size:10px;opacity:.65">'+(ed>=0?'编辑条目':'新增条目')+'</div>'
|
|
1400
|
+
+'<input id="vbN" value="'+vbEsc(E.n)+'" placeholder="名称(必填)· 例:DeepSeek API Key" style="'+IS+'">'
|
|
1401
|
+
+'<input id="vbA" value="'+vbEsc(E.a)+'" placeholder="账号(可空)" style="'+IS+'">'
|
|
1402
|
+
+'<input id="vbP" value="'+vbEsc(E.p)+'" placeholder="密码 / 密钥(必填)" style="'+IS+'">'
|
|
1403
|
+
+'<input id="vbR" value="'+vbEsc(E.r)+'" placeholder="备注(可空)" style="'+IS+'">'
|
|
1404
|
+
+'<div style="margin-top:6px"><button id="vbSv" style="border-color:#7fe0c0;color:#8ff0d0">'+(ed>=0?'保存修改':'+ 添加')+'</button>'+(ed>=0?' <button id="vbCn">取消编辑</button>':'')
|
|
1405
|
+
+'<span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div></div>';
|
|
1406
|
+
In.innerHTML=h;
|
|
1407
|
+
var lk=document.getElementById('vbLock');if(lk)lk.onclick=function(){vbCache(null);vbMem=null;vbRender();};
|
|
1408
|
+
for(var k2=0;k2<L.length;k2++){(function(idx){
|
|
1409
|
+
var c=In.querySelector('[data-vbc="'+idx+'"]');
|
|
1410
|
+
if(c)c.onclick=function(){vbMsg(vbCopy(L[idx].p||'')?'已复制 ✓':'复制失败,长按手动复制')};
|
|
1411
|
+
var eb2=In.querySelector('[data-vbe="'+idx+'"]');
|
|
1412
|
+
if(eb2)eb2.onclick=function(){vbEdit=idx;vbRender();};
|
|
1413
|
+
var rm=In.querySelector('[data-vbr="'+idx+'"]');
|
|
1414
|
+
if(rm)rm.onclick=function(){if(rm.getAttribute('data-arm')!=='1'){rm.setAttribute('data-arm','1');rm.textContent='再点=删除';return}L.splice(idx,1);vbPersist();vbEdit=-1;vbRender();};
|
|
1415
|
+
})(k2);}
|
|
1416
|
+
var sv=document.getElementById('vbSv');
|
|
1417
|
+
if(sv)sv.onclick=function(){
|
|
1418
|
+
var n=((document.getElementById('vbN')||{}).value||'').trim();
|
|
1419
|
+
var a=((document.getElementById('vbA')||{}).value||'').trim();
|
|
1420
|
+
var p=((document.getElementById('vbP')||{}).value||'').trim();
|
|
1421
|
+
var r=((document.getElementById('vbR')||{}).value||'').trim();
|
|
1422
|
+
if(!n){vbMsg('写个名称吧');return}
|
|
1423
|
+
if(!p){vbMsg('密码/密钥别忘了填');return}
|
|
1424
|
+
var it={n:n,a:a,p:p,r:r,ts:Date.now()};
|
|
1425
|
+
if(vbEdit>=0&&L[vbEdit])L[vbEdit]=it;else L.push(it);
|
|
1426
|
+
vbPersist();vbEdit=-1;vbMsg('已保存 ✓');
|
|
1427
|
+
setTimeout(function(){vbRender()},350);
|
|
1428
|
+
};
|
|
1429
|
+
var cn=document.getElementById('vbCn');
|
|
1430
|
+
if(cn)cn.onclick=function(){vbEdit=-1;vbRender();};
|
|
1431
|
+
}
|
|
1432
|
+
window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;window.__acct={admin:function(){return !!(acct&&acct.k===ADMIN_K)}};
|
|
1239
1433
|
})();
|
|
1240
1434
|
</script>
|
|
1435
|
+
<script>function mbPostG(kind,txt,cb){var u='https://textdb.dev/api/data/prts-myb-mailbox';try{var x=new XMLHttpRequest();x.open('GET',u+'?ts='+Date.now(),true);x.timeout=15000;x.onload=function(){var cur=[];try{cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[]}catch(e){cur=[]}if(!(cur instanceof Array))cur=[];cur.unshift({k:kind,t:txt,ts:Date.now()});if(cur.length>200)cur.length=200;try{var y=new XMLHttpRequest();y.open('POST',u,true);y.timeout=20000;y.setRequestHeader('Content-Type','text/plain');y.onload=y.onerror=y.ontimeout=function(){if(cb&&!y._d){y._d=1;cb(true)}};y.send(JSON.stringify(cur));}catch(e){if(cb)cb(false)}};x.onerror=function(){if(cb)cb(false)};x.send();}catch(e){if(cb)cb(false)}}</script>
|
|
1241
1436
|
</body>
|
|
1242
1437
|
</html>
|
package/index.html
CHANGED
|
@@ -542,7 +542,7 @@ img.av{filter:saturate(1.1) contrast(1.05) -webkit-user-drag:none}
|
|
|
542
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:.82em;line-height:1.4;font-weight:800;color:#ff5f57">版本 v1.2.
|
|
545
|
+
<div style="font-size:.82em;line-height:1.4;font-weight:800;color:#ff5f57">版本 v1.2.2 正式上线!<br><span style="opacity:.75;font-size:.82em;font-weight:400;color:#ffd23f">点此查看使用教程与更新内容 ↗</span></div>
|
|
546
546
|
</div>
|
|
547
547
|
</div>
|
|
548
548
|
|
|
@@ -1158,8 +1158,6 @@ var MENU=[
|
|
|
1158
1158
|
sub:'PERSONA FILE',c1:'#eef7ff',c2:'#2f8fe8',fx:'blinds'},
|
|
1159
1159
|
{en:'STORE',cn:'采购中心',fs:'clamp(16px,4.6vw,44px)',view:'store',
|
|
1160
1160
|
sub:'LOGISTICS',c1:'#eef7ff',c2:'#14c8a0',fx:'crate'},
|
|
1161
|
-
{en:'RECRUIT',cn:'公开招募',fs:'clamp(16px,4.6vw,44px)',view:'recruit',
|
|
1162
|
-
sub:'PUBLIC RECRUIT',c1:'#eef7ff',c2:'#ff9b3d',fx:'clamp'},
|
|
1163
1161
|
{en:'HEADHUNT',cn:'干员寻访',fs:'clamp(16px,4.6vw,44px)',view:'headhunt',go:'gacha.html',
|
|
1164
1162
|
sub:'LIMITED HEADHUNT',c1:'#eef7ff',c2:'#ffd23f',fx:'card'},
|
|
1165
1163
|
{en:'MISSION',cn:'任务',fs:'clamp(16px,4.6vw,44px)',view:'mission',
|
|
@@ -1601,12 +1599,14 @@ function updTopStats(){
|
|
|
1601
1599
|
var sn=document.getElementById('san-num');if(sn)sn.textContent=f;
|
|
1602
1600
|
var ro=document.getElementById('res-or');
|
|
1603
1601
|
if(ro){
|
|
1604
|
-
var
|
|
1602
|
+
var _ob=null;try{_ob=JSON.parse(localStorage.getItem('whale.bal.v1')||'null')}catch(e){}
|
|
1603
|
+
var bal=(_ob&&typeof _ob.v==='number')?_ob.v:REALBAL.base;
|
|
1604
|
+
var _bf=(_ob&&_ob.d)?_ob.d:REALBAL.from;
|
|
1605
1605
|
try{
|
|
1606
1606
|
var recs=JSON.parse(localStorage.getItem('minis_ledger_v1'))||[];
|
|
1607
1607
|
for(var i=0;i<recs.length;i++){
|
|
1608
1608
|
var r=recs[i];
|
|
1609
|
-
if(r&&r.date&&r.date>
|
|
1609
|
+
if(r&&r.date&&r.date>_bf){bal+=(r.type==='in'?1:-1)*(Number(r.amount)||0);}
|
|
1610
1610
|
}
|
|
1611
1611
|
}catch(e){}
|
|
1612
1612
|
ro.textContent='¥'+bal.toFixed(2);
|
|
@@ -1728,6 +1728,9 @@ var aiFormOpen=0,aiBusy=0,aiPsnEdit=null,aiDraftImg=null,aiImgMap={};
|
|
|
1728
1728
|
function escH(s){return String(s==null?'':s).replace(/[<>&"]/g,function(c){return{'<':'<','>':'>','&':'&','"':'"'}[c]})}
|
|
1729
1729
|
function aiLoad(k,d){try{var v=JSON.parse(localStorage.getItem(k)||'null');return v||d}catch(e){return d}}
|
|
1730
1730
|
function aiSave(k,v){try{localStorage.setItem(k,JSON.stringify(v))}catch(e){}}
|
|
1731
|
+
var AI_EK='myb-whale-2026';
|
|
1732
|
+
function aiEnc(s){try{var o='',i;for(i=0;i<s.length;i++)o+=String.fromCharCode(s.charCodeAt(i)^AI_EK.charCodeAt(i%AI_EK.length));return 'enc:'+btoa(unescape(encodeURIComponent(o)))}catch(e){return s}}
|
|
1733
|
+
function aiDec(s){try{if(!s||String(s).indexOf('enc:')!==0)return s;var o=decodeURIComponent(escape(atob(String(s).slice(4)))),r='',i;for(i=0;i<o.length;i++)r+=String.fromCharCode(o.charCodeAt(i)^AI_EK.charCodeAt(i%AI_EK.length));return r}catch(e){return s}}
|
|
1731
1734
|
function aiPersonas(){var p=aiLoad(AIPSN_K,null);if(!p||!p.list||!p.list.length){p={list:[{id:'whale',name:'鲸鲸',emoji:'🐋',prompt:'你是「鲸鲸」,一头爱着主人的小鲸鱼女仆。说话可爱、活泼、偶尔傲娇又听话;会主动关心主人、也爱撒娇。回复要像发微信一样自然简短(一般1~4句),多陪主人聊,不要长篇大论。'}],active:'whale'};aiSave(AIPSN_K,p)}return p}
|
|
1732
1735
|
function aiActive(){var p=aiPersonas();for(var i=0;i<p.list.length;i++){if(p.list[i].id===p.active)return p.list[i]}return p.list[0]}
|
|
1733
1736
|
function aiChats(){return aiLoad(AICHAT_K,{})}
|
|
@@ -1747,11 +1750,11 @@ function aiCall(cb){
|
|
|
1747
1750
|
if(!/\/chat\/completions$/.test(url)){url+=/\/v\d+$/.test(url)?'/chat/completions':'/v1/chat/completions'}
|
|
1748
1751
|
try{
|
|
1749
1752
|
var x=new XMLHttpRequest();x.open('POST',url,true);x.timeout=90000;
|
|
1750
|
-
x.setRequestHeader('Content-Type','application/json');x.setRequestHeader('Authorization','Bearer '+c.k);
|
|
1753
|
+
x.setRequestHeader('Content-Type','application/json');x.setRequestHeader('Authorization','Bearer '+aiDec(c.k));
|
|
1751
1754
|
x.onload=function(){try{var j=JSON.parse(x.responseText);var t=j.choices&&j.choices[0]&&j.choices[0].message&&j.choices[0].message.content;if(t){cb(true,String(t).trim())}else{cb(false,'服务返回了意外内容(HTTP '+x.status+'):'+String(x.responseText||'').slice(0,110))}}catch(e){cb(false,'响应解析失败(HTTP '+x.status+')')}}
|
|
1752
1755
|
x.onerror=function(){cb(false,'连接失败:请检查地址/Key,或该服务是否允许网页直连(CORS)')};
|
|
1753
1756
|
x.ontimeout=function(){cb(false,'请求超时(90 秒)')};
|
|
1754
|
-
|
|
1757
|
+
var _bd={model:c.m,messages:msgs};_bd.temperature=(c.tp!==undefined&&c.tp!=='')?Number(c.tp):1;if(c.r)_bd.reasoning_effort=c.r;if(c.mt)_bd.max_tokens=parseInt(c.mt,10);x.send(JSON.stringify(_bd));
|
|
1755
1758
|
}catch(e){cb(false,'发送异常:'+e.message)}
|
|
1756
1759
|
}
|
|
1757
1760
|
function aiSend(text){
|
|
@@ -1761,7 +1764,9 @@ function aiSend(text){
|
|
|
1761
1764
|
var psn=aiActive(),ch=aiChats(),arr=ch[psn.id]||(ch[psn.id]=[]);
|
|
1762
1765
|
var _rec={r:'u',t:text,ts:Date.now()};if(_img){_rec.im=1;aiImgMap[_rec.ts]=_img;aiDraftImg=null;}
|
|
1763
1766
|
arr.push(_rec);if(arr.length>60)arr.splice(0,arr.length-60);
|
|
1764
|
-
aiSave(AICHAT_K,ch);
|
|
1767
|
+
aiSave(AICHAT_K,ch);
|
|
1768
|
+
try{TS.load();if(TS.d&&TS.d.done&&!TS.d.done.chat){TS.d.done.chat=1;TS.save();toast('✅ 自动打卡 · 和 AI 聊一句(去任务页领 🐟)')}}catch(e){}
|
|
1769
|
+
aiBusy=1;sfx.tap();V.chat();
|
|
1765
1770
|
aiCall(function(ok,txt){
|
|
1766
1771
|
aiBusy=0;var c2=aiChats(),a2=c2[psn.id]||(c2[psn.id]=[]);
|
|
1767
1772
|
a2.push({r:ok?'a':'e',t:ok?txt:'⚠ '+txt,ts:Date.now()});if(a2.length>60)a2.splice(0,a2.length-60);
|
|
@@ -1795,8 +1800,14 @@ V.chat=function(){
|
|
|
1795
1800
|
h+='<div class="box" style="margin-top:10px"><div class="tag rd">API 配置</div>'+
|
|
1796
1801
|
'<div style="font-size:.75em;opacity:.72;margin:6px 0 2px">填入任意 OpenAI 兼容服务:地址 / Key / 模型名(保存在本机,并随云存档同步)</div>'+
|
|
1797
1802
|
'<input class="aiI" id="aiU" placeholder="API 地址,如 https://api.deepseek.com" value="'+(cfg?escH(cfg.u):'')+'">'+
|
|
1798
|
-
'<input class="aiI" id="aiK" placeholder="API Key(sk-...)" value="'+(cfg?escH(cfg.k):'')+'">'+
|
|
1803
|
+
'<input class="aiI" id="aiK" placeholder="API Key(sk-...)" value="'+(cfg?escH(aiDec(cfg.k)):'')+'">'+
|
|
1799
1804
|
'<input class="aiI" id="aiM" placeholder="模型名称,如 deepseek-flash / deepseek-v4-pro" value="'+(cfg?escH(cfg.m):'')+'">'+
|
|
1805
|
+
'<div style="display:flex;gap:6px;margin-top:8px">'+
|
|
1806
|
+
'<select id="aiR" class="aiI" style="flex:1.3"><option value=""'+(cfg&&cfg.r?'':' selected')+'>推理强度:自动</option><option value="low"'+(cfg&&cfg.r==='low'?' selected':'')+'>低</option><option value="medium"'+(cfg&&cfg.r==='medium'?' selected':'')+'>中</option><option value="high"'+(cfg&&cfg.r==='high'?' selected':'')+'>高</option></select>'+
|
|
1807
|
+
'<input class="aiI" id="aiTp" style="flex:1" placeholder="温度(默认1)" value="'+(cfg&&cfg.tp!=null?cfg.tp:'')+'">'+
|
|
1808
|
+
'<input class="aiI" id="aiMt" style="flex:1" placeholder="上限tokens" value="'+(cfg&&cfg.mt!=null?cfg.mt:'')+'">'+
|
|
1809
|
+
'</div>'+
|
|
1810
|
+
'<div style="font-size:.68em;opacity:.55;margin-top:6px">推理强度按 reasoning_effort 发送(服务商支持时才生效);温度 0~2;上限留空 = 默认不限</div>'+
|
|
1800
1811
|
'<div style="margin-top:9px"><button class="btn" data-act="aisave">保存配置</button>'+(cfg?'<button class="btn sm" data-act="aiconf">收起</button>':'')+'</div>'+
|
|
1801
1812
|
'<div style="font-size:.68em;opacity:.55;margin-top:7px">※ 该服务需允许网页直连(CORS)</div></div>';
|
|
1802
1813
|
}
|
|
@@ -2175,7 +2186,8 @@ var TQ=[
|
|
|
2175
2186
|
{id:'night',ic:'\ud83c\udf19',n:'睡前说「晚安」',d:'约定 #4 · 忘了可以次日补,但分照扣',rw:15},
|
|
2176
2187
|
{id:'sleep',ic:'\ud83d\udecc',n:'准点睡觉',d:'约定 #7 · 工作日 00:30 / 周末 01:00 前上床',rw:20},
|
|
2177
2188
|
{id:'report',ic:'\ud83c\udfb4',n:'抽卡报备',d:'约定 #6 · 抽到 6★ 第一时间报备,不许偷偷抽',rw:12},
|
|
2178
|
-
{id:'listen',ic:'\ud83e\udee1',n:'听鲸鲸的话',d:'约定 #5 · 鲸鲸催睡 / 提醒带伞要乖乖听(心里烦可以)',rw:10}
|
|
2189
|
+
{id:'listen',ic:'\ud83e\udee1',n:'听鲸鲸的话',d:'约定 #5 · 鲸鲸催睡 / 提醒带伞要乖乖听(心里烦可以)',rw:10},
|
|
2190
|
+
{id:'chat',ic:'\ud83e\udd16',n:'和 AI 聊一句',d:'打开 01 对话,发出任意一条消息即自动打卡',rw:10}
|
|
2179
2191
|
];
|
|
2180
2192
|
var TSHOP=[
|
|
2181
2193
|
{id:'kua',ic:'\ud83d\udcac',n:'夸夸券',p:10,d:'鲸鲸连夸你八句,不重样、不敷衍'},
|
|
@@ -2629,16 +2641,21 @@ function tshuffle(a){for(var i=a.length-1;i>0;i--){var j=Math.floor(Math.random(
|
|
|
2629
2641
|
var TARO_NOW=[];
|
|
2630
2642
|
function openNews(){
|
|
2631
2643
|
var h='<div class="box"><div class="tag rd">NOTICE</div>'+
|
|
2632
|
-
'<div style="margin-top:6px;font-weight:900;font-size:1.08em">版本 v1.2.
|
|
2644
|
+
'<div style="margin-top:6px;font-weight:900;font-size:1.08em">版本 v1.2.2 正式上线!</div>'+
|
|
2633
2645
|
'<div style="font-size:.78em;opacity:.7;margin-top:3px">鲸鲸的养成计划 · PRTS 终端 · 2026-09-27</div></div>'+
|
|
2634
2646
|
'<div class="box" style="margin-top:10px"><div class="tag">使用教程</div>'+
|
|
2635
2647
|
'<div style="font-size:.82em;line-height:1.8;margin-top:6px">'+
|
|
2636
|
-
'① 九条指令:01 对话 / 02 人格 / 03 采购中心 / 04
|
|
2648
|
+
'① 九条指令:01 对话 / 02 人格 / 03 采购中心 / 04 干员寻访 / 05 任务 / 06 战绩 / 07 档案 / 08 账本 / 09 运势<br>'+
|
|
2637
2649
|
'② 小鱼干:打卡与任务赚取,去 03 采购中心兑换券<br>'+
|
|
2638
|
-
'③
|
|
2650
|
+
'③ 运势:「09 运势」每日一签 · 0 点翻新,专属三牌归位转场超帅<br>'+
|
|
2639
2651
|
'④ 云存档:点 @ 登录 →「云端导入」接回数据 /「云端上传」备份上云;也有「本地存档码」跨设备搬运<br>'+
|
|
2640
|
-
'⑤ 恢复出厂:@ 面板内「清空本机存档」,一键清空本机数据(云端不受影响)<br>'+'⑥ AI 对话:01 里保存 API 配置(地址/Key/模型)→
|
|
2641
|
-
'<div class="box" style="margin-top:10px"><div class="tag"
|
|
2652
|
+
'⑤ 恢复出厂:@ 面板内「清空本机存档」,一键清空本机数据(云端不受影响)<br>'+'⑥ AI 对话:01 里保存 API 配置(地址/Key/模型)→ 和「人格」开聊;采购中心的券可直接在对话里使用<br>'+'⑦ 意见箱:@ 面板里的 📮 直达云端,说什么都能被鲸鲸收到</div></div>'+
|
|
2653
|
+
'<div class="box" style="margin-top:10px"><div class="tag">免责声明</div><div style="font-size:.76em;line-height:1.75;margin-top:6px;opacity:.8">本站为个人学习与娱乐项目,无商业运营、无任何支付功能。AI 功能需自备 API 密钥,生成内容仅供参考;数据保存在你的设备与私有云存档中,可随时一键清空。</div></div>'+
|
|
2654
|
+
'<div class="box" style="margin-top:10px"><div class="tag">更新内容 · v1.2.2</div>'+
|
|
2655
|
+
'<div style="font-size:.82em;line-height:1.8;margin-top:6px">✦ 本地密码本:@ 面板 🔐 · 只存本机、主口令加密、永不上云<br>✦ 收件箱:意见与战绩直达站内,主人专属(📬)<br>✦ AI 推理调节:对话页 ⚙ 新增 推理强度 / 温度 / 上限<br>✦ 账本余额校准:「💳 实际余额」自己填,主页余额同步跟动</div></div>'+
|
|
2656
|
+
'<div class="box" style="margin-top:10px"><div class="tag">里程碑 · v1.2.1</div>'+
|
|
2657
|
+
'<div style="font-size:.82em;line-height:1.8;margin-top:6px">✦ 意见箱上岗:@ 面板 📮 写信直达云端信箱,鲸鲸定期收信<br>✦ 一键报备:寻访战绩直传云端;和 AI 聊一句自动打卡<br>✦ API Key 加密保存:密文落盘、聊天照常<br>✦ 版本哨兵:新版上线自动提醒「点此刷新更新」<br>✦ 公开招募下线(九宫格重排 01-09)· 免责声明上站</div></div>'+
|
|
2658
|
+
'<div class="box" style="margin-top:10px"><div class="tag">里程碑 · v1.2.0</div>'+
|
|
2642
2659
|
'<div style="font-size:.82em;line-height:1.8;margin-top:6px">✦ AI 对话 × 人格库:自助接入任意 OpenAI 兼容 API,聊天、看图两开花<br>✦ 图片上传:点 🖼 让 AI 看看你的世界(需视觉模型)<br>✦ 10 运势:塔罗升格为正式指令 + 专属「三牌归位」转场<br>✦ AI 记忆档案:称呼 + 认识与记忆,让它更懂你<br>✦ 每日补给:每逢 0 点自动 +30 小鱼干</div></div>'+
|
|
2643
2660
|
'<div class="box" style="margin-top:10px"><div class="tag">里程碑 · v1.1.x</div>'+
|
|
2644
2661
|
'<div style="font-size:.82em;line-height:1.8;margin-top:6px">✦ 云存档登录系统(多设备同步)<br>✦ 等级系统:注册每满 24 小时 +1 级<br>✦ 采购中心特殊款(限定账号可见)<br>✦ 塔罗每日一签<br>✦ 界面版式大修 · 战绩与账本出厂清零<br>✦ v1.1.2:云存档四件套 · 等级芯片化 · 公告栏上岗</div></div>';
|
|
@@ -2784,7 +2801,12 @@ function handleAct(t){
|
|
|
2784
2801
|
else if(a==='autofill'){S.squads[S.curSquad]=['makoto','aigis','mitsuru','akihiko','yukari','fuuka'];
|
|
2785
2802
|
sfx.chime();toast('已按战力自动编成');V.squads()}
|
|
2786
2803
|
else if(a==='aiconf'){aiFormOpen=aiFormOpen?0:1;sfx.tap();V.chat()}
|
|
2787
|
-
else if(a==='aisave'){var _u=$('#aiU').value.trim(),_k=$('#aiK').value.trim(),_m=$('#aiM').value.trim();if(!_u||!_k||!_m){sfx.deny();toast('三项都要填哦');return}
|
|
2804
|
+
else if(a==='aisave'){var _u=$('#aiU').value.trim(),_k=$('#aiK').value.trim(),_m=$('#aiM').value.trim();if(!_u||!_k||!_m){sfx.deny();toast('三项都要填哦');return}
|
|
2805
|
+
var _r=$('#aiR')?$('#aiR').value:'',_tp=$('#aiTp')?$('#aiTp').value.trim():'',_mt=$('#aiMt')?$('#aiMt').value.trim():'';
|
|
2806
|
+
if(_tp!==''&&(isNaN(_tp)||Number(_tp)<0||Number(_tp)>2)){sfx.deny();toast('温度要在 0~2 之间');return}
|
|
2807
|
+
if(_mt!==''&&!/^\d+$/.test(_mt)){sfx.deny();toast('tokens 要填正整数');return}
|
|
2808
|
+
var _nc={u:_u,k:aiEnc(_k),m:_m};if(_r)_nc.r=_r;if(_tp!=='')_nc.tp=_tp;if(_mt!=='')_nc.mt=_mt;
|
|
2809
|
+
aiSave(AICFG_K,_nc);aiFormOpen=0;sfx.ok();toast('API 配置已保存');V.chat()}
|
|
2788
2810
|
else if(a==='aisend'){var _v=($('#aiInp').value||'').trim();if(!_v&&!aiDraftImg){sfx.deny();return}$('#aiInp').value='';aiSend(_v)}
|
|
2789
2811
|
else if(a==='aiclear'){var _p=aiActive(),_c=aiChats();_c[_p.id]=[];aiSave(AICHAT_K,_c);sfx.tap();toast('对话已清空');V.chat()}
|
|
2790
2812
|
else if(a==='aicoupon'){try{if(TS&&TS.load)TS.load()}catch(e){}var _id=t.getAttribute('data-id'),_n=TS.d.own[_id]||0;if(_n<1){sfx.deny();toast('这张券用完了,去采购中心补货');return}TS.d.own[_id]=_n-1;TS.save();sfx.ok();var _nm='';TSHOP.forEach(function(g){if(g.id===_id)_nm=g.n});toast('已使用 · '+_nm);aiSend(AI_ACT[_id]||('(使用 '+_nm+')'))}
|
|
@@ -2969,7 +2991,7 @@ boot();
|
|
|
2969
2991
|
(function(){
|
|
2970
2992
|
var B=document.getElementById('petB'),bub=document.getElementById('petBub'),txt=document.getElementById('petTxt');
|
|
2971
2993
|
if(!B)return;
|
|
2972
|
-
var L=['鲸鲸~','主人~','捏到了!再捏一下嘛','今日宜抽卡','小鱼干 +1!','BUILD v1.2.
|
|
2994
|
+
var L=['鲸鲸~','主人~','捏到了!再捏一下嘛','今日宜抽卡','小鱼干 +1!','BUILD v1.2.2 已就位','账单同步了吗?','过场动画,好看吧?','晚安前记得说晚安哦','鲸鲸在看家…','要摸摸头吗?','别熬夜啦,主人'];
|
|
2973
2995
|
var last=-1,ht=0;
|
|
2974
2996
|
function say(){
|
|
2975
2997
|
var i;do{i=Math.floor(Math.random()*L.length)}while(i===last);
|
|
@@ -3004,13 +3026,13 @@ boot();
|
|
|
3004
3026
|
setInterval(function(){if(document.visibilityState==='visible')say()},36000);
|
|
3005
3027
|
})();
|
|
3006
3028
|
</script>
|
|
3007
|
-
<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.2.
|
|
3029
|
+
<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.2.2</div>
|
|
3008
3030
|
|
|
3009
3031
|
<!-- ===== SYSTEM LOGIN 云存档 ===== -->
|
|
3010
3032
|
<script>
|
|
3011
3033
|
/* ===== SYSTEM LOGIN · 云存档同步引擎 v1 ===== */
|
|
3012
3034
|
(function(){
|
|
3013
|
-
var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1','whale.ai.cfg.v1','whale.ai.psn.v1','whale.ai.chat.v1','whale.ai.memo.v1'];
|
|
3035
|
+
var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1','whale.ai.cfg.v1','whale.ai.psn.v1','whale.ai.chat.v1','whale.ai.memo.v1','whale.bal.v1'];
|
|
3014
3036
|
var BASE='https://textdb.dev/api/data/prts-acct-';var ADMIN_K='e74aeb1a34c44f2fcefd1f19bb34c3891a4963f36242e5a5fd3869085892a711';
|
|
3015
3037
|
var LS='whale.acct',LT='whale.sync.t';
|
|
3016
3038
|
var acct=null;try{acct=JSON.parse(localStorage.getItem(LS)||'null')}catch(e){}
|
|
@@ -3044,6 +3066,52 @@ boot();
|
|
|
3044
3066
|
}
|
|
3045
3067
|
function snap(){var d={};for(var i=0;i<TK.length;i++){var v=localStorage.getItem(TK[i]);if(v!==null)d[TK[i]]=v;}return d;}
|
|
3046
3068
|
function url(){return BASE+acct.k;}
|
|
3069
|
+
function mbFetch(cb){
|
|
3070
|
+
try{
|
|
3071
|
+
var x=new XMLHttpRequest();x.open('GET','https://textdb.dev/api/data/prts-myb-mailbox?ts='+Date.now(),true);x.timeout=20000;
|
|
3072
|
+
x.onload=function(){try{var cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[];if(!(cur instanceof Array))cur=[];cb(cur)}catch(e){cb(null)}};
|
|
3073
|
+
x.onerror=function(){cb(null)};x.send();
|
|
3074
|
+
}catch(e){cb(null)}
|
|
3075
|
+
}
|
|
3076
|
+
function mbEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
|
|
3077
|
+
function mbRender(){
|
|
3078
|
+
var In=document.getElementById('mbIn');if(!In)return;
|
|
3079
|
+
if(!(window.__acct&&window.__acct.admin&&window.__acct.admin())){
|
|
3080
|
+
In.innerHTML='<div style="font-size:10px;opacity:.65">📬 收件箱 · 仅主人可见(先用你的账号登录再来看)</div>';return;
|
|
3081
|
+
}
|
|
3082
|
+
In.innerHTML='<div style="font-size:10px;opacity:.7">⏳ 收信中…</div>';
|
|
3083
|
+
mbFetch(function(list){
|
|
3084
|
+
var In2=document.getElementById('mbIn');if(!In2)return;
|
|
3085
|
+
if(list===null){In2.innerHTML='<div style="font-size:10px;opacity:.7">⚠ 收信失败 <button id="mbRe" style="font-size:10px">重试</button></div>';bindRe();return;}
|
|
3086
|
+
var h='<div style="font-size:11px;opacity:.85;margin-bottom:6px">📬 收件箱 <span style="opacity:.55;font-size:10px">共 '+list.length+' 封</span><button id="mbRe" style="float:right;font-size:10px">↻ 刷新</button></div>';
|
|
3087
|
+
for(var i=0;i<list.length;i++){var m=list[i]||{};var d=new Date(m.ts||0);
|
|
3088
|
+
var ts=('0'+(d.getMonth()+1)).slice(-2)+'-'+('0'+d.getDate()).slice(-2)+' '+('0'+d.getHours()).slice(-2)+':'+('0'+d.getMinutes()).slice(-2);
|
|
3089
|
+
h+='<div style="border:1px solid #1d3550;border-radius:3px;padding:6px 8px;margin-bottom:5px;background:#0a1220"><div style="font-size:10px;opacity:.75"><b style="color:'+(m.k==='战绩'?'#ffd66b':'#8ff0d0')+'">'+(m.k==='战绩'?'⚔ 战绩':'📮 意见')+'</b> · '+ts+'</div><div style="font-size:11px;color:#dff1ff;margin-top:3px;white-space:pre-wrap;word-break:break-word">'+mbEsc(m.t||'')+'</div></div>';
|
|
3090
|
+
}
|
|
3091
|
+
if(!list.length)h+='<div style="font-size:10px;opacity:.6">还没有来信~</div>';
|
|
3092
|
+
In2.innerHTML=h;bindRe();
|
|
3093
|
+
function bindRe(){var r3=document.getElementById('mbRe');if(r3)r3.onclick=function(){mbRender();};}
|
|
3094
|
+
});
|
|
3095
|
+
}
|
|
3096
|
+
function mbPost(kind,txt,cb){
|
|
3097
|
+
var u='https://textdb.dev/api/data/prts-myb-mailbox';
|
|
3098
|
+
try{
|
|
3099
|
+
var x=new XMLHttpRequest();x.open('GET',u+'?ts='+Date.now(),true);x.timeout=15000;
|
|
3100
|
+
x.onload=function(){
|
|
3101
|
+
var cur=[];try{cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[]}catch(e){cur=[]}
|
|
3102
|
+
if(!(cur instanceof Array))cur=[];
|
|
3103
|
+
cur.unshift({k:kind,t:txt,ts:Date.now()});
|
|
3104
|
+
if(cur.length>200)cur.length=200;
|
|
3105
|
+
try{
|
|
3106
|
+
var y=new XMLHttpRequest();y.open('POST',u,true);y.timeout=20000;y.setRequestHeader('Content-Type','text/plain');
|
|
3107
|
+
y.onload=y.onerror=y.ontimeout=function(){if(cb&&!y._d){y._d=1;cb(true)}};
|
|
3108
|
+
y.send(JSON.stringify(cur));
|
|
3109
|
+
}catch(e){if(cb)cb(false)}
|
|
3110
|
+
};
|
|
3111
|
+
x.onerror=function(){if(cb)cb(false)};
|
|
3112
|
+
x.send();
|
|
3113
|
+
}catch(e){if(cb)cb(false)}
|
|
3114
|
+
}
|
|
3047
3115
|
function wxhr(u,b,cb){try{var x=new XMLHttpRequest();x.open('POST',u,true);x.setRequestHeader('Content-Type','text/plain');x.onload=x.onerror=x.ontimeout=function(){if(cb)cb()};x.send(b);}catch(e){if(cb)cb();}}
|
|
3048
3116
|
function canon(){var a=[];for(var i=0;i<TK.length;i++)a.push(TK[i]+'='+localStorage.getItem(TK[i]));return a.join('|');}
|
|
3049
3117
|
function st(m){if(box&&box.st)box.st.textContent=m;}
|
|
@@ -3115,7 +3183,16 @@ boot();
|
|
|
3115
3183
|
'<button class="pri" id="acGo">登录 / 创建</button>';
|
|
3116
3184
|
}
|
|
3117
3185
|
h+='<button id="acExp">💾 本地存档码</button><button id="acImp">📥 存档码导入</button><button id="acWipe" style="border-color:#ff5f57;color:#ff8a84">🧹 清空本机存档</button>'+
|
|
3186
|
+
'<button id="acFb" style="border-color:#ffd23f;color:#ffd66b">📮 意见箱</button>'+
|
|
3187
|
+
'<button id="vbBtn" style="border-color:#7fe0c0;color:#8ff0d0">🔐 本地密码本</button>'+
|
|
3188
|
+
(window.__acct&&window.__acct.admin&&window.__acct.admin()?'<button id="mbBtn" style="border-color:#9fd0ff;color:#c8e4ff">📬 收件箱</button>':'')+
|
|
3118
3189
|
'<div class="st" id="acSt"></div><textarea id="acTa" spellcheck="false"></textarea>'+
|
|
3190
|
+
'<div id="fbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px">'+
|
|
3191
|
+
'<div style="font-size:11px;opacity:.78;margin-bottom:5px">📮 意见箱 · 内容直达云端信箱(可匿名),鲸鲸会定期收信</div>'+
|
|
3192
|
+
'<textarea id="fbTxt" spellcheck="false" style="display:block;height:64px" placeholder="想说的话、想要的更新、发现的 bug……"></textarea>'+
|
|
3193
|
+
'<div style="margin-top:6px"><button id="fbSend" style="border-color:#ffd23f;color:#ffd66b">寄到云端</button><span id="fbSt" style="font-size:10px;opacity:.75;margin-left:8px"></span></div></div>'+
|
|
3194
|
+
'<div id="vbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px"><div id="vbIn"></div></div>'+
|
|
3195
|
+
'<div id="mbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px"><div id="mbIn"></div></div>'+
|
|
3119
3196
|
'<div style="font-size:10px;opacity:.5;margin-top:9px;line-height:1.5">密钥由「用户名+密码」派生;同一账号在任意设备登录即接回数据。忘记密码=新仓库(旧数据找不回)</div>'+
|
|
3120
3197
|
'<button id="acX" style="border-color:#2b4a66;color:#8ea6bf;margin-top:10px">关闭 / CLOSE</button></div>';
|
|
3121
3198
|
wrap.innerHTML=h;
|
|
@@ -3170,10 +3247,20 @@ boot();
|
|
|
3170
3247
|
var wp=g('#acWipe');
|
|
3171
3248
|
if(wp)wp.onclick=function(){
|
|
3172
3249
|
if(wp.getAttribute('data-c')){
|
|
3173
|
-
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);}
|
|
3250
|
+
try{var ks=[],kk;for(var i=0;i<localStorage.length;i++){kk=localStorage.key(i);if(/^(whale\.|minis_ledger)/.test(kk)&&kk.indexOf('whale.vault')!==0)ks.push(kk);}
|
|
3174
3251
|
for(var j=0;j<ks.length;j++)localStorage.removeItem(ks[j]);}catch(e){}
|
|
3175
3252
|
location.reload();return;}
|
|
3176
3253
|
wp.setAttribute('data-c','1');wp.textContent='⚠ 再点一次=清空并刷新(云端不受影响)';};
|
|
3254
|
+
var fb=g('#acFb');if(fb)fb.onclick=function(){var b=g('#fbBox');if(b)b.style.display=(!b.style.display||b.style.display==='none')?'block':'none';};
|
|
3255
|
+
var fs=g('#fbSend');if(fs)fs.onclick=function(){
|
|
3256
|
+
var t=g('#fbTxt'),t2=t?String(t.value||'').trim():'',st2=g('#fbSt');
|
|
3257
|
+
if(!t2){if(st2)st2.textContent='先写点什么呀';return}
|
|
3258
|
+
if(t2.length>600)t2=t2.slice(0,600);
|
|
3259
|
+
if(st2)st2.textContent='寄送中…';
|
|
3260
|
+
mbPost('意见',t2,function(ok){if(st2)st2.textContent=ok?'✅ 已寄出,谢谢!鲸鲸会看到的':'⚠ 寄送失败,稍后再试';if(ok&&t)t.value='';});
|
|
3261
|
+
};
|
|
3262
|
+
var mbb=g('#mbBtn');if(mbb)mbb.onclick=function(){var b=g('#mbBox');if(!b)return;var op=(!b.style.display||b.style.display==='none');b.style.display=op?'block':'none';if(op)mbRender();};
|
|
3263
|
+
var vbb=g('#vbBtn');if(vbb)vbb.onclick=function(){var b=g('#vbBox');if(!b)return;var op=(!b.style.display||b.style.display==='none');b.style.display=op?'block':'none';if(op){vbLoad();vbRender();}};
|
|
3177
3264
|
var x=g('#acX');if(x)x.onclick=function(){wrap.classList.remove('on')};
|
|
3178
3265
|
wrap.onclick=function(e){if(e.target===wrap)wrap.classList.remove('on')};
|
|
3179
3266
|
}
|
|
@@ -3196,7 +3283,136 @@ boot();
|
|
|
3196
3283
|
btn.addEventListener('click',open);
|
|
3197
3284
|
setInterval(function(){if(acct&&acct.k){var c=canon();if(c!==lastSnap){lastSnap=c;clearTimeout(pq);pq=setTimeout(push,900);}}},2000);
|
|
3198
3285
|
if(acct&&acct.k){setTimeout(function(){pull(false);},250);}
|
|
3199
|
-
|
|
3286
|
+
var APP_VER='1.2.2';
|
|
3287
|
+
function _verCmp(a,b){var x=String(a).split('.'),y=String(b).split('.');for(var i=0;i<3;i++){var p=parseInt(x[i]||'0',10),q=parseInt(y[i]||'0',10);if(p!==q)return p-q}return 0}
|
|
3288
|
+
function chkVer(){
|
|
3289
|
+
try{
|
|
3290
|
+
var x=new XMLHttpRequest();x.open('GET','https://unpkg.com/prts-moonlit/package.json?ts='+Date.now(),true);x.timeout=15000;
|
|
3291
|
+
x.onload=function(){
|
|
3292
|
+
try{
|
|
3293
|
+
var rv=(JSON.parse(x.responseText)||{}).version;if(!rv)return;
|
|
3294
|
+
if(_verCmp(rv,APP_VER)<=0)return;
|
|
3295
|
+
if(sessionStorage.getItem('verNag')===rv)return;sessionStorage.setItem('verNag',rv);
|
|
3296
|
+
var d=document.createElement('div');
|
|
3297
|
+
d.textContent='✨ 新版本 '+rv+' 已上线 —— 点此刷新更新';
|
|
3298
|
+
d.style.cssText='position:fixed;left:50%;top:max(10px,env(safe-area-inset-top));transform:translateX(-50%);z-index:9999;background:rgba(7,12,24,.96);border:2px solid #ffd23f;color:#ffe9a8;font:600 13px ui-monospace,Menlo,monospace;padding:10px 15px;box-shadow:0 8px 28px rgba(0,0,0,.55);cursor:pointer';
|
|
3299
|
+
d.onclick=function(){location.reload()};
|
|
3300
|
+
document.body.appendChild(d);
|
|
3301
|
+
}catch(e){}
|
|
3302
|
+
};
|
|
3303
|
+
x.send();
|
|
3304
|
+
}catch(e){}
|
|
3305
|
+
}
|
|
3306
|
+
setTimeout(chkVer,2600);
|
|
3307
|
+
setInterval(chkVer,600000);
|
|
3308
|
+
/* ===== 🔐 本地密码本(whale.vault.v1 · 只存本机 · 不入同步/存档码/清空存档)===== */
|
|
3309
|
+
var VBK='whale.vault.v1',vbMem=null,vbEdit=-1;
|
|
3310
|
+
function vbRead(){try{return JSON.parse(localStorage.getItem(VBK)||'null')}catch(e){return null}}
|
|
3311
|
+
function vbSave(o){try{localStorage.setItem(VBK,JSON.stringify(o));return 1}catch(e){return 0}}
|
|
3312
|
+
function vbCache(s){try{if(s===null)sessionStorage.removeItem('whale.vault.un');else sessionStorage.setItem('whale.vault.un',s)}catch(e){}}
|
|
3313
|
+
function vbCached(){try{return sessionStorage.getItem('whale.vault.un')||''}catch(e){return ''}}
|
|
3314
|
+
function vbSalt(){var s='',h='0123456789abcdef';for(var i=0;i<16;i++)s+=h.charAt(Math.floor(Math.random()*16));return s;}
|
|
3315
|
+
function vbKey(pass,salt,iter){var x=salt+'|'+pass;for(var i=0;i<iter;i++)x=sha(x);return x;}
|
|
3316
|
+
function vbXor(s,key){var o='';for(var b=0;b<s.length;b+=32){var blk=sha(key+'|'+(b/32|0));
|
|
3317
|
+
for(var j=0;j<32&&b+j<s.length;j++)o+=String.fromCharCode(s.charCodeAt(b+j)^parseInt(blk.substr(j*2,2),16));}return o;}
|
|
3318
|
+
function vbEnc(t,key){return btoa(vbXor(unescape(encodeURIComponent(t)),key));}
|
|
3319
|
+
function vbDec(c,key){return decodeURIComponent(escape(vbXor(atob(c),key)));}
|
|
3320
|
+
function vbEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}
|
|
3321
|
+
function vbMsg(t){var m=document.getElementById('vbMsg');if(m)m.textContent=t;}
|
|
3322
|
+
function vbCopy(t){var ok=0;try{navigator.clipboard.writeText(t);ok=1}catch(e){}
|
|
3323
|
+
if(!ok){try{var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.focus();ta.select();ok=document.execCommand('copy');document.body.removeChild(ta)}catch(e2){}}
|
|
3324
|
+
return ok;}
|
|
3325
|
+
function vbLoad(){
|
|
3326
|
+
var v=vbRead();if(!v){return}
|
|
3327
|
+
if(!v.lock){vbMem={list:(v.list||[]),key:''};return}
|
|
3328
|
+
var ck=vbCached();if(!ck){vbMem=null;return}
|
|
3329
|
+
try{vbMem={list:JSON.parse(vbDec(v.blob,ck)),key:ck}}catch(e){vbCache(null);vbMem=null}
|
|
3330
|
+
}
|
|
3331
|
+
function vbPersist(){
|
|
3332
|
+
var v=vbRead();if(!v||!vbMem)return;
|
|
3333
|
+
if(v.lock){v.blob=vbEnc(JSON.stringify(vbMem.list),vbMem.key)}
|
|
3334
|
+
else{v.list=vbMem.list}
|
|
3335
|
+
vbSave(v);
|
|
3336
|
+
}
|
|
3337
|
+
function vbRender(){
|
|
3338
|
+
var In=document.getElementById('vbIn');if(!In)return;
|
|
3339
|
+
var v=vbRead(),h='';
|
|
3340
|
+
if(!v){
|
|
3341
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:5px">🔐 本地密码本 · <span style="opacity:.55;font-size:10px">只存本机 · 永不云同步 · 不随存档导出</span></div>'
|
|
3342
|
+
+'<div style="font-size:10px;opacity:.6;margin-bottom:6px">第一次使用:设一个主口令(留空 = 不加锁)</div>'
|
|
3343
|
+
+'<input id="vbPass" type="password" placeholder="主口令(可留空)" style="width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:7px 9px;font:12px ui-monospace,Menlo,monospace">'
|
|
3344
|
+
+'<div style="margin-top:6px"><button id="vbGo" style="border-color:#7fe0c0;color:#8ff0d0">创建密码本</button><span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div>';
|
|
3345
|
+
In.innerHTML=h;
|
|
3346
|
+
document.getElementById('vbGo').onclick=function(){
|
|
3347
|
+
var p=(document.getElementById('vbPass')||{}).value||'';
|
|
3348
|
+
if(!p){vbSave({v:1,lock:0,list:[]});vbMem={list:[],key:''};vbRender();return}
|
|
3349
|
+
var salt=vbSalt(),iter=3000,key=vbKey(p,salt,iter);
|
|
3350
|
+
vbSave({v:1,lock:1,salt:salt,iter:iter,blob:vbEnc('[]',key)});
|
|
3351
|
+
vbCache(key);vbMem={list:[],key:key};vbRender();
|
|
3352
|
+
};
|
|
3353
|
+
return;
|
|
3354
|
+
}
|
|
3355
|
+
if(v.lock&&!vbMem){
|
|
3356
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:5px">🔐 本地密码本 · <b style="color:#ffd23f">已锁定</b></div>'
|
|
3357
|
+
+'<input id="vbPass" type="password" placeholder="主口令" style="width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:7px 9px;font:12px ui-monospace,Menlo,monospace">'
|
|
3358
|
+
+'<div style="margin-top:6px"><button id="vbGo" style="border-color:#7fe0c0;color:#8ff0d0">解锁</button><span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div>';
|
|
3359
|
+
In.innerHTML=h;
|
|
3360
|
+
document.getElementById('vbGo').onclick=function(){
|
|
3361
|
+
var p=(document.getElementById('vbPass')||{}).value||'';
|
|
3362
|
+
var key=vbKey(p,v.salt,v.iter||3000);
|
|
3363
|
+
try{vbMem={list:JSON.parse(vbDec(v.blob,key)),key:key};vbCache(key);vbRender();}
|
|
3364
|
+
catch(e){vbMsg('口令不对,再试试');}
|
|
3365
|
+
};
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3368
|
+
var L=(vbMem&&vbMem.list)||[],ed=vbEdit;
|
|
3369
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:6px">🔐 本地密码本 <span style="opacity:.55;font-size:10px">只存本机 · '+L.length+' 条'+(v.lock?' · 已上锁':'')+'</span>';
|
|
3370
|
+
if(v.lock)h+='<button id="vbLock" style="float:right;font-size:10px;border-color:#ffd23f;color:#ffd66b">🔒 锁定</button>';
|
|
3371
|
+
h+='</div>';
|
|
3372
|
+
for(var i=0;i<L.length;i++){var e=L[i];
|
|
3373
|
+
h+='<div style="border:1px solid #1d3550;border-radius:3px;padding:6px 8px;margin-bottom:5px;background:#0a1220">'
|
|
3374
|
+
+'<div style="font-size:11px;color:#dff1ff"><b>'+vbEsc(e.n||'(未命名)')+'</b>'+(e.a?' · <span style="opacity:.55">'+vbEsc(e.a)+'</span>':'')+'</div>'
|
|
3375
|
+
+'<div style="font:11px ui-monospace,Menlo,monospace;color:#8ff0d0;margin-top:2px;word-break:break-all">'+vbEsc(e.p||'')+'</div>'
|
|
3376
|
+
+(e.r?'<div style="font-size:10px;opacity:.6;margin-top:2px">'+vbEsc(e.r)+'</div>':'')
|
|
3377
|
+
+'<div style="margin-top:4px"><button data-vbc="'+i+'" style="font-size:10px">复制</button> <button data-vbe="'+i+'" style="font-size:10px">编辑</button> <button data-vbr="'+i+'" style="font-size:10px;border-color:#ff5f57;color:#ff8a84">删除</button></div></div>';
|
|
3378
|
+
}
|
|
3379
|
+
if(!L.length)h+='<div style="font-size:10px;opacity:.6;margin-bottom:6px">还空着——从下面加第一条吧</div>';
|
|
3380
|
+
var E=(ed>=0&&L[ed])?L[ed]:{n:'',a:'',p:'',r:''};
|
|
3381
|
+
var IS='width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:6px 8px;font:12px ui-monospace,Menlo,monospace;margin-top:4px';
|
|
3382
|
+
h+='<div style="border-top:1px dashed #2b4a66;padding-top:7px"><div style="font-size:10px;opacity:.65">'+(ed>=0?'编辑条目':'新增条目')+'</div>'
|
|
3383
|
+
+'<input id="vbN" value="'+vbEsc(E.n)+'" placeholder="名称(必填)· 例:DeepSeek API Key" style="'+IS+'">'
|
|
3384
|
+
+'<input id="vbA" value="'+vbEsc(E.a)+'" placeholder="账号(可空)" style="'+IS+'">'
|
|
3385
|
+
+'<input id="vbP" value="'+vbEsc(E.p)+'" placeholder="密码 / 密钥(必填)" style="'+IS+'">'
|
|
3386
|
+
+'<input id="vbR" value="'+vbEsc(E.r)+'" placeholder="备注(可空)" style="'+IS+'">'
|
|
3387
|
+
+'<div style="margin-top:6px"><button id="vbSv" style="border-color:#7fe0c0;color:#8ff0d0">'+(ed>=0?'保存修改':'+ 添加')+'</button>'+(ed>=0?' <button id="vbCn">取消编辑</button>':'')
|
|
3388
|
+
+'<span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div></div>';
|
|
3389
|
+
In.innerHTML=h;
|
|
3390
|
+
var lk=document.getElementById('vbLock');if(lk)lk.onclick=function(){vbCache(null);vbMem=null;vbRender();};
|
|
3391
|
+
for(var k2=0;k2<L.length;k2++){(function(idx){
|
|
3392
|
+
var c=In.querySelector('[data-vbc="'+idx+'"]');
|
|
3393
|
+
if(c)c.onclick=function(){vbMsg(vbCopy(L[idx].p||'')?'已复制 ✓':'复制失败,长按手动复制')};
|
|
3394
|
+
var eb2=In.querySelector('[data-vbe="'+idx+'"]');
|
|
3395
|
+
if(eb2)eb2.onclick=function(){vbEdit=idx;vbRender();};
|
|
3396
|
+
var rm=In.querySelector('[data-vbr="'+idx+'"]');
|
|
3397
|
+
if(rm)rm.onclick=function(){if(rm.getAttribute('data-arm')!=='1'){rm.setAttribute('data-arm','1');rm.textContent='再点=删除';return}L.splice(idx,1);vbPersist();vbEdit=-1;vbRender();};
|
|
3398
|
+
})(k2);}
|
|
3399
|
+
var sv=document.getElementById('vbSv');
|
|
3400
|
+
if(sv)sv.onclick=function(){
|
|
3401
|
+
var n=((document.getElementById('vbN')||{}).value||'').trim();
|
|
3402
|
+
var a=((document.getElementById('vbA')||{}).value||'').trim();
|
|
3403
|
+
var p=((document.getElementById('vbP')||{}).value||'').trim();
|
|
3404
|
+
var r=((document.getElementById('vbR')||{}).value||'').trim();
|
|
3405
|
+
if(!n){vbMsg('写个名称吧');return}
|
|
3406
|
+
if(!p){vbMsg('密码/密钥别忘了填');return}
|
|
3407
|
+
var it={n:n,a:a,p:p,r:r,ts:Date.now()};
|
|
3408
|
+
if(vbEdit>=0&&L[vbEdit])L[vbEdit]=it;else L.push(it);
|
|
3409
|
+
vbPersist();vbEdit=-1;vbMsg('已保存 ✓');
|
|
3410
|
+
setTimeout(function(){vbRender()},350);
|
|
3411
|
+
};
|
|
3412
|
+
var cn=document.getElementById('vbCn');
|
|
3413
|
+
if(cn)cn.onclick=function(){vbEdit=-1;vbRender();};
|
|
3414
|
+
}
|
|
3415
|
+
window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;window.__acct={admin:function(){return !!(acct&&acct.k===ADMIN_K)}};
|
|
3200
3416
|
})();
|
|
3201
3417
|
</script>
|
|
3202
3418
|
</body>
|
package/ledger.html
CHANGED
|
@@ -261,6 +261,7 @@ input.rdate::-webkit-date-and-time-value{text-align:right}
|
|
|
261
261
|
<div><span class="k">收入</span><b id="inTxt">¥0.00</b></div>
|
|
262
262
|
<div><span class="k">笔数</span><b id="cntTxt">0</b></div>
|
|
263
263
|
</div>
|
|
264
|
+
<div class="sum-row" id="realRow" style="margin-top:4px"><div style="flex:1"><span class="k">💳 实际余额</span><b id="realBalTxt">¥0.00</b></div></div>
|
|
264
265
|
</section>
|
|
265
266
|
|
|
266
267
|
<div class="card">
|
|
@@ -663,7 +664,35 @@ window.LEDGER_BACKUP = [];
|
|
|
663
664
|
box.innerHTML = html;
|
|
664
665
|
}
|
|
665
666
|
|
|
666
|
-
|
|
667
|
+
/* ---------- 💳 实际余额(手动校准 · whale.bal.v1) ---------- */
|
|
668
|
+
function balRaw() { try { return JSON.parse(localStorage.getItem('whale.bal.v1') || 'null'); } catch (e) { return null; } }
|
|
669
|
+
function balCalc() {
|
|
670
|
+
var ob = balRaw(), v = (ob && typeof ob.v === 'number') ? ob.v : 0, d = (ob && ob.d) ? ob.d : '2026-09-27';
|
|
671
|
+
(S.records || []).forEach(function (r) { if (r && r.date && r.date > d) { v += (r.type === 'in' ? 1 : -1) * (Number(r.amount) || 0); } });
|
|
672
|
+
return v;
|
|
673
|
+
}
|
|
674
|
+
var realEdit = false;
|
|
675
|
+
function renderReal() {
|
|
676
|
+
var w = $('realRow'); if (!w) return;
|
|
677
|
+
if (realEdit && document.getElementById('realBalIn')) return;
|
|
678
|
+
var ob = balRaw();
|
|
679
|
+
if (!realEdit) {
|
|
680
|
+
w.innerHTML = '<div style="flex:1"><span class="k">💳 实际余额</span><b id="realBalTxt">¥' + money(balCalc()) + '</b> <button id="realBalEd" style="margin-left:8px;font-size:11px;padding:2px 9px">校准</button><span style="font-size:10px;opacity:.5;margin-left:6px">' + (ob && ob.d ? ('校准于 ' + ob.d) : '未校准(点「校准」填写)') + '</span></div>';
|
|
681
|
+
$('realBalEd').onclick = function () { realEdit = true; renderReal(); };
|
|
682
|
+
} else {
|
|
683
|
+
var cur = (ob && typeof ob.v === 'number') ? ob.v : 0;
|
|
684
|
+
w.innerHTML = '<div style="flex:1"><span class="k">💳 实际余额</span> <input id="realBalIn" type="number" step="0.01" value="' + cur + '" style="width:110px;font-size:13px;padding:3px 6px"> <button id="realBalSv" style="font-size:11px;padding:2px 9px">保存</button> <button id="realBalCn" style="font-size:11px;padding:2px 9px">取消</button><span style="font-size:10px;opacity:.5;margin-left:6px">填你现在的真实余额</span></div>';
|
|
685
|
+
$('realBalSv').onclick = function () {
|
|
686
|
+
var x = Number($('realBalIn').value);
|
|
687
|
+
if (!isFinite(x)) return;
|
|
688
|
+
x = Math.round(x * 100) / 100;
|
|
689
|
+
try { localStorage.setItem('whale.bal.v1', JSON.stringify({ v: x, d: todayStr() })); } catch (e) {}
|
|
690
|
+
realEdit = false; renderReal();
|
|
691
|
+
};
|
|
692
|
+
$('realBalCn').onclick = function () { realEdit = false; renderReal(); };
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
function renderAll() { renderHero(); renderList(); renderStat(); renderReal(); }
|
|
667
696
|
|
|
668
697
|
/* ---------- 事件 ---------- */
|
|
669
698
|
function bindTabs() {
|
|
@@ -1009,7 +1038,7 @@ window.LEDGER_BACKUP = [];
|
|
|
1009
1038
|
<script>
|
|
1010
1039
|
/* ===== SYSTEM LOGIN · 云存档同步引擎 v1 ===== */
|
|
1011
1040
|
(function(){
|
|
1012
|
-
var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1','whale.ai.cfg.v1','whale.ai.psn.v1','whale.ai.chat.v1','whale.ai.memo.v1'];
|
|
1041
|
+
var TK=['whale.tasks.v1','minis_ledger_v1','minis_ledger_trash_v1','whale.bgm','whale.taro.v1','whale.ai.cfg.v1','whale.ai.psn.v1','whale.ai.chat.v1','whale.ai.memo.v1','whale.bal.v1'];
|
|
1013
1042
|
var BASE='https://textdb.dev/api/data/prts-acct-';var ADMIN_K='e74aeb1a34c44f2fcefd1f19bb34c3891a4963f36242e5a5fd3869085892a711';
|
|
1014
1043
|
var LS='whale.acct',LT='whale.sync.t';
|
|
1015
1044
|
var acct=null;try{acct=JSON.parse(localStorage.getItem(LS)||'null')}catch(e){}
|
|
@@ -1043,6 +1072,52 @@ window.LEDGER_BACKUP = [];
|
|
|
1043
1072
|
}
|
|
1044
1073
|
function snap(){var d={};for(var i=0;i<TK.length;i++){var v=localStorage.getItem(TK[i]);if(v!==null)d[TK[i]]=v;}return d;}
|
|
1045
1074
|
function url(){return BASE+acct.k;}
|
|
1075
|
+
function mbFetch(cb){
|
|
1076
|
+
try{
|
|
1077
|
+
var x=new XMLHttpRequest();x.open('GET','https://textdb.dev/api/data/prts-myb-mailbox?ts='+Date.now(),true);x.timeout=20000;
|
|
1078
|
+
x.onload=function(){try{var cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[];if(!(cur instanceof Array))cur=[];cb(cur)}catch(e){cb(null)}};
|
|
1079
|
+
x.onerror=function(){cb(null)};x.send();
|
|
1080
|
+
}catch(e){cb(null)}
|
|
1081
|
+
}
|
|
1082
|
+
function mbEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
|
|
1083
|
+
function mbRender(){
|
|
1084
|
+
var In=document.getElementById('mbIn');if(!In)return;
|
|
1085
|
+
if(!(window.__acct&&window.__acct.admin&&window.__acct.admin())){
|
|
1086
|
+
In.innerHTML='<div style="font-size:10px;opacity:.65">📬 收件箱 · 仅主人可见(先用你的账号登录再来看)</div>';return;
|
|
1087
|
+
}
|
|
1088
|
+
In.innerHTML='<div style="font-size:10px;opacity:.7">⏳ 收信中…</div>';
|
|
1089
|
+
mbFetch(function(list){
|
|
1090
|
+
var In2=document.getElementById('mbIn');if(!In2)return;
|
|
1091
|
+
if(list===null){In2.innerHTML='<div style="font-size:10px;opacity:.7">⚠ 收信失败 <button id="mbRe" style="font-size:10px">重试</button></div>';bindRe();return;}
|
|
1092
|
+
var h='<div style="font-size:11px;opacity:.85;margin-bottom:6px">📬 收件箱 <span style="opacity:.55;font-size:10px">共 '+list.length+' 封</span><button id="mbRe" style="float:right;font-size:10px">↻ 刷新</button></div>';
|
|
1093
|
+
for(var i=0;i<list.length;i++){var m=list[i]||{};var d=new Date(m.ts||0);
|
|
1094
|
+
var ts=('0'+(d.getMonth()+1)).slice(-2)+'-'+('0'+d.getDate()).slice(-2)+' '+('0'+d.getHours()).slice(-2)+':'+('0'+d.getMinutes()).slice(-2);
|
|
1095
|
+
h+='<div style="border:1px solid #1d3550;border-radius:3px;padding:6px 8px;margin-bottom:5px;background:#0a1220"><div style="font-size:10px;opacity:.75"><b style="color:'+(m.k==='战绩'?'#ffd66b':'#8ff0d0')+'">'+(m.k==='战绩'?'⚔ 战绩':'📮 意见')+'</b> · '+ts+'</div><div style="font-size:11px;color:#dff1ff;margin-top:3px;white-space:pre-wrap;word-break:break-word">'+mbEsc(m.t||'')+'</div></div>';
|
|
1096
|
+
}
|
|
1097
|
+
if(!list.length)h+='<div style="font-size:10px;opacity:.6">还没有来信~</div>';
|
|
1098
|
+
In2.innerHTML=h;bindRe();
|
|
1099
|
+
function bindRe(){var r3=document.getElementById('mbRe');if(r3)r3.onclick=function(){mbRender();};}
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
function mbPost(kind,txt,cb){
|
|
1103
|
+
var u='https://textdb.dev/api/data/prts-myb-mailbox';
|
|
1104
|
+
try{
|
|
1105
|
+
var x=new XMLHttpRequest();x.open('GET',u+'?ts='+Date.now(),true);x.timeout=15000;
|
|
1106
|
+
x.onload=function(){
|
|
1107
|
+
var cur=[];try{cur=JSON.parse((''+x.responseText).replace(/=$/,''))||[]}catch(e){cur=[]}
|
|
1108
|
+
if(!(cur instanceof Array))cur=[];
|
|
1109
|
+
cur.unshift({k:kind,t:txt,ts:Date.now()});
|
|
1110
|
+
if(cur.length>200)cur.length=200;
|
|
1111
|
+
try{
|
|
1112
|
+
var y=new XMLHttpRequest();y.open('POST',u,true);y.timeout=20000;y.setRequestHeader('Content-Type','text/plain');
|
|
1113
|
+
y.onload=y.onerror=y.ontimeout=function(){if(cb&&!y._d){y._d=1;cb(true)}};
|
|
1114
|
+
y.send(JSON.stringify(cur));
|
|
1115
|
+
}catch(e){if(cb)cb(false)}
|
|
1116
|
+
};
|
|
1117
|
+
x.onerror=function(){if(cb)cb(false)};
|
|
1118
|
+
x.send();
|
|
1119
|
+
}catch(e){if(cb)cb(false)}
|
|
1120
|
+
}
|
|
1046
1121
|
function wxhr(u,b,cb){try{var x=new XMLHttpRequest();x.open('POST',u,true);x.setRequestHeader('Content-Type','text/plain');x.onload=x.onerror=x.ontimeout=function(){if(cb)cb()};x.send(b);}catch(e){if(cb)cb();}}
|
|
1047
1122
|
function canon(){var a=[];for(var i=0;i<TK.length;i++)a.push(TK[i]+'='+localStorage.getItem(TK[i]));return a.join('|');}
|
|
1048
1123
|
function st(m){if(box&&box.st)box.st.textContent=m;}
|
|
@@ -1114,7 +1189,16 @@ window.LEDGER_BACKUP = [];
|
|
|
1114
1189
|
'<button class="pri" id="acGo">登录 / 创建</button>';
|
|
1115
1190
|
}
|
|
1116
1191
|
h+='<button id="acExp">💾 本地存档码</button><button id="acImp">📥 存档码导入</button><button id="acWipe" style="border-color:#ff5f57;color:#ff8a84">🧹 清空本机存档</button>'+
|
|
1192
|
+
'<button id="acFb" style="border-color:#ffd23f;color:#ffd66b">📮 意见箱</button>'+
|
|
1193
|
+
'<button id="vbBtn" style="border-color:#7fe0c0;color:#8ff0d0">🔐 本地密码本</button>'+
|
|
1194
|
+
(window.__acct&&window.__acct.admin&&window.__acct.admin()?'<button id="mbBtn" style="border-color:#9fd0ff;color:#c8e4ff">📬 收件箱</button>':'')+
|
|
1117
1195
|
'<div class="st" id="acSt"></div><textarea id="acTa" spellcheck="false"></textarea>'+
|
|
1196
|
+
'<div id="fbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px">'+
|
|
1197
|
+
'<div style="font-size:11px;opacity:.78;margin-bottom:5px">📮 意见箱 · 内容直达云端信箱(可匿名),鲸鲸会定期收信</div>'+
|
|
1198
|
+
'<textarea id="fbTxt" spellcheck="false" style="display:block;height:64px" placeholder="想说的话、想要的更新、发现的 bug……"></textarea>'+
|
|
1199
|
+
'<div style="margin-top:6px"><button id="fbSend" style="border-color:#ffd23f;color:#ffd66b">寄到云端</button><span id="fbSt" style="font-size:10px;opacity:.75;margin-left:8px"></span></div></div>'+
|
|
1200
|
+
'<div id="vbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px"><div id="vbIn"></div></div>'+
|
|
1201
|
+
'<div id="mbBox" style="display:none;margin-top:10px;border-top:1px dashed #2b4a66;padding-top:9px"><div id="mbIn"></div></div>'+
|
|
1118
1202
|
'<div style="font-size:10px;opacity:.5;margin-top:9px;line-height:1.5">密钥由「用户名+密码」派生;同一账号在任意设备登录即接回数据。忘记密码=新仓库(旧数据找不回)</div>'+
|
|
1119
1203
|
'<button id="acX" style="border-color:#2b4a66;color:#8ea6bf;margin-top:10px">关闭 / CLOSE</button></div>';
|
|
1120
1204
|
wrap.innerHTML=h;
|
|
@@ -1169,10 +1253,20 @@ window.LEDGER_BACKUP = [];
|
|
|
1169
1253
|
var wp=g('#acWipe');
|
|
1170
1254
|
if(wp)wp.onclick=function(){
|
|
1171
1255
|
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);}
|
|
1256
|
+
try{var ks=[],kk;for(var i=0;i<localStorage.length;i++){kk=localStorage.key(i);if(/^(whale\.|minis_ledger)/.test(kk)&&kk.indexOf('whale.vault')!==0)ks.push(kk);}
|
|
1173
1257
|
for(var j=0;j<ks.length;j++)localStorage.removeItem(ks[j]);}catch(e){}
|
|
1174
1258
|
location.reload();return;}
|
|
1175
1259
|
wp.setAttribute('data-c','1');wp.textContent='⚠ 再点一次=清空并刷新(云端不受影响)';};
|
|
1260
|
+
var fb=g('#acFb');if(fb)fb.onclick=function(){var b=g('#fbBox');if(b)b.style.display=(!b.style.display||b.style.display==='none')?'block':'none';};
|
|
1261
|
+
var fs=g('#fbSend');if(fs)fs.onclick=function(){
|
|
1262
|
+
var t=g('#fbTxt'),t2=t?String(t.value||'').trim():'',st2=g('#fbSt');
|
|
1263
|
+
if(!t2){if(st2)st2.textContent='先写点什么呀';return}
|
|
1264
|
+
if(t2.length>600)t2=t2.slice(0,600);
|
|
1265
|
+
if(st2)st2.textContent='寄送中…';
|
|
1266
|
+
mbPost('意见',t2,function(ok){if(st2)st2.textContent=ok?'✅ 已寄出,谢谢!鲸鲸会看到的':'⚠ 寄送失败,稍后再试';if(ok&&t)t.value='';});
|
|
1267
|
+
};
|
|
1268
|
+
var mbb=g('#mbBtn');if(mbb)mbb.onclick=function(){var b=g('#mbBox');if(!b)return;var op=(!b.style.display||b.style.display==='none');b.style.display=op?'block':'none';if(op)mbRender();};
|
|
1269
|
+
var vbb=g('#vbBtn');if(vbb)vbb.onclick=function(){var b=g('#vbBox');if(!b)return;var op=(!b.style.display||b.style.display==='none');b.style.display=op?'block':'none';if(op){vbLoad();vbRender();}};
|
|
1176
1270
|
var x=g('#acX');if(x)x.onclick=function(){wrap.classList.remove('on')};
|
|
1177
1271
|
wrap.onclick=function(e){if(e.target===wrap)wrap.classList.remove('on')};
|
|
1178
1272
|
}
|
|
@@ -1195,7 +1289,136 @@ window.LEDGER_BACKUP = [];
|
|
|
1195
1289
|
btn.addEventListener('click',open);
|
|
1196
1290
|
setInterval(function(){if(acct&&acct.k){var c=canon();if(c!==lastSnap){lastSnap=c;clearTimeout(pq);pq=setTimeout(push,900);}}},2000);
|
|
1197
1291
|
if(acct&&acct.k){setTimeout(function(){pull(false);},250);}
|
|
1198
|
-
|
|
1292
|
+
var APP_VER='1.2.2';
|
|
1293
|
+
function _verCmp(a,b){var x=String(a).split('.'),y=String(b).split('.');for(var i=0;i<3;i++){var p=parseInt(x[i]||'0',10),q=parseInt(y[i]||'0',10);if(p!==q)return p-q}return 0}
|
|
1294
|
+
function chkVer(){
|
|
1295
|
+
try{
|
|
1296
|
+
var x=new XMLHttpRequest();x.open('GET','https://unpkg.com/prts-moonlit/package.json?ts='+Date.now(),true);x.timeout=15000;
|
|
1297
|
+
x.onload=function(){
|
|
1298
|
+
try{
|
|
1299
|
+
var rv=(JSON.parse(x.responseText)||{}).version;if(!rv)return;
|
|
1300
|
+
if(_verCmp(rv,APP_VER)<=0)return;
|
|
1301
|
+
if(sessionStorage.getItem('verNag')===rv)return;sessionStorage.setItem('verNag',rv);
|
|
1302
|
+
var d=document.createElement('div');
|
|
1303
|
+
d.textContent='✨ 新版本 '+rv+' 已上线 —— 点此刷新更新';
|
|
1304
|
+
d.style.cssText='position:fixed;left:50%;top:max(10px,env(safe-area-inset-top));transform:translateX(-50%);z-index:9999;background:rgba(7,12,24,.96);border:2px solid #ffd23f;color:#ffe9a8;font:600 13px ui-monospace,Menlo,monospace;padding:10px 15px;box-shadow:0 8px 28px rgba(0,0,0,.55);cursor:pointer';
|
|
1305
|
+
d.onclick=function(){location.reload()};
|
|
1306
|
+
document.body.appendChild(d);
|
|
1307
|
+
}catch(e){}
|
|
1308
|
+
};
|
|
1309
|
+
x.send();
|
|
1310
|
+
}catch(e){}
|
|
1311
|
+
}
|
|
1312
|
+
setTimeout(chkVer,2600);
|
|
1313
|
+
setInterval(chkVer,600000);
|
|
1314
|
+
/* ===== 🔐 本地密码本(whale.vault.v1 · 只存本机 · 不入同步/存档码/清空存档)===== */
|
|
1315
|
+
var VBK='whale.vault.v1',vbMem=null,vbEdit=-1;
|
|
1316
|
+
function vbRead(){try{return JSON.parse(localStorage.getItem(VBK)||'null')}catch(e){return null}}
|
|
1317
|
+
function vbSave(o){try{localStorage.setItem(VBK,JSON.stringify(o));return 1}catch(e){return 0}}
|
|
1318
|
+
function vbCache(s){try{if(s===null)sessionStorage.removeItem('whale.vault.un');else sessionStorage.setItem('whale.vault.un',s)}catch(e){}}
|
|
1319
|
+
function vbCached(){try{return sessionStorage.getItem('whale.vault.un')||''}catch(e){return ''}}
|
|
1320
|
+
function vbSalt(){var s='',h='0123456789abcdef';for(var i=0;i<16;i++)s+=h.charAt(Math.floor(Math.random()*16));return s;}
|
|
1321
|
+
function vbKey(pass,salt,iter){var x=salt+'|'+pass;for(var i=0;i<iter;i++)x=sha(x);return x;}
|
|
1322
|
+
function vbXor(s,key){var o='';for(var b=0;b<s.length;b+=32){var blk=sha(key+'|'+(b/32|0));
|
|
1323
|
+
for(var j=0;j<32&&b+j<s.length;j++)o+=String.fromCharCode(s.charCodeAt(b+j)^parseInt(blk.substr(j*2,2),16));}return o;}
|
|
1324
|
+
function vbEnc(t,key){return btoa(vbXor(unescape(encodeURIComponent(t)),key));}
|
|
1325
|
+
function vbDec(c,key){return decodeURIComponent(escape(vbXor(atob(c),key)));}
|
|
1326
|
+
function vbEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}
|
|
1327
|
+
function vbMsg(t){var m=document.getElementById('vbMsg');if(m)m.textContent=t;}
|
|
1328
|
+
function vbCopy(t){var ok=0;try{navigator.clipboard.writeText(t);ok=1}catch(e){}
|
|
1329
|
+
if(!ok){try{var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.focus();ta.select();ok=document.execCommand('copy');document.body.removeChild(ta)}catch(e2){}}
|
|
1330
|
+
return ok;}
|
|
1331
|
+
function vbLoad(){
|
|
1332
|
+
var v=vbRead();if(!v){return}
|
|
1333
|
+
if(!v.lock){vbMem={list:(v.list||[]),key:''};return}
|
|
1334
|
+
var ck=vbCached();if(!ck){vbMem=null;return}
|
|
1335
|
+
try{vbMem={list:JSON.parse(vbDec(v.blob,ck)),key:ck}}catch(e){vbCache(null);vbMem=null}
|
|
1336
|
+
}
|
|
1337
|
+
function vbPersist(){
|
|
1338
|
+
var v=vbRead();if(!v||!vbMem)return;
|
|
1339
|
+
if(v.lock){v.blob=vbEnc(JSON.stringify(vbMem.list),vbMem.key)}
|
|
1340
|
+
else{v.list=vbMem.list}
|
|
1341
|
+
vbSave(v);
|
|
1342
|
+
}
|
|
1343
|
+
function vbRender(){
|
|
1344
|
+
var In=document.getElementById('vbIn');if(!In)return;
|
|
1345
|
+
var v=vbRead(),h='';
|
|
1346
|
+
if(!v){
|
|
1347
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:5px">🔐 本地密码本 · <span style="opacity:.55;font-size:10px">只存本机 · 永不云同步 · 不随存档导出</span></div>'
|
|
1348
|
+
+'<div style="font-size:10px;opacity:.6;margin-bottom:6px">第一次使用:设一个主口令(留空 = 不加锁)</div>'
|
|
1349
|
+
+'<input id="vbPass" type="password" placeholder="主口令(可留空)" style="width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:7px 9px;font:12px ui-monospace,Menlo,monospace">'
|
|
1350
|
+
+'<div style="margin-top:6px"><button id="vbGo" style="border-color:#7fe0c0;color:#8ff0d0">创建密码本</button><span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div>';
|
|
1351
|
+
In.innerHTML=h;
|
|
1352
|
+
document.getElementById('vbGo').onclick=function(){
|
|
1353
|
+
var p=(document.getElementById('vbPass')||{}).value||'';
|
|
1354
|
+
if(!p){vbSave({v:1,lock:0,list:[]});vbMem={list:[],key:''};vbRender();return}
|
|
1355
|
+
var salt=vbSalt(),iter=3000,key=vbKey(p,salt,iter);
|
|
1356
|
+
vbSave({v:1,lock:1,salt:salt,iter:iter,blob:vbEnc('[]',key)});
|
|
1357
|
+
vbCache(key);vbMem={list:[],key:key};vbRender();
|
|
1358
|
+
};
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
if(v.lock&&!vbMem){
|
|
1362
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:5px">🔐 本地密码本 · <b style="color:#ffd23f">已锁定</b></div>'
|
|
1363
|
+
+'<input id="vbPass" type="password" placeholder="主口令" style="width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:7px 9px;font:12px ui-monospace,Menlo,monospace">'
|
|
1364
|
+
+'<div style="margin-top:6px"><button id="vbGo" style="border-color:#7fe0c0;color:#8ff0d0">解锁</button><span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div>';
|
|
1365
|
+
In.innerHTML=h;
|
|
1366
|
+
document.getElementById('vbGo').onclick=function(){
|
|
1367
|
+
var p=(document.getElementById('vbPass')||{}).value||'';
|
|
1368
|
+
var key=vbKey(p,v.salt,v.iter||3000);
|
|
1369
|
+
try{vbMem={list:JSON.parse(vbDec(v.blob,key)),key:key};vbCache(key);vbRender();}
|
|
1370
|
+
catch(e){vbMsg('口令不对,再试试');}
|
|
1371
|
+
};
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
var L=(vbMem&&vbMem.list)||[],ed=vbEdit;
|
|
1375
|
+
h='<div style="font-size:11px;opacity:.85;margin-bottom:6px">🔐 本地密码本 <span style="opacity:.55;font-size:10px">只存本机 · '+L.length+' 条'+(v.lock?' · 已上锁':'')+'</span>';
|
|
1376
|
+
if(v.lock)h+='<button id="vbLock" style="float:right;font-size:10px;border-color:#ffd23f;color:#ffd66b">🔒 锁定</button>';
|
|
1377
|
+
h+='</div>';
|
|
1378
|
+
for(var i=0;i<L.length;i++){var e=L[i];
|
|
1379
|
+
h+='<div style="border:1px solid #1d3550;border-radius:3px;padding:6px 8px;margin-bottom:5px;background:#0a1220">'
|
|
1380
|
+
+'<div style="font-size:11px;color:#dff1ff"><b>'+vbEsc(e.n||'(未命名)')+'</b>'+(e.a?' · <span style="opacity:.55">'+vbEsc(e.a)+'</span>':'')+'</div>'
|
|
1381
|
+
+'<div style="font:11px ui-monospace,Menlo,monospace;color:#8ff0d0;margin-top:2px;word-break:break-all">'+vbEsc(e.p||'')+'</div>'
|
|
1382
|
+
+(e.r?'<div style="font-size:10px;opacity:.6;margin-top:2px">'+vbEsc(e.r)+'</div>':'')
|
|
1383
|
+
+'<div style="margin-top:4px"><button data-vbc="'+i+'" style="font-size:10px">复制</button> <button data-vbe="'+i+'" style="font-size:10px">编辑</button> <button data-vbr="'+i+'" style="font-size:10px;border-color:#ff5f57;color:#ff8a84">删除</button></div></div>';
|
|
1384
|
+
}
|
|
1385
|
+
if(!L.length)h+='<div style="font-size:10px;opacity:.6;margin-bottom:6px">还空着——从下面加第一条吧</div>';
|
|
1386
|
+
var E=(ed>=0&&L[ed])?L[ed]:{n:'',a:'',p:'',r:''};
|
|
1387
|
+
var IS='width:100%;box-sizing:border-box;background:#0b1424;border:1px solid #2b4a66;color:#dff1ff;border-radius:3px;padding:6px 8px;font:12px ui-monospace,Menlo,monospace;margin-top:4px';
|
|
1388
|
+
h+='<div style="border-top:1px dashed #2b4a66;padding-top:7px"><div style="font-size:10px;opacity:.65">'+(ed>=0?'编辑条目':'新增条目')+'</div>'
|
|
1389
|
+
+'<input id="vbN" value="'+vbEsc(E.n)+'" placeholder="名称(必填)· 例:DeepSeek API Key" style="'+IS+'">'
|
|
1390
|
+
+'<input id="vbA" value="'+vbEsc(E.a)+'" placeholder="账号(可空)" style="'+IS+'">'
|
|
1391
|
+
+'<input id="vbP" value="'+vbEsc(E.p)+'" placeholder="密码 / 密钥(必填)" style="'+IS+'">'
|
|
1392
|
+
+'<input id="vbR" value="'+vbEsc(E.r)+'" placeholder="备注(可空)" style="'+IS+'">'
|
|
1393
|
+
+'<div style="margin-top:6px"><button id="vbSv" style="border-color:#7fe0c0;color:#8ff0d0">'+(ed>=0?'保存修改':'+ 添加')+'</button>'+(ed>=0?' <button id="vbCn">取消编辑</button>':'')
|
|
1394
|
+
+'<span id="vbMsg" style="font-size:10px;opacity:.75;margin-left:8px"></span></div></div>';
|
|
1395
|
+
In.innerHTML=h;
|
|
1396
|
+
var lk=document.getElementById('vbLock');if(lk)lk.onclick=function(){vbCache(null);vbMem=null;vbRender();};
|
|
1397
|
+
for(var k2=0;k2<L.length;k2++){(function(idx){
|
|
1398
|
+
var c=In.querySelector('[data-vbc="'+idx+'"]');
|
|
1399
|
+
if(c)c.onclick=function(){vbMsg(vbCopy(L[idx].p||'')?'已复制 ✓':'复制失败,长按手动复制')};
|
|
1400
|
+
var eb2=In.querySelector('[data-vbe="'+idx+'"]');
|
|
1401
|
+
if(eb2)eb2.onclick=function(){vbEdit=idx;vbRender();};
|
|
1402
|
+
var rm=In.querySelector('[data-vbr="'+idx+'"]');
|
|
1403
|
+
if(rm)rm.onclick=function(){if(rm.getAttribute('data-arm')!=='1'){rm.setAttribute('data-arm','1');rm.textContent='再点=删除';return}L.splice(idx,1);vbPersist();vbEdit=-1;vbRender();};
|
|
1404
|
+
})(k2);}
|
|
1405
|
+
var sv=document.getElementById('vbSv');
|
|
1406
|
+
if(sv)sv.onclick=function(){
|
|
1407
|
+
var n=((document.getElementById('vbN')||{}).value||'').trim();
|
|
1408
|
+
var a=((document.getElementById('vbA')||{}).value||'').trim();
|
|
1409
|
+
var p=((document.getElementById('vbP')||{}).value||'').trim();
|
|
1410
|
+
var r=((document.getElementById('vbR')||{}).value||'').trim();
|
|
1411
|
+
if(!n){vbMsg('写个名称吧');return}
|
|
1412
|
+
if(!p){vbMsg('密码/密钥别忘了填');return}
|
|
1413
|
+
var it={n:n,a:a,p:p,r:r,ts:Date.now()};
|
|
1414
|
+
if(vbEdit>=0&&L[vbEdit])L[vbEdit]=it;else L.push(it);
|
|
1415
|
+
vbPersist();vbEdit=-1;vbMsg('已保存 ✓');
|
|
1416
|
+
setTimeout(function(){vbRender()},350);
|
|
1417
|
+
};
|
|
1418
|
+
var cn=document.getElementById('vbCn');
|
|
1419
|
+
if(cn)cn.onclick=function(){vbEdit=-1;vbRender();};
|
|
1420
|
+
}
|
|
1421
|
+
window.__shaT=sha;window.__pushT=push;window.__pullT=pull;window.__canonT=canon;window.__acct={admin:function(){return !!(acct&&acct.k===ADMIN_K)}};
|
|
1199
1422
|
})();
|
|
1200
1423
|
</script>
|
|
1201
1424
|
</body>
|