feat: sync current progress (P0 hardening + P1 observability + deploy docs/systemd)

This commit is contained in:
OpenClaw Agent
2026-02-28 23:51:23 +08:00
commit d17296d794
96 changed files with 6358 additions and 0 deletions
@@ -0,0 +1 @@
import{d as v,i as $,z as x,u as w,r as u,o as i,l as d,w as e,a as s,m as r,f as n}from"./index-CnyV6Gd0.js";const A=v({__name:"AppNav",setup(b){const f=$(),l=x(),m=w();function p(y){f.push(y)}function k(){m.logout(),f.push("/login")}return(y,t)=>{const o=u("el-button"),C=u("el-space"),g=u("el-card");return i(),d(g,{class:"card",shadow:"never",style:{"margin-bottom":"12px"}},{default:e(()=>[s(C,{wrap:""},{default:e(()=>[s(o,{type:r(l).path==="/"?"primary":"default",onClick:t[0]||(t[0]=a=>p("/"))},{default:e(()=>[...t[6]||(t[6]=[n("公开记录",-1)])]),_:1},8,["type"]),s(o,{type:r(l).path==="/app"?"primary":"default",onClick:t[1]||(t[1]=a=>p("/app"))},{default:e(()=>[...t[7]||(t[7]=[n("仪表盘",-1)])]),_:1},8,["type"]),s(o,{type:r(l).path==="/assets"?"primary":"default",onClick:t[2]||(t[2]=a=>p("/assets"))},{default:e(()=>[...t[8]||(t[8]=[n("资产",-1)])]),_:1},8,["type"]),s(o,{type:r(l).path==="/categories"?"primary":"default",onClick:t[3]||(t[3]=a=>p("/categories"))},{default:e(()=>[...t[9]||(t[9]=[n("分类",-1)])]),_:1},8,["type"]),s(o,{type:r(l).path==="/reminders"?"primary":"default",onClick:t[4]||(t[4]=a=>p("/reminders"))},{default:e(()=>[...t[10]||(t[10]=[n("提醒",-1)])]),_:1},8,["type"]),r(m).token?(i(),d(o,{key:0,type:"danger",plain:"",onClick:k},{default:e(()=>[...t[11]||(t[11]=[n("退出",-1)])]),_:1})):(i(),d(o,{key:1,onClick:t[5]||(t[5]=a=>p("/login"))},{default:e(()=>[...t[12]||(t[12]=[n("登录",-1)])]),_:1}))]),_:1})]),_:1})}}});export{A as _};
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{_ as k}from"./AppNav.vue_vue_type_script_setup_true_lang-RQbRtBk5.js";import{_ as E}from"./PageState.vue_vue_type_script_setup_true_lang-DEQuT0jG.js";import{l as M,c as B}from"./categories-Bz8nm2Da.js";import{g as v}from"./errors-E9D9vVes.js";import{d as N,j as U,c as $,a as e,w as t,r as a,h as p,f as b,g as j,E as _,o as D}from"./index-CnyV6Gd0.js";const I={class:"page"},H=N({__name:"Categories",setup(T){const c=p([]),l=j({name:"",type:"digital"}),r=p(!1),s=p("");async function d(){r.value=!0,s.value="";try{const n=await M();c.value=n.data||[]}catch(n){s.value=v(n,"分类数据加载失败")}finally{r.value=!1}}async function w(){if(!l.name.trim())return _.error("分类名必填");try{await B({name:l.name.trim(),type:l.type}),l.name="",await d(),_.success("新增成功")}catch(n){_.error(v(n,"新增失败"))}}return U(d),(n,o)=>{const x=a("el-input"),i=a("el-col"),f=a("el-option"),C=a("el-select"),y=a("el-button"),V=a("el-row"),g=a("el-card"),m=a("el-table-column"),h=a("el-table");return D(),$("div",I,[e(k),e(g,{class:"card"},{default:t(()=>[e(V,{gutter:12},{default:t(()=>[e(i,{xs:24,sm:10},{default:t(()=>[e(x,{modelValue:l.name,"onUpdate:modelValue":o[0]||(o[0]=u=>l.name=u),placeholder:"分类名称"},null,8,["modelValue"])]),_:1}),e(i,{xs:24,sm:8},{default:t(()=>[e(C,{modelValue:l.type,"onUpdate:modelValue":o[1]||(o[1]=u=>l.type=u),style:{width:"100%"}},{default:t(()=>[e(f,{label:"digital",value:"digital"}),e(f,{label:"real",value:"real"})]),_:1},8,["modelValue"])]),_:1}),e(i,{xs:24,sm:6},{default:t(()=>[e(y,{type:"primary",onClick:w},{default:t(()=>[...o[2]||(o[2]=[b("新增分类",-1)])]),_:1})]),_:1})]),_:1})]),_:1}),e(g,{class:"card"},{default:t(()=>[e(E,{loading:r.value,error:s.value,empty:!r.value&&!s.value&&c.value.length===0,"empty-text":"当前没有分类记录"},{retry:t(()=>[e(y,{onClick:d},{default:t(()=>[...o[3]||(o[3]=[b("重试",-1)])]),_:1})]),default:t(()=>[e(h,{data:c.value},{default:t(()=>[e(m,{prop:"id",label:"ID",width:"80"}),e(m,{prop:"name",label:"分类名","min-width":"140"}),e(m,{prop:"type",label:"类型",width:"120"}),e(m,{prop:"created_at",label:"创建时间","min-width":"180"})]),_:1},8,["data"])]),_:1},8,["loading","error","empty"])]),_:1})])}}});export{H as default};
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{d as g,u as V,c as b,a as o,w as a,r as s,b as x,e as y,f as v,g as h,h as C,E as p,i as E,o as k}from"./index-CnyV6Gd0.js";import{g as B}from"./errors-E9D9vVes.js";const M={class:"page",style:{"max-width":"420px","margin-top":"80px"}},A=g({__name:"Login",setup(N){const t=h({username:"",password:""}),i=V(),c=E(),l=C(!1);async function u(){l.value=!0;try{await i.login(t.username,t.password),p.success("登录成功"),c.push("/app")}catch(d){p.error(B(d,"登录失败,请检查账号密码"))}finally{l.value=!1}}return(d,e)=>{const m=s("el-input"),n=s("el-form-item"),_=s("el-button"),f=s("el-form"),w=s("el-card");return k(),b("div",M,[o(w,{class:"card"},{default:a(()=>[e[3]||(e[3]=x("h2",null,"登录",-1)),o(f,{onSubmit:y(u,["prevent"]),"label-width":"80px"},{default:a(()=>[o(n,{label:"用户名"},{default:a(()=>[o(m,{modelValue:t.username,"onUpdate:modelValue":e[0]||(e[0]=r=>t.username=r)},null,8,["modelValue"])]),_:1}),o(n,{label:"密码"},{default:a(()=>[o(m,{modelValue:t.password,"onUpdate:modelValue":e[1]||(e[1]=r=>t.password=r),"show-password":"",type:"password"},null,8,["modelValue"])]),_:1}),o(n,null,{default:a(()=>[o(_,{type:"primary",loading:l.value,onClick:u,style:{width:"100%"}},{default:a(()=>[...e[2]||(e[2]=[v("登录",-1)])]),_:1},8,["loading"])]),_:1})]),_:1})]),_:1})])}}});export{A as default};
@@ -0,0 +1 @@
import{d,c as i,a as m,l as n,w as p,y as a,r as t,o}from"./index-CnyV6Gd0.js";const y={key:0,style:{padding:"12px"}},k=d({__name:"PageState",props:{loading:{type:Boolean,default:!1},error:{default:""},empty:{type:Boolean,default:!1},emptyText:{default:"暂无数据"}},setup(e){return(l,u)=>{const r=t("el-skeleton"),s=t("el-result"),c=t("el-empty");return e.loading?(o(),i("div",y,[m(r,{rows:5,animated:""})])):e.error?(o(),n(s,{key:1,icon:"error",title:"加载失败","sub-title":e.error},{extra:p(()=>[a(l.$slots,"retry")]),_:3},8,["sub-title"])):e.empty?(o(),n(c,{key:2,description:e.emptyText},null,8,["description"])):a(l.$slots,"default",{key:3})}}});export{k as _};
+1
View File
@@ -0,0 +1 @@
import{_ as x}from"./AppNav.vue_vue_type_script_setup_true_lang-RQbRtBk5.js";import{_ as k}from"./PageState.vue_vue_type_script_setup_true_lang-DEQuT0jG.js";import{d as C,j,c as B,a as e,w as t,r as l,h as u,o as N,f as p,t as w,b as y}from"./index-CnyV6Gd0.js";const V={class:"page"},D={style:{display:"flex","justify-content":"space-between","align-items":"center"}},P=C({__name:"PublicRecords",setup(E){const n=u(!1),s=u(""),c=u({}),r=u([]);async function i(){n.value=!0,s.value="";try{const _=await fetch("/public/records");if(!_.ok)throw new Error("请求失败");const a=await _.json();c.value=a.summary||{},r.value=a.records||[]}catch{s.value="公开记录加载失败"}finally{n.value=!1}}return j(i),(_,a)=>{const f=l("el-button"),d=l("el-statistic"),m=l("el-col"),b=l("el-row"),o=l("el-table-column"),h=l("el-table"),g=l("el-card");return N(),B("div",V,[e(x),e(g,{class:"card"},{header:t(()=>[y("div",D,[a[1]||(a[1]=y("span",null,"已记录内容(公开只读)",-1)),e(f,{onClick:i},{default:t(()=>[...a[0]||(a[0]=[p("刷新",-1)])]),_:1})])]),default:t(()=>[e(k,{loading:n.value,error:s.value,empty:!n.value&&!s.value&&r.value.length===0,"empty-text":"当前 0 条记录。请先到 /app 添加资产"},{retry:t(()=>[e(f,{onClick:i},{default:t(()=>[...a[2]||(a[2]=[p("重试",-1)])]),_:1})]),default:t(()=>[e(b,{gutter:12,style:{"margin-bottom":"12px"}},{default:t(()=>[e(m,{xs:24,sm:8},{default:t(()=>[e(d,{title:"活跃资产",value:c.value.active_asset_count||0},null,8,["value"])]),_:1}),e(m,{xs:24,sm:8},{default:t(()=>[e(d,{title:"总资产值",value:c.value.total_assets_value||0},null,8,["value"])]),_:1}),e(m,{xs:24,sm:8},{default:t(()=>[e(d,{title:"记录数",value:r.value.length},null,8,["value"])]),_:1})]),_:1}),e(h,{data:r.value,style:{width:"100%"}},{default:t(()=>[e(o,{prop:"id",label:"ID",width:"70"}),e(o,{prop:"name",label:"名称","min-width":"140"}),e(o,{prop:"category_name",label:"分类","min-width":"120"}),e(o,{label:"金额","min-width":"120"},{default:t(v=>[p(w(v.row.total_value)+" "+w(v.row.currency),1)]),_:1}),e(o,{prop:"status",label:"状态",width:"100"}),e(o,{prop:"expiry_date",label:"到期日","min-width":"180"})]),_:1},8,["data"])]),_:1},8,["loading","error","empty"])]),_:1})])}}});export{P as default};
+1
View File
@@ -0,0 +1 @@
import{_ as N}from"./AppNav.vue_vue_type_script_setup_true_lang-RQbRtBk5.js";import{_ as j}from"./PageState.vue_vue_type_script_setup_true_lang-DEQuT0jG.js";import{x as D,d as E,j as M,c as y,a as e,w as a,r as t,h as n,l as R,f as w,t as S,b as T,o as g}from"./index-CnyV6Gd0.js";import{g as $}from"./errors-E9D9vVes.js";async function I(f){const{data:r}=await D.get("/reminders",{params:f});return r}const U={class:"page"},q={key:1},A={style:{"margin-top":"12px",display:"flex","justify-content":"flex-end"}},K=E({__name:"Reminders",setup(f){const r=n("pending"),m=n([]),v=n(0),p=n(1),b=n(20),u=n(!1),d=n("");function h(){p.value=1,_()}async function _(){u.value=!0,d.value="";try{const i=await I({status:r.value||void 0,page:p.value,page_size:b.value});m.value=i.data||[],v.value=i.total||0}catch(i){d.value=$(i,"提醒数据加载失败")}finally{u.value=!1}}return M(_),(i,o)=>{const c=t("el-tab-pane"),x=t("el-tabs"),k=t("el-button"),l=t("el-table-column"),C=t("el-tag"),V=t("el-table"),z=t("el-pagination"),B=t("el-card");return g(),y("div",U,[e(N),e(B,{class:"card"},{default:a(()=>[e(x,{modelValue:r.value,"onUpdate:modelValue":o[0]||(o[0]=s=>r.value=s),onTabChange:h},{default:a(()=>[e(c,{label:"待处理",name:"pending"}),e(c,{label:"发送中",name:"sending"}),e(c,{label:"已发送",name:"sent"}),e(c,{label:"失败",name:"failed"})]),_:1},8,["modelValue"]),e(j,{loading:u.value,error:d.value,empty:!u.value&&!d.value&&m.value.length===0,"empty-text":"当前没有提醒记录"},{retry:a(()=>[e(k,{onClick:_},{default:a(()=>[...o[2]||(o[2]=[w("重试",-1)])]),_:1})]),default:a(()=>[e(V,{data:m.value},{default:a(()=>[e(l,{prop:"id",label:"ID",width:"70"}),e(l,{prop:"asset_name",label:"资产","min-width":"140"}),e(l,{prop:"status",label:"状态",width:"100"}),e(l,{prop:"remind_at",label:"提醒时间","min-width":"180"}),e(l,{prop:"next_retry_at",label:"下次重试","min-width":"180"}),e(l,{prop:"retry_count",label:"重试",width:"80"}),e(l,{label:"错误信息","min-width":"240"},{default:a(s=>[s.row.last_error?(g(),R(C,{key:0,type:"danger",size:"small"},{default:a(()=>[w(S(s.row.last_error),1)]),_:2},1024)):(g(),y("span",q,"-"))]),_:1})]),_:1},8,["data"]),T("div",A,[e(z,{background:"",layout:"prev, pager, next, total",total:v.value,"page-size":b.value,"current-page":p.value,onCurrentChange:o[1]||(o[1]=s=>{p.value=s,_()})},null,8,["total","page-size","current-page"])])]),_:1},8,["loading","error","empty"])]),_:1})])}}});export{K as default};
+1
View File
@@ -0,0 +1 @@
import{_ as p,c as d,a as t,w as o,b as n,f as i,r as s,o as u}from"./index-CnyV6Gd0.js";const c={},m={class:"page",style:{"max-width":"520px","margin-top":"80px"}};function _(r,e){const a=s("el-button"),l=s("el-card");return u(),d("div",m,[t(l,{class:"card"},{default:o(()=>[e[2]||(e[2]=n("h2",null,"会话已过期",-1)),e[3]||(e[3]=n("p",null,"登录状态失效,请重新登录后继续操作。",-1)),t(a,{type:"primary",onClick:e[0]||(e[0]=f=>r.$router.push("/login"))},{default:o(()=>[...e[1]||(e[1]=[i("去登录",-1)])]),_:1})]),_:1})])}const b=p(c,[["render",_]]);export{b as default};
+1
View File
@@ -0,0 +1 @@
import{x as s}from"./index-CnyV6Gd0.js";async function c(t){const{data:a}=await s.get("/assets",{params:t});return a}async function r(t){const{data:a}=await s.post("/assets",t);return a}async function o(t,a){const{data:e}=await s.put(`/assets/${t}`,a);return e}async function u(t){const{data:a}=await s.delete(`/assets/${t}`);return a}async function d(){const{data:t}=await s.get("/dashboard/summary");return t}export{u as a,r as c,d,c as l,o as u};
+1
View File
@@ -0,0 +1 @@
import{x as a}from"./index-CnyV6Gd0.js";async function r(){const{data:t}=await a.get("/categories");return t}async function s(t){const{data:e}=await a.post("/categories",t);return e}export{s as c,r as l};
+1
View File
@@ -0,0 +1 @@
function a(e,o="请求失败,请稍后重试"){const t=e?.response?.status,n=e?.response?.data?.message;if(n&&typeof n=="string"){const i=e?.response?.data?.request_id;return i?`${n}(请求编号: ${i})`:n}let s=o;t===400?s="请求参数有误,请检查后重试":t===401?s="登录状态已失效,请重新登录":t===403?s="你没有权限执行该操作":t===404?s="请求资源不存在":t>=500&&(s="服务暂时不可用,请稍后重试");const r=e?.response?.data?.request_id||e?.response?.headers?.["x-request-id"];return r?`${s}(请求编号: ${r})`:s}export{a as g};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long