You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4 lines
15 KiB
4 lines
15 KiB
import{g as ot,y as lt,z as at,j as rt,c as r,k as c,v as z,a as t,l as G,F as g,r as j,t as a,A as it,m as v,B as dt,p as ut,q as pt,n as _,d as u,s as f,x as q,o as i}from"./ydFS6PsN.js";import{u as ct}from"./CWcpm1jv.js";import{u as mt}from"./CQ70mTiW.js";const bt={class:"flex items-center justify-between mb-5"},xt={class:"bg-white rounded-xl shadow-sm border border-slate-100"},gt={class:"overflow-x-auto"},ft={class:"table table-zebra text-sm"},vt={key:0},_t={key:1},yt={class:"font-mono"},kt={class:"font-medium"},wt={class:"text-xs text-slate-500"},ht={class:"font-mono text-xs"},Ct={key:0,class:"text-green-600"},Mt={key:1,class:"text-slate-400"},Tt={class:"flex gap-1"},Nt=["onClick"],St=["onClick"],It=["onClick"],zt=["onClick"],Ot={class:"flex items-center gap-3 mb-5"},Vt={class:"text-lg font-semibold text-slate-800"},At={class:"bg-white rounded-xl shadow-sm border border-slate-100 p-6 max-w-3xl"},$t={class:"grid grid-cols-2 gap-4"},Ut={class:"form-control"},Dt={class:"form-control"},Lt={class:"form-control mt-4"},jt={class:"form-control mt-4"},qt={class:"form-control mt-4"},Bt={class:"flex items-center gap-2 mt-4"},Rt={class:"flex items-center gap-2 cursor-pointer"},Ft={class:"mt-4 text-sm"},Pt={class:"flex gap-3 mt-6"},Et=["disabled"],Jt=["disabled"],Yt={class:"modal-box"},Gt={class:"text-sm text-slate-500 mt-1"},Ht={class:"grid grid-cols-2 gap-3 mt-4"},Kt={key:0,class:"bg-slate-50 border border-slate-200 rounded-lg p-3"},Qt={class:"flex justify-between items-center text-xs mb-1.5"},Wt={class:"text-slate-600"},Xt={class:"font-mono text-slate-400"},Zt=["value"],te={class:"mt-2 text-xs space-y-0.5"},ee={key:1,class:"text-red-600"},se={key:2,class:"bg-green-50 border border-green-100 rounded-lg p-3"},ne={class:"grid grid-cols-2 gap-x-4 gap-y-1 text-xs text-slate-600 mb-2"},oe={class:"border-t border-green-100 pt-2 text-xs"},le={class:"text-slate-500"},ae={class:"font-mono text-slate-700"},re={class:"modal-action"},ie=["disabled"],me=ot({__name:"apps",setup(de){const{consoleApi:y}=ct(),{success:k,error:b}=mt(),B=lt(),H=at(),C=f("list"),M=f([]),O=f(!1),T=f(!1),w=f(!1),N=f(!1),d=q({show:!1,apiOk:!1,apiMsg:"",dbOk:!1,dbMsg:""}),l=q({id:0,name:"",region:"",base_url:"",service_dsn:"",remark:"",enabled:!0});function K(o){const e=(o||"").match(/\/([^/?]+)\?/);return e?e[1]:"-"}async function S(){O.value=!0;try{const o=await y("apps/list",{});M.value=o??[]}catch(o){b(o?.message??"获取应用列表失败"),M.value=[]}finally{O.value=!1}}function V(){w.value=!1,d.show=!1,d.apiMsg="",d.dbMsg=""}function A(){C.value="list",S()}function R(o){o?(T.value=!0,l.id=o.id,l.name=o.name||"",l.region=o.region||"",l.base_url=o.base_url||"",l.service_dsn=o.service_dsn||"",l.remark=o.remark||"",l.enabled=!!o.enabled):(T.value=!1,l.id=0,l.name="",l.region="",l.base_url="",l.service_dsn="",l.remark="",l.enabled=!0),V(),C.value="form"}async function Q(){const o=l.base_url.trim(),e=l.service_dsn.trim();if(!o||!e){b("请先填应用地址和业务库 DSN");return}N.value=!0;try{const n=await y("apps/test",{base_url:o,service_dsn:e});d.apiOk=!!n.api_ok,d.apiMsg=n.api_msg,d.dbOk=!!n.db_ok,d.dbMsg=n.db_msg,d.show=!0,w.value=!!n.ok,w.value?k("检测通过,可以保存"):b("检测未通过")}catch(n){b(n?.message??"测试失败")}finally{N.value=!1}}async function W(){if(!w.value){b("请先「测试连接」通过再保存");return}const o={name:l.name,region:l.region,base_url:l.base_url,service_dsn:l.service_dsn,remark:l.remark,enabled:l.enabled};let e="apps/add";T.value&&l.id&&(o.id=Number(l.id),e="apps/update");try{await y(e,o),k("保存成功"),A()}catch(n){b(n?.message??"失败")}}function X(o){window.confirm(`删除注册应用 #${o} ?(不影响应用自身的库)`)&&y("apps/del",{id:o}).then(()=>{k("已删除"),S()}).catch(e=>b(e?.message??"失败"))}const $=f(null),s=q({appId:0,appLabel:"",start:"",end:"",resultShow:!1,resultClass:"",mode:"",steps:[],curIndex:0,curTotal:0,curName:"",pct:0,errMsg:"",report:null,running:!1,btnText:"开始分析"});function F(o){return parseInt((o||"").replace(/-/g,""))||0}function Z(o,e){s.appId=o,s.appLabel="应用:"+e+" (#"+o+")",s.start="",s.end="",s.resultShow=!1,s.mode="",s.report=null,s.errMsg="",s.steps=[],s.curIndex=0,s.curTotal=0,s.curName="",s.pct=0,s.running=!1,s.btnText="开始分析",$.value?.showModal()}function tt(){$.value?.close()}function et(o){s.steps[o.index-1]=o.name,s.pct=Math.round(o.index/(o.total+1)*100),s.curIndex=o.index,s.curTotal=o.total,s.curName=o.name}async function st(){const o=s.appLabel,e=s.start||"最早",n=s.end||"至今";if(!window.confirm(`将先删除【${o}】在 ${e} ~ ${n} 区间的历史统计数据,然后重新分析写入。
|
|
|
|
确认继续?`))return;s.running=!0,s.btnText="分析中...",s.resultShow=!0,s.resultClass="",s.mode="progress",s.steps=[],s.curIndex=0,s.curTotal=0,s.curName="",s.pct=0,s.report=null,s.errMsg="";const m={app_id:s.appId,start_day:F(s.start),end_day:F(s.end)};let U=null,h=null,P=!1;function E(x){if(x=(x||"").trim(),!x)return;let p;try{p=JSON.parse(x)}catch{return}if(p.code===18){P=!0;return}if(p.code!==void 0&&p.code!==0){h=p.msg||"请求被拒绝";return}p.type==="progress"?et(p):p.type==="done"?U=p.report:p.type==="error"&&(h=p.msg)}try{const p=(await fetch("/console/api/apps/analyze",{method:"POST",headers:{"Content-Type":"application/json",Authorization:B.token},body:JSON.stringify(m)})).body.getReader(),J=new TextDecoder;let I="";for(;;){const Y=await p.read();if(Y.done)break;I+=J.decode(Y.value,{stream:!0});const D=I.split(`
|
|
`);I=D.pop();for(let L=0;L<D.length;L++)E(D[L])}E(I)}catch(x){h="网络异常: "+x.message}if(P){B.logout(),H.push("/");return}if(s.running=!1,s.btnText="重新分析",h){s.resultClass="text-red-600",s.mode="error",s.errMsg=h;return}if(!U){s.resultClass="text-red-600",s.mode="error",s.errMsg="分析中断,未收到完成事件";return}s.resultClass="",s.mode="done",s.report=U,k("分析完成"),S()}function nt(o){window.confirm(`向应用 #${o} 发送一条配置 reload 事件?`)&&y("config/notify",{app_id:o,type:"all",action:"reload"}).then(e=>{k("已发送 → "+(e&&e.subject))}).catch(e=>b(e?.message??"失败"))}return rt(S),(o,e)=>(i(),r("div",null,[c(t("div",null,[t("div",bt,[e[11]||(e[11]=t("div",null,[t("h2",{class:"text-lg font-semibold text-slate-800"},"应用注册"),t("p",{class:"text-sm text-slate-400 mt-1"},"注册各应用的地址与业务库 DSN(仅「重置设备码」清用户绑定时用);厂家/产品/设备码统一在 console 主库,无需逐应用配。")],-1)),t("button",{class:"btn btn-primary btn-sm text-white",onClick:e[0]||(e[0]=n=>R())},"+ 注册应用")]),t("div",xt,[t("div",gt,[t("table",ft,[e[14]||(e[14]=t("thead",null,[t("tr",null,[t("th",null,"ID"),t("th",null,"名称"),t("th",null,"区域"),t("th",null,"应用地址"),t("th",null,"业务库"),t("th",null,"启用"),t("th",null,"操作")])],-1)),t("tbody",null,[O.value?(i(),r("tr",vt,[...e[12]||(e[12]=[t("td",{colspan:"7",class:"text-center py-8"},[t("span",{class:"loading loading-spinner loading-sm"})],-1)])])):M.value.length?G("",!0):(i(),r("tr",_t,[...e[13]||(e[13]=[t("td",{colspan:"7",class:"text-center text-slate-400 py-8"},"暂无注册应用",-1)])])),(i(!0),r(g,null,j(M.value,n=>(i(),r("tr",{key:n.id},[t("td",yt,a(n.id),1),t("td",kt,a(n.name||""),1),t("td",null,a(n.region||""),1),t("td",wt,a(n.base_url||""),1),t("td",ht,a(K(n.service_dsn)),1),t("td",null,[n.enabled?(i(),r("span",Ct,"是")):(i(),r("span",Mt,"否"))]),t("td",null,[t("div",Tt,[t("button",{class:"btn btn-ghost btn-xs",onClick:m=>R(n)},"编辑",8,Nt),t("button",{class:"btn btn-ghost btn-xs text-emerald-600",onClick:m=>Z(n.id,n.name||"应用#"+n.id)},"分析历史",8,St),t("button",{class:"btn btn-ghost btn-xs text-indigo-500",onClick:m=>nt(n.id)},"发事件",8,It),t("button",{class:"btn btn-ghost btn-xs text-red-500",onClick:m=>X(n.id)},"删除",8,zt)])])]))),128))])])])])],512),[[z,C.value==="list"]]),c(t("div",null,[t("div",Ot,[t("button",{class:"btn btn-ghost btn-sm",onClick:e[1]||(e[1]=n=>A())},"← 返回"),t("h2",Vt,a(T.value?"编辑应用":"注册应用"),1)]),t("div",At,[t("form",{onSubmit:it(W,["prevent"])},[t("div",$t,[t("div",Ut,[e[15]||(e[15]=t("label",{class:"label"},[t("span",{class:"label-text font-medium"},"名称 *")],-1)),c(t("input",{"onUpdate:modelValue":e[2]||(e[2]=n=>l.name=n),type:"text",class:"input input-bordered w-full",required:"",placeholder:"如 Voitrans(国内)"},null,512),[[v,l.name]])]),t("div",Dt,[e[17]||(e[17]=t("label",{class:"label"},[t("span",{class:"label-text font-medium"},"区域")],-1)),c(t("select",{"onUpdate:modelValue":e[3]||(e[3]=n=>l.region=n),class:"select select-bordered w-full"},[...e[16]||(e[16]=[dt('<option value="">未指定</option><option value="中国">中国</option><option value="美国">美国</option><option value="东亚">东亚</option><option value="东南亚">东南亚</option><option value="南亚">南亚</option><option value="中东">中东</option><option value="欧洲">欧洲</option><option value="俄罗斯">俄罗斯</option><option value="非洲">非洲</option><option value="南美">南美</option><option value="北美">北美</option><option value="大洋洲">大洋洲</option><option value="巴西">巴西</option><option value="印度">印度</option>',15)])],512),[[ut,l.region]])])]),t("div",Lt,[e[18]||(e[18]=t("label",{class:"label"},[t("span",{class:"label-text font-medium"},"应用地址 *")],-1)),c(t("input",{"onUpdate:modelValue":e[4]||(e[4]=n=>l.base_url=n),type:"text",class:"input input-bordered w-full",required:"",placeholder:"https://api.xxx.com/",onInput:V},null,544),[[v,l.base_url]]),e[19]||(e[19]=t("span",{class:"text-xs text-slate-400 mt-1"},"用于通知应用业务服务事件(如配置更新)",-1))]),t("div",jt,[e[20]||(e[20]=t("label",{class:"label"},[t("span",{class:"label-text font-medium"},"业务库 DSN *")],-1)),c(t("input",{"onUpdate:modelValue":e[5]||(e[5]=n=>l.service_dsn=n),type:"text",class:"input input-bordered w-full font-mono text-xs",required:"",placeholder:"root:pwd@tcp(host:3306)/earphone?charset=utf8mb4&parseTime=True&loc=Local",onInput:V},null,544),[[v,l.service_dsn]]),e[21]||(e[21]=t("span",{class:"text-xs text-slate-400 mt-1"},"用于读取业务数据(重置设备码时清 userdevice/product_stat)",-1))]),t("div",qt,[e[22]||(e[22]=t("label",{class:"label"},[t("span",{class:"label-text font-medium"},"备注")],-1)),c(t("input",{"onUpdate:modelValue":e[6]||(e[6]=n=>l.remark=n),type:"text",class:"input input-bordered w-full"},null,512),[[v,l.remark]])]),t("div",Bt,[t("label",Rt,[c(t("input",{"onUpdate:modelValue":e[7]||(e[7]=n=>l.enabled=n),type:"checkbox",class:"toggle toggle-primary toggle-sm"},null,512),[[pt,l.enabled]]),e[23]||(e[23]=t("span",{class:"text-sm"},"启用",-1))])]),c(t("div",Ft,[t("div",{class:_(d.apiOk?"text-green-700":"text-red-600")},[t("span",{class:_(d.apiOk?"text-green-600":"text-red-500")},a(d.apiOk?"✓":"✗"),3),u(" 应用地址:"+a(d.apiMsg),1)],2),t("div",{class:_(d.dbOk?"text-green-700":"text-red-600")},[t("span",{class:_(d.dbOk?"text-green-600":"text-red-500")},a(d.dbOk?"✓":"✗"),3),u(" 业务库:"+a(d.dbMsg),1)],2)],512),[[z,d.show]]),t("div",Pt,[t("button",{type:"button",class:"btn btn-ghost",onClick:e[8]||(e[8]=n=>A())},"取消"),t("button",{type:"button",class:"btn btn-outline",disabled:N.value,onClick:Q},a(N.value?"测试中...":"测试连接"),9,Et),t("button",{type:"submit",class:"btn btn-primary text-white",disabled:!w.value},"保存",8,Jt)]),e[24]||(e[24]=t("p",{class:"text-xs text-slate-400 mt-2"},"需先「测试连接」通过(应用地址可达 + 业务库可连)才能保存。",-1))],32)])],512),[[z,C.value==="form"]]),t("dialog",{ref_key:"analyzeModal",ref:$,class:"modal"},[t("div",Yt,[e[32]||(e[32]=t("h3",{class:"font-bold text-lg"},"分析历史数据",-1)),t("p",Gt,a(s.appLabel),1),e[33]||(e[33]=t("div",{class:"text-xs text-amber-700 mt-3 bg-amber-50 border border-amber-100 rounded-lg p-3 leading-relaxed"},[u(" 扫描该应用业务库,按 "),t("b",null,"天 + 产品 + 区域"),u(" 生成历史统计(新增用户 / 订单 / 资源发放·使用 / 激活绑定设备),汇入 console 主库。"),t("br"),u(" · "),t("b",null,"分析前会先清理该应用+区域在所选区间内的旧统计行"),u(",避免数据重叠。"),t("br"),u(" · 登录、活跃用户、AI对话等无每日原始记录,历史无法还原(由实时管道往后采集)。"),t("br"),u(" · 仅对实时管道上线前的区间运行。留空 = 全部历史。大库可能耗时。 ")],-1)),t("div",Ht,[t("div",null,[e[25]||(e[25]=t("label",{class:"text-xs text-slate-500"},"起始日(含)",-1)),c(t("input",{"onUpdate:modelValue":e[9]||(e[9]=n=>s.start=n),type:"date",class:"input input-bordered input-sm w-full"},null,512),[[v,s.start]])]),t("div",null,[e[26]||(e[26]=t("label",{class:"text-xs text-slate-500"},"结束日(含)",-1)),c(t("input",{"onUpdate:modelValue":e[10]||(e[10]=n=>s.end=n),type:"date",class:"input input-bordered input-sm w-full"},null,512),[[v,s.end]])])]),c(t("div",{class:_(["text-sm mt-3",s.resultClass])},[s.mode==="progress"?(i(),r("div",Kt,[t("div",Qt,[t("span",Wt,[s.curName?(i(),r(g,{key:0},[e[27]||(e[27]=t("span",{class:"loading loading-spinner loading-xs"},null,-1)),u(" 正在:"+a(s.curName)+" ("+a(s.curIndex)+"/"+a(s.curTotal)+") ",1)],64)):(i(),r(g,{key:1},[u("准备中...")],64))]),t("span",Xt,a(s.pct)+"%",1)]),t("progress",{class:"progress progress-primary w-full h-2",value:s.pct,max:"100"},null,8,Zt),t("div",te,[(i(!0),r(g,null,j(s.steps,(n,m)=>(i(),r("div",{key:m,class:_(m===s.curIndex-1?"text-slate-600":"text-green-600")},[m===s.curIndex-1?(i(),r(g,{key:0},[e[28]||(e[28]=t("span",{class:"loading loading-spinner loading-xs"},null,-1)),u(" "+a(n),1)],64)):(i(),r(g,{key:1},[u("✓ "+a(n),1)],64))],2))),128))])])):s.mode==="error"?(i(),r("div",ee,"✗ "+a(s.errMsg),1)):s.mode==="done"&&s.report?(i(),r("div",se,[e[31]||(e[31]=t("div",{class:"font-semibold text-green-700 mb-2"},"✓ 分析完成",-1)),t("div",ne,[t("div",null,[e[29]||(e[29]=u("应用:",-1)),t("b",null,a(s.report.app_name||""),1)]),t("div",null,"区域:"+a(s.report.region||"未指定"),1),t("div",null,"区间:"+a((s.report.start_day||"不限")+" ~ "+(s.report.end_day||"不限")),1),t("div",null,"清理旧行:"+a(s.report.cleared_rows||0),1),t("div",null,[e[30]||(e[30]=u("写入天数:",-1)),t("b",null,a(s.report.days_written||0),1)]),t("div",null,"写入行数:"+a(s.report.rows_written||0),1)]),t("div",oe,[(i(!0),r(g,null,j(s.report.steps||[],(n,m)=>(i(),r("div",{key:m,class:"flex justify-between py-0.5"},[t("span",le,a(n.name),1),t("span",ae,a((n.groups||0)+" 组"),1)]))),128))])])):G("",!0)],2),[[z,s.resultShow]]),t("div",re,[t("button",{class:"btn btn-ghost btn-sm",onClick:tt},"关闭"),t("button",{class:"btn btn-primary btn-sm text-white",disabled:s.running,onClick:st},a(s.btnText),9,ie)])]),e[34]||(e[34]=t("form",{method:"dialog",class:"modal-backdrop"},[t("button",null,"close")],-1))],512)]))}});export{me as default};
|
|
|