PageSourceSearch

https://xynergy.ai/_next/static/chunks/1688.961da46509ee7b53.js

js xynergy.ai collected 2026-10-05 16:02:06 UTC 11,623 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1688],{1688:(e,a,t)=>{t.r(a),t.d(a,{default:()=>b});var s=t(85047),r=t(31615),n=t(73521),l=t(41178),c=t(21410),i=t(82520),d=t(96968),o=t(21582),u=t(866),m=t(10892),h=t(62557);let x=[{code:"201",name:"臺銀人壽"},{code:"202",name:"台灣人壽"},{code:"203",name:"保誠人壽"},{code:"204",name:"國泰人壽"},{code:"205",name:"凱基人壽"},{code:"206",name:"南山人壽"},{code:"207",name:"國華人壽"},{code:"208",name:"新光人壽"},{code:"209",name:"富邦人壽"},{code:"210",name:"國寶人壽"},{code:"211",name:"三商美邦人壽"},{code:"212",name:"朝陽人壽"},{code:"215",name:"幸福人壽"},{code:"216",name:"遠雄人壽"},{code:"217",name:"宏泰人壽"},{code:"218",name:"安聯人壽"},{code:"220",name:"中華郵政"},{code:"221",name:"第一金人壽"},{code:"222",name:"合作金庫人壽"},{code:"252",name:"安泰人壽"},{code:"254",name:"中國信託人壽"},{code:"255",name:"台新人壽"},{code:"256",name:"安達國際人壽"},{code:"257",name:"友邦人壽"},{code:"258",name:"宏利人壽"},{code:"261",name:"元大人壽"},{code:"262",name:"環球瑞泰人壽"},{code:"264",name:"全球人壽"},{code:"267",name:"法國巴黎人壽"},{code:"269",name:"安達保險"},{code:"270",name:"安達人壽"},{code:"271",name:"匯豐人壽"},{code:"272",name:"蘇黎世國際人壽"}];x.map(e=>e.code);let j=[{value:"傳統型壽險",label:"傳統型壽險"},{value:"投資型保險",label:"投資型保險"},{value:"健康保險",label:"健康保險"},{value:"傷害保險",label:"傷害保險"},{value:"年金保險",label:"年金保險"}];var p=t(11787);async function g(){let{auth:e}=await Promise.resolve().then(t.bind(t,76458)),a=e?.currentUser;if(!a)throw Error("未登入");let s=await a.getIdToken(!0);return{Authorization:`Bearer ${s}`}}let f="admin:tiiCrawlJobId";function v(e){return Array.from(new Set(e.split(/\r?\n/).map(e=>e.trim()).filter(e=>e.length>0)))}function b({pendingAppendKeyword:e=null}={}){let{user:a}=(0,n.A)(),{toast:t}=(0,l.dj)(),[N,y]=(0,r.useState)(""),[w,S]=(0,r.useState)(""),[C,k]=(0,r.useState)(114),[T,I]=(0,r.useState)(3),[E,F]=(0,r.useState)(""),[A,J]=(0,r.useState)(!1),[R,q]=(0,r.useState)("傳統型壽險"),[B,D]=(0,r.useState)(!1),[P,V]=(0,r.useState)(null),[$,Z]=(0,r.useState)(null),[_,O]=(0,r.useState)(!1),[U,W]=(0,r.useState)(!1),z=(0,r.useCallback)(async e=>{try{let a=await g(),t=await fetch(`/api/admin/tii-crawl/jobs/${e}`,{headers:a});if(!t.ok)return null;return await t.json()}catch{return null}},[]);(0,r.useEffect)(()=>{if(P)return;let e=localStorage.getItem(f);e&&V(e)},[P]);let M=(0,r.useRef)(null);(0,r.useEffect)(()=>{if(!e)return;let a=e.trim();a&&M.current!==a&&(M.current=a,S(e=>{let t=v(e);return t.includes(a)?e:[...t,a].join("\n")}),t({title:"已加入關鍵字",description:a}))},[e,t]),(0,r.useEffect)(()=>{if(!P||!(!$||"pending"===$.status||"running"===$.status))return;let e=setInterval(async()=>{let e=await z(P);e&&Z(e)},2500);return()=>clearInterval(e)},[P,$?.status,z,$]),(0,r.useEffect)(()=>{!a||P&&localStorage.setItem(f,P)},[a,P]),(0,r.useEffect)(()=>{P&&($?.status==="completed"||$?.status==="failed"||$?.status==="cancelled")&&localStorage.removeItem(f)},[P,$?.status]);let G=async()=>{if(P&&!U){W(!0);try{let e=await g(),a=await fetch(`/api/admin/tii-crawl/jobs/${P}/cancel`,{method:"POST",headers:{...e,"Content-Type":"application/json"}}),s=await a.json().catch(()=>({}));if(!a.ok)return void t({variant:"destructive",title:"停止失敗",description:s.error||a.statusText});Z(e=>e?{...e,status:"cancelled"}:e),t({title:"已停止",description:"已送出停止請求,若正在下載中會在短時間內中止。"})}catch(e){t({variant:"destructive",title:"停止失敗",description:e instanceof Error?e.message:String(e)})}finally{W(!1)}}},H=async e=>{if(e.preventDefault(),!a||_)return;let s=v(w),r=s.length>0;if(r||C&&T){O(!0),Z(null);try{let e=await g(),a={company:N,insurance:R||void 0,notDiscontinued:B};r?a.keywords=s:(a.year=Number(C),a.monthFrom=Number(T),A&&(a.monthTo=""!==E?Number(E):Number(T)));let n=await fetch(r?"/api/admin/tii-crawl/run-batch":"/api/admin/tii-crawl/run",{method:"POST",headers:{...e,"Content-Type":"application/json"},body:JSON.stringify(a)}),l=await n.json().catch(()=>({}));if(!n.ok)return void t({variant:"destructive",title:"啟動失敗",description:l.error||n.statusText});
1V(l.jobId),Z({status:"running",mode:r?"batch":"single",params:a,summary:r?{total:s.length,succeeded:0,failed:0,currentIndex:0}:void 0}),t({title:"已開始爬取",description:r?"已啟動爬取,系統會逐筆執行並上傳至 Cloudflare R2(tii-product-documents/)。你可切換到其他頁,回來仍可用同一 jobId 續看進度。":"已啟動爬取(日期模式)。你可切換到其他頁,回來仍可用同一 jobId 續看進度。PDF 會上傳至 Cloudflare R2(tii-product-documents/)。"})}catch(e){t({variant:"destructive",title:"請求失敗",description:e instanceof Error?e.message:String(e)})}finally{O(!1)}}};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(i.Zp,{children:[(0,s.jsxs)(i.aR,{children:[(0,s.jsx)(i.ZB,{children:"保發中心爬取"}),(0,s.jsx)(i.BT,{children:"可依關鍵字查詢(不需設定銷售日區間)或依民國年/月份查詢。關鍵字請使用「每行一筆」輸入,只有 1 行也可以。若關鍵字留空,則會改用日期查詢。僅下載條款與費率(-A / -C)PDF,並上傳至 Cloudflare R2(tii-product-documents/)。"})]}),(0,s.jsx)(i.Wu,{children:(0,s.jsxs)("form",{onSubmit:H,className:"space-y-4",children:[(0,s.jsxs)("div",{className:"grid gap-2",children:[(0,s.jsx)(d.J,{children:"公司"}),(0,s.jsxs)(o.l6,{value:N,onValueChange:y,required:!0,children:[(0,s.jsx)(o.bq,{children:(0,s.jsx)(o.yv,{placeholder:"請選擇壽險公司"})}),(0,s.jsx)(o.gC,{children:x.map(e=>(0,s.jsxs)(o.eb,{value:e.code,children:[e.name," (",e.code,")"]},e.code))})]})]}),(0,s.jsxs)("div",{className:"grid gap-2",children:[(0,s.jsx)(d.J,{children:"關鍵字(每行一筆)"}),(0,s.jsx)(m.T,{value:w,onChange:e=>S(e.target.value),placeholder:"例如:\n美康滿利\n好利旺...",rows:6}),(0,s.jsxs)("p",{className:"text-xs text-muted-foreground",children:["目前有效關鍵字:",v(w).length," 筆(會自動去除空白與重複)。每行可為列表完整商品名,或商品名/前綴(不需對齊公司名稱)。留空則改用日期查詢。"]})]}),0===v(w).length&&(0,s.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,s.jsxs)("div",{className:"grid gap-2",children:[(0,s.jsx)(d.J,{children:"民國年"}),(0,s.jsx)(u.p,{type:"number",min:100,max:200,value:C,onChange:e=>k(Number(e.target.value)||114)})]}),(0,s.jsxs)("div",{className:"grid gap-2",children:[(0,s.jsx)(d.J,{children:"月份"}),(0,s.jsxs)("div",{className:"flex gap-2 items-center flex-wrap",children:[(0,s.jsxs)(o.l6,{value:A?"range":"single",onValueChange:e=>J("range"===e),children:[(0,s.jsx)(o.bq,{className:"w-[100px]",children:(0,s.jsx)(o.yv,{})}),(0,s.jsxs)(o.gC,{children:[(0,s.jsx)(o.eb,{value:"single",children:"單月"}),(0,s.jsx)(o.eb,{value:"range",children:"區間"})]})]}),(0,s.jsxs)(o.l6,{value:String(T),onValueChange:e=>I(Number(e)),children:[(0,s.jsx)(o.bq,{className:"w-[80px]",children:(0,s.jsx)(o.yv,{})}),(0,s.jsx)(o.gC,{children:Array.from({length:12},(e,a)=>a+1).map(e=>(0,s.jsxs)(o.eb,{value:String(e),children:[e," 月"]},e))})]}),A&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("span",{className:"text-muted-foreground",children:"~"}),(0,s.jsxs)(o.l6,{value:""===E?String(T):String(E),onValueChange:e=>F(Number(e)),children:[(0,s.jsx)(o.bq,{className:"w-[80px]",children:(0,s.jsx)(o.yv,{placeholder:"迄"})}),(0,s.jsx)(o.gC,{children:Array.from({length:12},(e,a)=>a+1).map(e=>(0,s.jsxs)(o.eb,{value:String(e),disabled:e<T,children:[e," 月"]},e))})]})]})]})]})]}),(0,s.jsxs)("div",{className:"grid gap-2",children:[(0,s.jsx)(d.J,{children:"險種"}),(0,s.jsxs)(o.l6,{value:R,onValueChange:q,children:[(0,s.jsx)(o.bq,{children:(0,s.jsx)(o.yv,{})}),(0,s.jsx)(o.gC,{children:j.map(e=>(0,s.jsx)(o.eb,{value:e.value,children:e.label},e.value))})]})]}),(0,s.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,s.jsx)(h.S,{id:"notDiscontinued",checked:B,onCheckedChange:e=>D(!0===e)}),(0,s.jsx)(d.J,{htmlFor:"notDiscontinued",className:"cursor-pointer font-normal",children:"查詢未停售"})]}),(0,s.jsx)(c.$,{type:"submit",disabled:_||!N||0===v(w).length&&(!C||!T),children:_?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(p.A,{className:"mr-2 h-4 w-4 animate-spin"}),"啟動中…"]}):"開始爬取"})]})})]}),P&&(0,s.jsxs)(i.Zp,{children:[(0,s.jsxs)(i.aR,{children:[(0,s.jsx)(i.ZB,{children:"執行狀態"}),(0,s.jsxs)(i.BT,{children:[!$&&"(可切換到其他頁,回來仍可續看進度)",$?.status==="running"&&"爬取進行中(可切換到其他頁,回來仍可續看進度)。",$?.
1status==="completed"&&"爬取已完成。",$?.status==="failed"&&"爬取失敗,請查看下方日誌。",$?.status==="cancelled"&&"已停止(取消爬取)。"]})]}),(0,s.jsxs)(i.Wu,{className:"space-y-2",children:[(0,s.jsxs)("div",{className:"flex items-center justify-between gap-3 flex-wrap",children:[$?.status==="running"&&(0,s.jsxs)("div",{className:"flex items-center gap-2 text-muted-foreground",children:[(0,s.jsx)(p.A,{className:"h-4 w-4 animate-spin"}),(0,s.jsx)("span",{children:"執行中…"})]}),($?.status==="running"||$?.status==="pending")&&(0,s.jsx)(c.$,{variant:"destructive",type:"button",onClick:G,disabled:U,children:U?"停止中…":"停止"})]}),$?.summary&&(0,s.jsxs)("p",{className:"text-sm text-muted-foreground",children:["進度:",$.summary.currentIndex,"/",$.summary.total,",成功 ",$.summary.succeeded,",失敗 ",$.summary.failed]}),$?.status==="completed"&&(0,s.jsx)(s.Fragment,{children:$.summary&&$.summary.failed>0?(0,s.jsxs)("p",{className:"text-amber-600 dark:text-amber-400",children:["批次已跑完,但有 ",$.summary.failed," 筆關鍵字失敗(請看下方明細)。整體 exit code: ",$.exitCode??1]}):(0,s.jsxs)("p",{className:"text-green-600 dark:text-green-400",children:["已完成(exit code: ",$.exitCode??0,")"]})}),$?.status==="failed"&&(0,s.jsxs)(s.Fragment,{children:[$.error&&(0,s.jsx)("p",{className:"text-destructive text-sm",children:$.error}),$.logTail&&(0,s.jsx)("pre",{className:"text-xs bg-muted p-3 rounded overflow-auto max-h-48 whitespace-pre-wrap",children:$.logTail})]}),$?.status==="cancelled"&&(0,s.jsx)("p",{className:"text-muted-foreground text-sm",children:"已停止。若需要可重新開始爬取。"}),($?.items?.length??0)>0&&(0,s.jsxs)("div",{className:"space-y-2",children:[(0,s.jsx)("p",{className:"text-sm font-medium",children:"批次明細"}),(0,s.jsx)("div",{className:"max-h-56 overflow-auto rounded border",children:(0,s.jsxs)("table",{className:"w-full text-xs",children:[(0,s.jsx)("thead",{className:"bg-muted",children:(0,s.jsxs)("tr",{children:[(0,s.jsx)("th",{className:"text-left p-2",children:"關鍵字"}),(0,s.jsx)("th",{className:"text-left p-2",children:"狀態"}),(0,s.jsx)("th",{className:"text-right p-2",children:"R2 上傳"}),(0,s.jsx)("th",{className:"text-left p-2",children:"錯誤"})]})}),(0,s.jsx)("tbody",{children:$?.items?.map(e=>(0,s.jsxs)("tr",{className:"border-t",children:[(0,s.jsx)("td",{className:"p-2",children:e.keyword}),(0,s.jsx)("td",{className:"p-2",children:e.status}),(0,s.jsx)("td",{className:"p-2 text-right",children:e.r2Uploaded??0}),(0,s.jsx)("td",{className:"p-2 text-destructive",children:e.errorMessage??"-"})]},e.keyword))})]})})]})]})]})]})}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.