@@ -2433,7 +2445,85 @@ document.querySelectorAll('.notif-row.is-expandable').forEach(function(row){
});
// 账户入口
$('#rowSettings').addEventListener('click', ()=>subOpen('settings'));
-$('#rowRouting').addEventListener('click', ()=>subOpen('routing'));
+$('#rowRouting').addEventListener('click', ()=>{ subOpen('routing'); renderRouting(); });
+
+/* ========= 分流规则:代理模式切换 + 添加/导入/重置 ========= */
+(function(){
+ if(!state.routeMode) state.routeMode='smart';
+ const _t=(zh,en)=>state.lang==='zh'?zh:en;
+ const _esc=s=>String(s).replace(/&/g,'&').replace(//g,'>');
+ const INP='padding:10px 12px;border-radius:var(--radius-md);border:1px solid var(--border);background:var(--bg-subtle);color:var(--fg1);font-size:14px;font-family:inherit;width:100%;box-sizing:border-box';
+
+ window.renderRouting=function(){
+ const mode=state.routeMode||'smart', smart=mode==='smart';
+ document.querySelectorAll('#rtModeSeg button').forEach(b=>b.classList.toggle('is-active', b.dataset.mode===mode));
+ ['rtCnRow','rtMyRules'].forEach(id=>{ const el=document.getElementById(id); if(!el) return; el.style.opacity=smart?'':'.4'; el.style.pointerEvents=smart?'':'none'; });
+ const fp=document.getElementById('rtFinalPill');
+ if(fp){ if(mode==='direct'){ fp.textContent=_t('直连','Direct'); fp.className='pill is-success'; } else { fp.textContent=_t('走隧道','Tunnel'); fp.className='pill is-warning'; } }
+ const note=document.getElementById('rtModeNote');
+ if(note){
+ if(smart) note.innerHTML=_t('「我的规则」仅在
智能分流模式生效;全局 / 直连为一刀切,忽略自定义规则(系统强制层仍保留)。','Rules apply only in
Smart routing; Global / Direct are one-size modes that ignore custom rules (system-forced layer stays).');
+ else if(mode==='global') note.innerHTML=_t('
全局代理:所有流量走隧道,忽略国内直连与自定义规则(系统强制层仍保留)。','
Global proxy: all traffic tunnels; China-direct and custom rules ignored (system-forced layer stays).');
+ else note.innerHTML=_t('
全部直连:所有流量直连,忽略自定义规则(系统强制层仍保留)。','
Direct: all traffic goes direct; custom rules ignored (system-forced layer stays).');
+ }
+ };
+ document.querySelectorAll('#rtModeSeg button').forEach(b=>b.addEventListener('click', ()=>{ state.routeMode=b.dataset.mode; renderRouting(); }));
+
+ const openM=id=>{ const m=document.getElementById(id); if(m){ m.classList.add('is-open'); m.onclick=e=>{ if(e.target===m) m.classList.remove('is-open'); }; } };
+ const closeM=id=>{ const m=document.getElementById(id); if(m) m.classList.remove('is-open'); };
+ const pillFor=act=> act==='proxy'?'
'+_t('走隧道','Tunnel')+'' : act==='reject'?'
'+_t('拒绝','Reject')+'' : '
'+_t('直连','Direct')+'';
+ const TYPE={domain_suffix:['域名后缀','Domain suffix'],domain:['域名','Domain'],ip_cidr:['IP-CIDR','IP-CIDR'],geosite:['GeoSite','GeoSite'],geoip:['GeoIP','GeoIP']};
+ function addRuleRow(type,val,act,prepend){
+ const list=document.getElementById('rtRulesList'); if(!list) return;
+ const tl=TYPE[type]||[type,type];
+ const row=document.createElement('div'); row.className='setting-row';
+ row.innerHTML='
≡'+_esc(val)+'
'+_t(tl[0],tl[1])+'
'+pillFor(act)+'
';
+ if(prepend) list.insertBefore(row,list.firstChild); else list.appendChild(row);
+ }
+ const _defaultRules=(()=>{ const l=document.getElementById('rtRulesList'); return l?l.innerHTML:''; })();
+
+ function openAdd(){
+ const win=document.getElementById('rtAddWin');
+ win.innerHTML='
'+_t('添加规则','Add rule')+'
'
+ +'
'
+ +'
'
+ +'
'
+ +'
'+_t('动作','Action')+' '
+ +'
'
+ +'
';
+ let act='direct';
+ win.querySelectorAll('#rtActSeg button').forEach(b=>b.addEventListener('click',()=>{ act=b.dataset.act; win.querySelectorAll('#rtActSeg button').forEach(x=>x.classList.toggle('is-active',x===b)); }));
+ win.querySelector('#rtAddClose').addEventListener('click',()=>closeM('rtAddModal'));
+ win.querySelector('#rtAddCancel').addEventListener('click',()=>closeM('rtAddModal'));
+ win.querySelector('#rtAddOk').addEventListener('click',()=>{ const v=(win.querySelector('#rtAddVal').value||'').trim(); if(!v){ win.querySelector('#rtAddVal').focus(); return; } addRuleRow(win.querySelector('#rtAddType').value,v,act,true); closeM('rtAddModal'); });
+ openM('rtAddModal');
+ }
+ function openImport(){
+ const win=document.getElementById('rtImportWin');
+ win.innerHTML='
'+_t('从文本导入','Import from text')+'
'
+ +'
'+_t('每行一条:目标,动作(direct / proxy / reject)','One per line: target,action (direct / proxy / reject)')+'
'
+ +'
'
+ +'
';
+ win.querySelector('#rtImpClose').addEventListener('click',()=>closeM('rtImportModal'));
+ win.querySelector('#rtImpCancel').addEventListener('click',()=>closeM('rtImportModal'));
+ win.querySelector('#rtImpOk').addEventListener('click',()=>{ (win.querySelector('#rtImpText').value||'').split('\n').forEach(ln=>{ const p=ln.split(','); const v=(p[0]||'').trim(); const a=(p[1]||'proxy').trim().toLowerCase(); if(!v) return; const type=/^[\d.]+\/\d+$/.test(v)?'ip_cidr':'domain_suffix'; addRuleRow(type,v,a==='direct'?'direct':a==='reject'?'reject':'proxy',false); }); closeM('rtImportModal'); });
+ openM('rtImportModal');
+ }
+ function openReset(){
+ const win=document.getElementById('rtResetWin');
+ win.innerHTML='
'
+ +'
'+_t('重置为默认规则?','Reset to defaults?')+'
'
+ +'
'+_t('将清除你自定义的所有规则,恢复到出厂分流表。','Clears all your custom rules and restores the factory routing table.')+'
'
+ +'
';
+ win.querySelector('#rtRstCancel').addEventListener('click',()=>closeM('rtResetModal'));
+ win.querySelector('#rtRstOk').addEventListener('click',()=>{ const l=document.getElementById('rtRulesList'); if(l) l.innerHTML=_defaultRules; closeM('rtResetModal'); });
+ openM('rtResetModal');
+ }
+ const b1=document.getElementById('rtAddBtn'); if(b1) b1.addEventListener('click',openAdd);
+ const b2=document.getElementById('rtImportBtn'); if(b2) b2.addEventListener('click',openImport);
+ const b3=document.getElementById('rtResetBtn'); if(b3) b3.addEventListener('click',openReset);
+ renderRouting();
+})();
$('#rowContact').addEventListener('click', ()=>subOpen('contact'));
$('#rowInvite').addEventListener('click', ()=>subOpen('invite'));
$('#rowRedeem').addEventListener('click', ()=>subOpen('redeem'));