فهرست منبع

浏览器兼容更新

liuchengsen 3 هفته پیش
والد
کامیت
7181716e33
1فایلهای تغییر یافته به همراه29 افزوده شده و 17 حذف شده
  1. 29 17
      static/index.html

+ 29 - 17
static/index.html

@@ -69,7 +69,7 @@
     .brand-card-arrow{float:right;font-size:13px;color:#c4a035;margin-left:8px}
     .brand-more-btn{display:block;width:100%;padding:8px;margin-top:6px;background:#fffdf5;border:1px dashed #e0c080;border-radius:8px;font-size:12px;color:#b8860b;cursor:pointer;text-align:center;transition:all .15s}
     .brand-more-btn:hover{background:#fff8e1;border-color:#d4a017}
-    .brand-detail-overlay{position:fixed;inset:0;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;z-index:200;padding:20px}
+    .brand-detail-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;z-index:200;padding:20px}
     .brand-detail-box{background:#fff;border-radius:14px;max-width:420px;width:100%;max-height:85vh;overflow-y:auto;box-shadow:0 8px 32px rgba(0,0,0,.18)}
     .brand-detail-header{position:sticky;top:0;background:#fff;padding:16px 18px 10px;border-bottom:1px solid #eee;z-index:1}
     .brand-detail-header h2{font-size:17px;color:var(--bk);margin:0 0 4px}
@@ -123,7 +123,7 @@
     .pager button:disabled{opacity:.35;cursor:default}
     .pager .page-info{font-size:12px;color:#888;margin:0 4px;white-space:nowrap}
     .pager select{padding:6px 8px;appearance:auto}
-    .login-modal-mask{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,.5);z-index:100}
+    .login-modal-mask{position:fixed;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,.5);z-index:100}
     .login-modal{width:min(320px,100%);overflow:hidden;border-radius:12px;background:#fff;box-shadow:0 12px 36px rgba(0,0,0,.2);text-align:center}
     .login-modal-title{padding:24px 24px 8px;color:var(--text);font-size:17px;font-weight:700}
     .login-modal-desc{padding:0 24px 24px;color:var(--sub);font-size:14px;line-height:1.6}
@@ -264,11 +264,11 @@
     h=h.replace(/\[([^\]]+)\]\((https?:\/\/[^\s<>)]+)\)/g,'<a href="$2" target="_blank" rel="noopener" class="ext-link">$1</a>');
     h=h.replace(/——— 原文参考 ———/g,"<h3>📖 原文参考</h3>");
     var s='(?:结论|详细说明|注意事项|来源明细|适应症|用法与用量|用法用量|禁忌|不良反应|副作用|药理|药物相互作用|贮藏|特殊人群|安全提醒|就医指征|非药物建议|用药建议|用药方案|通用药学知识|来源汇总|病情评估|处理方案|免责声明|AI 声明|AI声明|来源说明)';
-    h=h.replace(new RegExp('(?<![【])】\\s*('+s+')','g'),'【$1】');
-    h=h.replace(new RegExp('(?<![【])('+s+')】','g'),'【$1】');
+    h=h.replace(new RegExp('】\\s*('+s+')','g'),function(m,name,off,whole){if(off>0&&whole.charAt(off-1)==='【')return m;return'【'+name+'】'});
+    h=h.replace(new RegExp('('+s+')】','g'),function(m,name,off,whole){if(off>0&&whole.charAt(off-1)==='【')return m;return'【'+name+'】'});
     // 去掉"来源引用"括号内多余的【栏目】标记,避免被当成栏目标题拆行
     for(var k=0;k<3;k++){var _p=h;h=h.replace(/((来源:[^)]*)【[^】]*?】([^)]*))/g,'$1$2');if(h===_p)break;}
-    h=h.replace(/(?<![<br>\n])【(.+?)】/g,'<br>【$1】');
+    h=h.replace(/【(.+?)】/g,function(m,inner,off,whole){if(off===0)return'<br>'+m;var pre=whole.charAt(off-1);if(pre==='<'||pre==='b'||pre==='r'||pre==='>'||pre==='\n')return m;return'<br>'+m});
     h=h.replace(/\n\n+/g,'</p><p>');h=h.replace(/\n/g,'<br>');
     // LLM prompts 产生的栏目标题(大标题样式)
   var PROMPT_SECTIONS='结论|详细说明|详细信息|注意事项|来源明细|适应症|用法与用量|用法用量|禁忌|不良反应|副作用|药理|药代动力学|药物相互作用|贮藏|特殊人群|安全提醒|就医指征|非药物建议|用药建议|用药方案|通用药学知识|来源汇总|病情评估|处理方案|免责声明|AI 声明|AI声明|来源说明|记忆技巧|考试频率|知识要点|考点定位|摘要|原文引用|条款出处|关联条款|安全提醒|详细内容|来源说明|药物概况';
@@ -284,7 +284,7 @@
     h=h.replace(/(?:<br>|^)(\d+)\.\s+(.+?)(?=<br>|$)/g,'<li>$2</li>');
     h=h.replace(/((?:<li>.*?<\/li>)+)/g,function(m){return m.indexOf('<ul>')>=0?m:'<ol>'+m+'</ol>'});
     h='<p>'+h+'</p>';h=h.replace(/<p>(<br>)*<\/p>/g,'');h=h.replace(/<p><\/p>/g,'');
-    h=h.replace(/(?<!href=")(?<!href=')(?<!">)(?<!'>)(https?:\/\/[^\s<>]+)/g,'<a href="$1" target="_blank" rel="noopener" class="ext-link">$1</a>');
+    h=h.replace(/https?:\/\/[^\s<>]+/g,function(url,off,whole){var pre=whole.substring(Math.max(0,off-6),off);if(/(href=["']|["']>)$/.test(pre))return url;return'<a href="'+url+'" target="_blank" rel="noopener" class="ext-link">'+url+'</a>'});
     h=h.replace(/——— 原文参考 ———/g,"<h3>📖 原文参考</h3>");
     return h;
   }
@@ -455,9 +455,10 @@
       body=JSON.stringify({message:query,request_id:metrics.reqId});
     }
     try{
-      var ctrl=streamAbort?streamAbort:new AbortController();
       var hdrs=authHeaders();if(metrics&&metrics.reqId)hdrs['X-Request-Id']=metrics.reqId;
-      var r=await fetch(endpoint,{method:'POST',headers:hdrs,body:body,signal:ctrl.signal});
+      var fetchOpts={method:'POST',headers:hdrs,body:body};
+      if(streamAbort&&streamAbort.signal!==undefined)fetchOpts.signal=streamAbort.signal;
+      var r=await fetch(endpoint,fetchOpts);
       if(r.status===401){console.warn('需要登录');aiDiv.classList.remove('streaming');STREAMING=false;resetSendBtn();contentDiv.innerHTML=md2html('请先登录后再提问');trackComplete(metrics,'error',{http_status:401});return}
       if(r.status===429){
         var detail='请求过于频繁,请稍后再试';
@@ -467,11 +468,20 @@
       if(!r.ok){contentDiv.innerHTML=md2html('请求失败: HTTP '+r.status);aiDiv.classList.remove('streaming');STREAMING=false;resetSendBtn();trackComplete(metrics,'error',{http_status:r.status});return}
       sourcesData=[];
       brandRecsData=[];
-      var reader=r.body.getReader(),decoder=new TextDecoder(),buffer='',fullText='',eventType='';
+      var buffer='',fullText='',eventType='';
+      var reader;
+      if(r.body&&typeof r.body.getReader==='function'&&window.TextDecoder){
+        reader=r.body.getReader();
+      }else{
+        var _all=await r.text(),_used=false;
+        reader={read:function(){if(_used)return Promise.resolve({done:true});_used=true;return Promise.resolve({done:false,value:_all})}};
+      }
+      var decoder=window.TextDecoder?new TextDecoder():null;
       while(true){
-        var{ done, value }=await reader.read();
-        if(done)break;
-        buffer+=decoder.decode(value,{stream:true});
+        var chunk=await reader.read();
+        if(chunk.done)break;
+        var value=chunk.value;
+        buffer+=(typeof value==='string')?value:decoder.decode(value,{stream:true});
         var lines=buffer.split('\n');buffer=lines.pop()||'';
         for(var i=0;i<lines.length;i++){
           var line=lines[i].trim();
@@ -574,7 +584,7 @@
     doSend(text,hasMedia?pendingMedia:null,reqId);
   };
   function doSend(text,media,reqId){
-    STREAMING=true;streamAbort=new AbortController();
+    STREAMING=true;streamAbort=window.AbortController?new AbortController():null;
     document.getElementById('sendBtn').disabled=true;document.getElementById('stopBtn').style.display='inline-block';
     var w=document.getElementById('chat').querySelector('.welcome');if(w)w.remove();
     var userDisplay=text;
@@ -863,9 +873,11 @@
   };
   window.switchTab=function(tab){
     track('switch_tab', {tab: tab});
-    document.querySelectorAll('.nav-btn').forEach(function(b){b.classList.toggle('active',b.dataset.tab===tab)});
-    document.getElementById('tabChat').classList.toggle('hidden',tab!=='chat');
-    document.getElementById('tabDrugs').classList.toggle('hidden',tab!=='drugs');
+    var btns=document.querySelectorAll('.nav-btn');
+    Array.prototype.forEach.call(btns,function(b){var active=b.getAttribute('data-tab')===tab;if(active){b.classList.add('active')}else{b.classList.remove('active')}});
+    var tabChat=document.getElementById('tabChat'),tabDrugs=document.getElementById('tabDrugs');
+    if(tab==='chat'){tabChat.classList.remove('hidden');tabDrugs.classList.add('hidden')}
+    else{tabChat.classList.add('hidden');tabDrugs.classList.remove('hidden')}
     if(tab==='drugs'){
     drugKeyword='';drugPage=1;lastSearched='';
     showDrugList();
@@ -877,7 +889,7 @@
   // 初始化:打开本地数据库 → 恢复对话 → 预加载药品列表 → 加载快捷提问标签
       (async function init(){
         track('page_view');
-        await openChatDB();
+        try{await openChatDB()}catch(e){chatDB=null}
         await restoreChat();
         loadQuickAsks();
       })();