feat: enhance tag relation graph filtering, fullscreen, and i18n

feature/tag-relationship-graph
wuqinchuan 2026-01-11 18:33:17 +08:00
parent 59bef3915e
commit 3771de5834
48 changed files with 696 additions and 185 deletions

View File

@ -13,7 +13,7 @@ Promise.resolve().then(async () => {
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Infinite Image Browsing</title> <title>Infinite Image Browsing</title>
<script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-d6594e8e.js"></script> <script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-0205daf8.js"></script>
<link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-af514ea9.css"> <link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-af514ea9.css">
</head> </head>

View File

@ -18,8 +18,6 @@ TAG_ABSTRACTION_CACHE_VERSION = 2
class TagGraphReq(BaseModel): class TagGraphReq(BaseModel):
folder_paths: List[str] folder_paths: List[str]
top_n_tags: Optional[int] = 50
top_n_clusters: Optional[int] = 20
lang: Optional[str] = "en" # Language for LLM output lang: Optional[str] = "en" # Language for LLM output
@ -291,8 +289,7 @@ If unsure about Level 2, OMIT it entirely. Start response with {{ and end with }
raise HTTPException(400, "No clusters found in result") raise HTTPException(400, "No clusters found in result")
# === Layer 0: Cluster Nodes === # === Layer 0: Cluster Nodes ===
top_n_clusters = req.top_n_clusters or 20 top_clusters = sorted(clusters, key=lambda c: c.get("size", 0), reverse=True)
top_clusters = sorted(clusters, key=lambda c: c.get("size", 0), reverse=True)[:top_n_clusters]
cluster_nodes = [] cluster_nodes = []
cluster_to_tags_links = [] cluster_to_tags_links = []
@ -348,12 +345,11 @@ If unsure about Level 2, OMIT it entirely. Start response with {{ and end with }
tag_stats[keyword]["total_images"] += cluster_size tag_stats[keyword]["total_images"] += cluster_size
# Filter and sort tags # Filter and sort tags
top_n_tags = req.top_n_tags or 50
sorted_tags = sorted( sorted_tags = sorted(
tag_stats.items(), tag_stats.items(),
key=lambda x: x[1]["total_images"], key=lambda x: x[1]["total_images"],
reverse=True reverse=True
)[:top_n_tags] )
tag_nodes = [] tag_nodes = []
selected_tags = set() selected_tags = set()

View File

@ -1 +1 @@
import{d as E,bC as $,r as f,m as M,_ as T,a as c,an as W,h as m,c as v,P as z}from"./index-d6594e8e.js";var G=["prefixCls","name","id","type","disabled","readonly","tabindex","autofocus","value","required"],H={prefixCls:String,name:String,id:String,type:String,defaultChecked:{type:[Boolean,Number],default:void 0},checked:{type:[Boolean,Number],default:void 0},disabled:Boolean,tabindex:{type:[Number,String]},readonly:Boolean,autofocus:Boolean,value:z.any,required:Boolean};const L=E({compatConfig:{MODE:3},name:"Checkbox",inheritAttrs:!1,props:$(H,{prefixCls:"rc-checkbox",type:"checkbox",defaultChecked:!1}),emits:["click","change"],setup:function(a,d){var t=d.attrs,h=d.emit,g=d.expose,o=f(a.checked===void 0?a.defaultChecked:a.checked),i=f();M(function(){return a.checked},function(){o.value=a.checked}),g({focus:function(){var e;(e=i.value)===null||e===void 0||e.focus()},blur:function(){var e;(e=i.value)===null||e===void 0||e.blur()}});var l=f(),x=function(e){if(!a.disabled){a.checked===void 0&&(o.value=e.target.checked),e.shiftKey=l.value;var r={target:c(c({},a),{},{checked:e.target.checked}),stopPropagation:function(){e.stopPropagation()},preventDefault:function(){e.preventDefault()},nativeEvent:e};a.checked!==void 0&&(i.value.checked=!!a.checked),h("change",r),l.value=!1}},C=function(e){h("click",e),l.value=e.shiftKey};return function(){var n,e=a.prefixCls,r=a.name,s=a.id,p=a.type,b=a.disabled,K=a.readonly,P=a.tabindex,B=a.autofocus,S=a.value,N=a.required,_=T(a,G),q=t.class,D=t.onFocus,j=t.onBlur,w=t.onKeydown,A=t.onKeypress,F=t.onKeyup,y=c(c({},_),t),O=Object.keys(y).reduce(function(k,u){return(u.substr(0,5)==="aria-"||u.substr(0,5)==="data-"||u==="role")&&(k[u]=y[u]),k},{}),R=W(e,q,(n={},m(n,"".concat(e,"-checked"),o.value),m(n,"".concat(e,"-disabled"),b),n)),V=c(c({name:r,id:s,type:p,readonly:K,disabled:b,tabindex:P,class:"".concat(e,"-input"),checked:!!o.value,autofocus:B,value:S},O),{},{onChange:x,onClick:C,onFocus:D,onBlur:j,onKeydown:w,onKeypress:A,onKeyup:F,required:N});return v("span",{class:R},[v("input",c({ref:i},V),null),v("span",{class:"".concat(e,"-inner")},null)])}}});export{L as V}; import{d as E,bC as $,r as f,m as M,_ as T,a as c,an as W,h as m,c as v,P as z}from"./index-0205daf8.js";var G=["prefixCls","name","id","type","disabled","readonly","tabindex","autofocus","value","required"],H={prefixCls:String,name:String,id:String,type:String,defaultChecked:{type:[Boolean,Number],default:void 0},checked:{type:[Boolean,Number],default:void 0},disabled:Boolean,tabindex:{type:[Number,String]},readonly:Boolean,autofocus:Boolean,value:z.any,required:Boolean};const L=E({compatConfig:{MODE:3},name:"Checkbox",inheritAttrs:!1,props:$(H,{prefixCls:"rc-checkbox",type:"checkbox",defaultChecked:!1}),emits:["click","change"],setup:function(a,d){var t=d.attrs,h=d.emit,g=d.expose,o=f(a.checked===void 0?a.defaultChecked:a.checked),i=f();M(function(){return a.checked},function(){o.value=a.checked}),g({focus:function(){var e;(e=i.value)===null||e===void 0||e.focus()},blur:function(){var e;(e=i.value)===null||e===void 0||e.blur()}});var l=f(),x=function(e){if(!a.disabled){a.checked===void 0&&(o.value=e.target.checked),e.shiftKey=l.value;var r={target:c(c({},a),{},{checked:e.target.checked}),stopPropagation:function(){e.stopPropagation()},preventDefault:function(){e.preventDefault()},nativeEvent:e};a.checked!==void 0&&(i.value.checked=!!a.checked),h("change",r),l.value=!1}},C=function(e){h("click",e),l.value=e.shiftKey};return function(){var n,e=a.prefixCls,r=a.name,s=a.id,p=a.type,b=a.disabled,K=a.readonly,P=a.tabindex,B=a.autofocus,S=a.value,N=a.required,_=T(a,G),q=t.class,D=t.onFocus,j=t.onBlur,w=t.onKeydown,A=t.onKeypress,F=t.onKeyup,y=c(c({},_),t),O=Object.keys(y).reduce(function(k,u){return(u.substr(0,5)==="aria-"||u.substr(0,5)==="data-"||u==="role")&&(k[u]=y[u]),k},{}),R=W(e,q,(n={},m(n,"".concat(e,"-checked"),o.value),m(n,"".concat(e,"-disabled"),b),n)),V=c(c({name:r,id:s,type:p,readonly:K,disabled:b,tabindex:P,class:"".concat(e,"-input"),checked:!!o.value,autofocus:B,value:S},O),{},{onChange:x,onClick:C,onFocus:D,onBlur:j,onKeydown:w,onKeypress:A,onKeyup:F,required:N});return v("span",{class:R},[v("input",c({ref:i},V),null),v("span",{class:"".concat(e,"-inner")},null)])}}});export{L as V};

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{d as a,U as t,V as s,c as n,cO as _,a0 as c}from"./index-d6594e8e.js";const o={class:"img-sli-container"},i=a({__name:"ImgSliPagePane",props:{paneIdx:{},tabIdx:{},left:{},right:{}},setup(l){return(e,r)=>(t(),s("div",o,[n(_,{left:e.left,right:e.right},null,8,["left","right"])]))}});const p=c(i,[["__scopeId","data-v-ec71de83"]]);export{p as default}; import{d as a,U as t,V as s,c as n,cQ as _,a0 as c}from"./index-0205daf8.js";const o={class:"img-sli-container"},i=a({__name:"ImgSliPagePane",props:{paneIdx:{},tabIdx:{},left:{},right:{}},setup(l){return(e,r)=>(t(),s("div",o,[n(_,{left:e.left,right:e.right},null,8,["left","right"])]))}});const p=c(i,[["__scopeId","data-v-ec71de83"]]);export{p as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

72
vue/dist/assets/TopicSearch-4fe24c7f.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{bV as i,b1 as t,e6 as f,bM as n}from"./index-d6594e8e.js";function u(e,s,r){if(!i(r))return!1;var a=typeof s;return(a=="number"?t(r)&&f(s,r.length):a=="string"&&s in r)?n(r[s],e):!1}export{u as i}; import{bV as i,b1 as t,e6 as f,bM as n}from"./index-0205daf8.js";function u(e,s,r){if(!i(r))return!1;var a=typeof s;return(a=="number"?t(r)&&f(s,r.length):a=="string"&&s in r)?n(r[s],e):!1}export{u as i};

View File

@ -1 +1 @@
import{d as F,a1 as B,cP as $,cc as S,U as _,V as w,W as f,c as l,a3 as d,X as p,Y as c,a4 as s,a2 as R,af as A,cQ as V,cR as y,z as x,B as E,ak as T,a0 as U}from"./index-d6594e8e.js";import{_ as N}from"./index-e620c28b.js";import{u as L,a as H,f as O,F as P,d as Q}from"./FileItem-2eb00024.js";import"./numInput.vue_vue_type_style_index_0_scoped_bd954eda_lang-c8c8013d.js";/* empty css */import"./index-cb6a3d31.js";import"./_isIterateeCall-bfd79848.js";import"./index-30b8f89a.js";import"./index-9b184148.js";const W={class:"actions-panel actions"},j={class:"item"},q={key:0,class:"file-list"},G={class:"hint"},X=F({__name:"batchDownload",props:{tabIdx:{},paneIdx:{},id:{}},setup(Y){const{stackViewEl:D}=L().toRefs(),{itemSize:h,gridItems:b,cellWidth:g}=H(),i=B(),m=O(),{selectdFiles:a}=$(m),r=S(),v=async e=>{const t=V(e);t&&m.addFiles(t.nodes)},C=async()=>{r.pushAction(async()=>{const e=await y.value.post("/zip",{paths:a.value.map(u=>u.fullpath),compress:i.batchDownloadCompress,pack_only:!1},{responseType:"blob"}),t=window.URL.createObjectURL(new Blob([e.data])),o=document.createElement("a");o.href=t,o.setAttribute("download",`iib_${new Date().toLocaleString()}.zip`),document.body.appendChild(o),o.click()})},I=async()=>{r.pushAction(async()=>{await y.value.post("/zip",{paths:a.value.map(e=>e.fullpath),compress:i.batchDownloadCompress,pack_only:!0},{responseType:"blob"}),x.success(E("success"))})},z=e=>{a.value.splice(e,1)};return(e,t)=>{const o=T,u=N;return _(),w("div",{class:"container",ref_key:"stackViewEl",ref:D,onDrop:v},[f("div",W,[l(o,{onClick:t[0]||(t[0]=n=>s(m).selectdFiles=[])},{default:d(()=>[p(c(e.$t("clear")),1)]),_:1}),f("div",j,[p(c(e.$t("compressFile"))+": ",1),l(u,{checked:s(i).batchDownloadCompress,"onUpdate:checked":t[1]||(t[1]=n=>s(i).batchDownloadCompress=n)},null,8,["checked"])]),l(o,{onClick:I,type:"primary",loading:!s(r).isIdle},{default:d(()=>[p(c(e.$t("packOnlyNotDownload")),1)]),_:1},8,["loading"]),l(o,{onClick:C,type:"primary",loading:!s(r).isIdle},{default:d(()=>[p(c(e.$t("zipDownload")),1)]),_:1},8,["loading"])]),s(a).length?(_(),R(s(Q),{key:1,ref:"scroller",class:"file-list",items:s(a).slice(),"item-size":s(h).first,"key-field":"fullpath","item-secondary-size":s(h).second,gridItems:s(b)},{default:d(({item:n,index:k})=>[l(P,{idx:k,file:n,"cell-width":s(g),"enable-close-icon":"",onCloseIconClick:J=>z(k),"full-screen-preview-image-url":s(A)(n),"enable-right-click-menu":!1},null,8,["idx","file","cell-width","onCloseIconClick","full-screen-preview-image-url"])]),_:1},8,["items","item-size","item-secondary-size","gridItems"])):(_(),w("div",q,[f("p",G,c(e.$t("batchDownloaDDragAndDropHint")),1)]))],544)}}});const le=U(X,[["__scopeId","data-v-3d7e6f2d"]]);export{le as default}; import{d as F,a1 as B,cR as S,cc as $,U as _,V as w,W as f,c as l,a3 as d,X as p,Y as c,a4 as s,a2 as R,af as A,cS as T,cT as y,z as V,B as x,ak as E,a0 as U}from"./index-0205daf8.js";import{_ as N}from"./index-728b29ca.js";import{u as L,a as H,f as O,F as W,d as j}from"./FileItem-cc53e03a.js";import"./numInput.vue_vue_type_style_index_0_scoped_bd954eda_lang-e54a5eff.js";/* empty css */import"./index-6a8edab1.js";import"./_isIterateeCall-7008db8e.js";import"./index-6d8e3499.js";import"./index-e9cc5bd5.js";const q={class:"actions-panel actions"},G={class:"item"},P={key:0,class:"file-list"},Q={class:"hint"},X=F({__name:"batchDownload",props:{tabIdx:{},paneIdx:{},id:{}},setup(Y){const{stackViewEl:D}=L().toRefs(),{itemSize:h,gridItems:b,cellWidth:g}=H(),i=B(),m=O(),{selectdFiles:a}=S(m),r=$(),v=async e=>{const t=T(e);t&&m.addFiles(t.nodes)},C=async()=>{r.pushAction(async()=>{const e=await y.value.post("/zip",{paths:a.value.map(u=>u.fullpath),compress:i.batchDownloadCompress,pack_only:!1},{responseType:"blob"}),t=window.URL.createObjectURL(new Blob([e.data])),o=document.createElement("a");o.href=t,o.setAttribute("download",`iib_${new Date().toLocaleString()}.zip`),document.body.appendChild(o),o.click()})},I=async()=>{r.pushAction(async()=>{await y.value.post("/zip",{paths:a.value.map(e=>e.fullpath),compress:i.batchDownloadCompress,pack_only:!0},{responseType:"blob"}),V.success(x("success"))})},z=e=>{a.value.splice(e,1)};return(e,t)=>{const o=E,u=N;return _(),w("div",{class:"container",ref_key:"stackViewEl",ref:D,onDrop:v},[f("div",q,[l(o,{onClick:t[0]||(t[0]=n=>s(m).selectdFiles=[])},{default:d(()=>[p(c(e.$t("clear")),1)]),_:1}),f("div",G,[p(c(e.$t("compressFile"))+": ",1),l(u,{checked:s(i).batchDownloadCompress,"onUpdate:checked":t[1]||(t[1]=n=>s(i).batchDownloadCompress=n)},null,8,["checked"])]),l(o,{onClick:I,type:"primary",loading:!s(r).isIdle},{default:d(()=>[p(c(e.$t("packOnlyNotDownload")),1)]),_:1},8,["loading"]),l(o,{onClick:C,type:"primary",loading:!s(r).isIdle},{default:d(()=>[p(c(e.$t("zipDownload")),1)]),_:1},8,["loading"])]),s(a).length?(_(),R(s(j),{key:1,ref:"scroller",class:"file-list",items:s(a).slice(),"item-size":s(h).first,"key-field":"fullpath","item-secondary-size":s(h).second,gridItems:s(b)},{default:d(({item:n,index:k})=>[l(W,{idx:k,file:n,"cell-width":s(g),"enable-close-icon":"",onCloseIconClick:J=>z(k),"full-screen-preview-image-url":s(A)(n),"enable-right-click-menu":!1},null,8,["idx","file","cell-width","onCloseIconClick","full-screen-preview-image-url"])]),_:1},8,["items","item-size","item-secondary-size","gridItems"])):(_(),w("div",P,[f("p",Q,c(e.$t("batchDownloaDDragAndDropHint")),1)]))],544)}}});const le=U(X,[["__scopeId","data-v-3d7e6f2d"]]);export{le as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{u as w,a as y,F as b,d as k}from"./FileItem-2eb00024.js";import{d as x,a1 as h,c9 as F,r as D,bh as I,bl as C,U as V,V as E,c as n,a3 as S,a4 as e,af as z,cQ as B,cS as R,a0 as A}from"./index-d6594e8e.js";import"./numInput.vue_vue_type_style_index_0_scoped_bd954eda_lang-c8c8013d.js";/* empty css */import"./index-cb6a3d31.js";import"./_isIterateeCall-bfd79848.js";import"./index-30b8f89a.js";import"./index-9b184148.js";const K=x({__name:"gridView",props:{tabIdx:{},paneIdx:{},id:{},removable:{type:Boolean},allowDragAndDrop:{type:Boolean},files:{},paneKey:{}},setup(p){const o=p,m=h(),{stackViewEl:d}=w().toRefs(),{itemSize:i,gridItems:u,cellWidth:f}=y(),g=F(),a=D(o.files??[]),_=async s=>{const l=B(s);o.allowDragAndDrop&&l&&(a.value=R([...a.value,...l.nodes]))},v=s=>{a.value.splice(s,1)};return I(()=>{m.pageFuncExportMap.set(o.paneKey,{getFiles:()=>C(a.value),setFiles:s=>a.value=s})}),(s,l)=>(V(),E("div",{class:"container",ref_key:"stackViewEl",ref:d,onDrop:_},[n(e(k),{ref:"scroller",class:"file-list",items:a.value.slice(),"item-size":e(i).first,"key-field":"fullpath","item-secondary-size":e(i).second,gridItems:e(u)},{default:S(({item:t,index:r})=>{var c;return[n(b,{idx:r,file:t,"cell-width":e(f),"enable-close-icon":o.removable,onCloseIconClick:T=>v(r),"full-screen-preview-image-url":e(z)(t),"extra-tags":(c=t==null?void 0:t.tags)==null?void 0:c.map(e(g).tagConvert),"enable-right-click-menu":!1},null,8,["idx","file","cell-width","enable-close-icon","onCloseIconClick","full-screen-preview-image-url","extra-tags"])]}),_:1},8,["items","item-size","item-secondary-size","gridItems"])],544))}});const W=A(K,[["__scopeId","data-v-0c31f6b2"]]);export{W as default}; import{u as w,a as y,F as b,d as k}from"./FileItem-cc53e03a.js";import{d as x,a1 as h,c9 as F,r as D,bh as I,bl as C,U as V,V as E,c as n,a3 as S,a4 as e,af as z,cS as B,cU as R,a0 as U}from"./index-0205daf8.js";import"./numInput.vue_vue_type_style_index_0_scoped_bd954eda_lang-e54a5eff.js";/* empty css */import"./index-6a8edab1.js";import"./_isIterateeCall-7008db8e.js";import"./index-6d8e3499.js";import"./index-e9cc5bd5.js";const A=x({__name:"gridView",props:{tabIdx:{},paneIdx:{},id:{},removable:{type:Boolean},allowDragAndDrop:{type:Boolean},files:{},paneKey:{}},setup(p){const o=p,m=h(),{stackViewEl:d}=w().toRefs(),{itemSize:i,gridItems:u,cellWidth:f}=y(),g=F(),a=D(o.files??[]),_=async s=>{const l=B(s);o.allowDragAndDrop&&l&&(a.value=R([...a.value,...l.nodes]))},v=s=>{a.value.splice(s,1)};return I(()=>{m.pageFuncExportMap.set(o.paneKey,{getFiles:()=>C(a.value),setFiles:s=>a.value=s})}),(s,l)=>(V(),E("div",{class:"container",ref_key:"stackViewEl",ref:d,onDrop:_},[n(e(k),{ref:"scroller",class:"file-list",items:a.value.slice(),"item-size":e(i).first,"key-field":"fullpath","item-secondary-size":e(i).second,gridItems:e(u)},{default:S(({item:t,index:r})=>{var c;return[n(b,{idx:r,file:t,"cell-width":e(f),"enable-close-icon":o.removable,onCloseIconClick:K=>v(r),"full-screen-preview-image-url":e(z)(t),"extra-tags":(c=t==null?void 0:t.tags)==null?void 0:c.map(e(g).tagConvert),"enable-right-click-menu":!1},null,8,["idx","file","cell-width","enable-close-icon","onCloseIconClick","full-screen-preview-image-url","extra-tags"])]}),_:1},8,["items","item-size","item-secondary-size","gridItems"])],544))}});const j=U(A,[["__scopeId","data-v-0c31f6b2"]]);export{j as default};

View File

@ -1 +1 @@
import{am as F,r as g,l as P,k as A,O as b,G as R,cc as q,cn as O,cs as z}from"./index-d6594e8e.js";import{u as L,a as Q,b as j,e as H}from"./FileItem-2eb00024.js";import{a as T,b as U,c as W}from"./MultiSelectKeep-ba3817a4.js";import{u as B}from"./useGenInfoDiff-f63a5430.js";let K=0;const V=()=>++K,X=(n,i,{dataUpdateStrategy:l="replace"}={})=>{const o=F([""]),c=g(!1),t=g(),a=g(!1);let f=g(-1);const v=new Set,w=e=>{var s;l==="replace"?t.value=e:l==="merge"&&(b((Array.isArray(t.value)||typeof t.value>"u")&&Array.isArray(e),"数据更新策略为合并时仅可用于值为数组的情况"),t.value=[...(s=t==null?void 0:t.value)!==null&&s!==void 0?s:[],...e])},d=e=>A(void 0,void 0,void 0,function*(){if(a.value||c.value&&typeof e>"u")return!1;a.value=!0;const s=V();f.value=s;try{let r;if(typeof e=="number"){if(r=o[e],typeof r!="string")return!1}else r=o[o.length-1];const h=yield n(r);if(v.has(s))return v.delete(s),!1;w(i(h));const u=h.cursor;if((e===o.length-1||typeof e!="number")&&(c.value=!u.has_next,u.has_next)){const m=u.next_cursor||u.next;b(typeof m=="string"),o.push(m)}}finally{f.value===s&&(a.value=!1)}return!0}),p=()=>{v.add(f.value),a.value=!1},x=(e=!1)=>A(void 0,void 0,void 0,function*(){const{refetch:s,force:r}=typeof e=="object"?e:{refetch:e};r&&p(),b(!a.value),o.splice(0,o.length,""),a.value=!1,t.value=void 0,c.value=!1,s&&(yield d())}),I=()=>({next:()=>A(void 0,void 0,void 0,function*(){if(a.value)throw new Error("不允许同时迭代");return{done:!(yield d()),value:t.value}})});return P({abort:p,load:c,next:d,res:t,loading:a,cursorStack:o,reset:x,[Symbol.asyncIterator]:I,iter:{[Symbol.asyncIterator]:I}})},se=n=>F(X(n,i=>i.files,{dataUpdateStrategy:"merge"})),ne=n=>{const i=F(new Set),l=R(()=>(n.res??[]).filter(y=>!i.has(y.fullpath))),o=q(),{stackViewEl:c,multiSelectedIdxs:t,stack:a,scroller:f,props:v}=L({images:l}).toRefs(),{itemSize:w,gridItems:d,cellWidth:p,onScroll:x}=Q({fetchNext:()=>n.next()}),{showMenuIdx:I}=j(),{onFileDragStart:e,onFileDragEnd:s}=T(),{showGenInfo:r,imageGenInfo:h,q:u,onContextMenuClick:m,onFileItemClick:C}=U({openNext:O}),{previewIdx:_,previewing:E,onPreviewVisibleChange:M,previewImgMove:D,canPreview:G}=W({loadNext:()=>n.next()}),J=async(y,S,N)=>{a.value=[{curr:"",files:l.value}],await m(y,S,N)};H("removeFiles",async({paths:y})=>{y.forEach(S=>i.add(S))});const k=()=>{z(l.value)};return{images:l,scroller:f,queue:o,iter:n,onContextMenuClickU:J,stackViewEl:c,previewIdx:_,previewing:E,onPreviewVisibleChange:M,previewImgMove:D,canPreview:G,itemSize:w,gridItems:d,showGenInfo:r,imageGenInfo:h,q:u,onContextMenuClick:m,onFileItemClick:C,showMenuIdx:I,multiSelectedIdxs:t,onFileDragStart:e,onFileDragEnd:s,cellWidth:p,onScroll:x,saveLoadedFileAsJson:k,saveAllFileAsJson:async()=>{for(;!n.load;)await n.next();k()},props:v,...B()}};export{se as c,ne as u}; import{am as F,r as g,l as P,k as A,O as b,G as R,cc as q,cn as O,cs as z}from"./index-0205daf8.js";import{u as L,a as Q,b as j,e as H}from"./FileItem-cc53e03a.js";import{a as T,b as U,c as W}from"./MultiSelectKeep-74181f4c.js";import{u as B}from"./useGenInfoDiff-13d2ea38.js";let K=0;const V=()=>++K,X=(n,i,{dataUpdateStrategy:l="replace"}={})=>{const o=F([""]),c=g(!1),t=g(),a=g(!1);let f=g(-1);const v=new Set,w=e=>{var s;l==="replace"?t.value=e:l==="merge"&&(b((Array.isArray(t.value)||typeof t.value>"u")&&Array.isArray(e),"数据更新策略为合并时仅可用于值为数组的情况"),t.value=[...(s=t==null?void 0:t.value)!==null&&s!==void 0?s:[],...e])},d=e=>A(void 0,void 0,void 0,function*(){if(a.value||c.value&&typeof e>"u")return!1;a.value=!0;const s=V();f.value=s;try{let r;if(typeof e=="number"){if(r=o[e],typeof r!="string")return!1}else r=o[o.length-1];const h=yield n(r);if(v.has(s))return v.delete(s),!1;w(i(h));const u=h.cursor;if((e===o.length-1||typeof e!="number")&&(c.value=!u.has_next,u.has_next)){const m=u.next_cursor||u.next;b(typeof m=="string"),o.push(m)}}finally{f.value===s&&(a.value=!1)}return!0}),p=()=>{v.add(f.value),a.value=!1},x=(e=!1)=>A(void 0,void 0,void 0,function*(){const{refetch:s,force:r}=typeof e=="object"?e:{refetch:e};r&&p(),b(!a.value),o.splice(0,o.length,""),a.value=!1,t.value=void 0,c.value=!1,s&&(yield d())}),I=()=>({next:()=>A(void 0,void 0,void 0,function*(){if(a.value)throw new Error("不允许同时迭代");return{done:!(yield d()),value:t.value}})});return P({abort:p,load:c,next:d,res:t,loading:a,cursorStack:o,reset:x,[Symbol.asyncIterator]:I,iter:{[Symbol.asyncIterator]:I}})},se=n=>F(X(n,i=>i.files,{dataUpdateStrategy:"merge"})),ne=n=>{const i=F(new Set),l=R(()=>(n.res??[]).filter(y=>!i.has(y.fullpath))),o=q(),{stackViewEl:c,multiSelectedIdxs:t,stack:a,scroller:f,props:v}=L({images:l}).toRefs(),{itemSize:w,gridItems:d,cellWidth:p,onScroll:x}=Q({fetchNext:()=>n.next()}),{showMenuIdx:I}=j(),{onFileDragStart:e,onFileDragEnd:s}=T(),{showGenInfo:r,imageGenInfo:h,q:u,onContextMenuClick:m,onFileItemClick:C}=U({openNext:O}),{previewIdx:_,previewing:E,onPreviewVisibleChange:M,previewImgMove:D,canPreview:G}=W({loadNext:()=>n.next()}),J=async(y,S,N)=>{a.value=[{curr:"",files:l.value}],await m(y,S,N)};H("removeFiles",async({paths:y})=>{y.forEach(S=>i.add(S))});const k=()=>{z(l.value)};return{images:l,scroller:f,queue:o,iter:n,onContextMenuClickU:J,stackViewEl:c,previewIdx:_,previewing:E,onPreviewVisibleChange:M,previewImgMove:D,canPreview:G,itemSize:w,gridItems:d,showGenInfo:r,imageGenInfo:h,q:u,onContextMenuClick:m,onFileItemClick:C,showMenuIdx:I,multiSelectedIdxs:t,onFileDragStart:e,onFileDragEnd:s,cellWidth:p,onScroll:x,saveLoadedFileAsJson:k,saveAllFileAsJson:async()=>{for(;!n.load;)await n.next();k()},props:v,...B()}};export{se as c,ne as u};

File diff suppressed because one or more lines are too long

1
vue/dist/assets/index-17a1bd90.js vendored Normal file
View File

@ -0,0 +1 @@
import{d as x,a1 as $,aK as g,cV as b,r as w,U as p,V as i,W as a,c as r,a3 as d,X as u,Y as n,Z as B,a8 as V,a4 as m,y as W,z as _,B as v,aj as I,ak as D,cW as N,a0 as R}from"./index-0205daf8.js";/* empty css */const F={class:"container"},K={class:"actions"},L={class:"uni-desc"},U={class:"snapshot"},j=x({__name:"index",props:{tabIdx:{},paneIdx:{},id:{},paneKey:{}},setup(q){const h=$(),t=g(),f=e=>{h.tabList=W(e.tabs)},k=b(async e=>{await N(`workspace_snapshot_${e.id}`),t.snapshots=t.snapshots.filter(c=>c.id!==e.id),_.success(v("deleteSuccess"))}),o=w(""),y=async()=>{if(!o.value){_.error(v("nameRequired"));return}const e=t.createSnapshot(o.value);await t.addSnapshot(e),_.success(v("saveCompleted"))};return(e,c)=>{const C=I,l=D;return p(),i("div",F,[a("div",K,[r(C,{value:o.value,"onUpdate:value":c[0]||(c[0]=s=>o.value=s),placeholder:e.$t("name"),style:{"max-width":"300px"}},null,8,["value","placeholder"]),r(l,{type:"primary",onClick:y},{default:d(()=>[u(n(e.$t("saveWorkspaceSnapshot")),1)]),_:1})]),a("p",L,n(e.$t("WorkspaceSnapshotDesc")),1),a("ul",U,[(p(!0),i(B,null,V(m(t).snapshots,s=>(p(),i("li",{key:s.id},[a("div",null,[a("span",null,n(s.name),1)]),a("div",null,[r(l,{onClick:S=>f(s)},{default:d(()=>[u(n(e.$t("restore")),1)]),_:2},1032,["onClick"]),r(l,{onClick:S=>m(k)(s)},{default:d(()=>[u(n(e.$t("remove")),1)]),_:2},1032,["onClick"])])]))),128))])])}}});const E=R(j,[["__scopeId","data-v-e55e3025"]]);export{E as default};

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{d as F,u as S,G as k,an as j,h as d,c as s,aq as U,e7 as W,r as q,bh as G,Z as V,dw as Z,P as N,cb as z}from"./index-d6594e8e.js";var H=function(){return{prefixCls:String,checked:{type:Boolean,default:void 0},onChange:{type:Function},onClick:{type:Function},"onUpdate:checked":Function}},J=F({compatConfig:{MODE:3},name:"ACheckableTag",props:H(),setup:function(e,i){var l=i.slots,r=i.emit,g=S("tag",e),u=g.prefixCls,o=function(C){var v=e.checked;r("update:checked",!v),r("change",!v),r("click",C)},p=k(function(){var a;return j(u.value,(a={},d(a,"".concat(u.value,"-checkable"),!0),d(a,"".concat(u.value,"-checkable-checked"),e.checked),a))});return function(){var a;return s("span",{class:p.value,onClick:o},[(a=l.default)===null||a===void 0?void 0:a.call(l)])}}});const b=J;var K=new RegExp("^(".concat(U.join("|"),")(-inverse)?$")),L=new RegExp("^(".concat(W.join("|"),")$")),Q=function(){return{prefixCls:String,color:{type:String},closable:{type:Boolean,default:!1},closeIcon:N.any,visible:{type:Boolean,default:void 0},onClose:{type:Function},"onUpdate:visible":Function,icon:N.any}},f=F({compatConfig:{MODE:3},name:"ATag",props:Q(),slots:["closeIcon","icon"],setup:function(e,i){var l=i.slots,r=i.emit,g=i.attrs,u=S("tag",e),o=u.prefixCls,p=u.direction,a=q(!0);G(function(){e.visible!==void 0&&(a.value=e.visible)});var C=function(t){t.stopPropagation(),r("update:visible",!1),r("close",t),!t.defaultPrevented&&e.visible===void 0&&(a.value=!1)},v=k(function(){var n=e.color;return n?K.test(n)||L.test(n):!1}),E=k(function(){var n;return j(o.value,(n={},d(n,"".concat(o.value,"-").concat(e.color),v.value),d(n,"".concat(o.value,"-has-color"),e.color&&!v.value),d(n,"".concat(o.value,"-hidden"),!a.value),d(n,"".concat(o.value,"-rtl"),p.value==="rtl"),n))});return function(){var n,t,h,m=e.icon,w=m===void 0?(n=l.icon)===null||n===void 0?void 0:n.call(l):m,y=e.color,_=e.closeIcon,P=_===void 0?(t=l.closeIcon)===null||t===void 0?void 0:t.call(l):_,x=e.closable,R=x===void 0?!1:x,B=function(){return R?P?s("span",{class:"".concat(o.value,"-close-icon"),onClick:C},[P]):s(z,{class:"".concat(o.value,"-close-icon"),onClick:C},null):null},O={backgroundColor:y&&!v.value?y:void 0},I=w||null,T=(h=l.default)===null||h===void 0?void 0:h.call(l),A=I?s(V,null,[I,s("span",null,[T])]):T,D="onClick"in g,$=s("span",{class:E.value,style:O},[A,B()]);return D?s(Z,null,{default:function(){return[$]}}):$}}});f.CheckableTag=b;f.install=function(c){return c.component(f.name,f),c.component(b.name,b),c};const Y=f;export{Y as _}; import{d as F,u as S,G as k,an as j,h as d,c as s,aq as U,e7 as W,r as q,bh as G,Z as V,dw as Z,P as N,cb as z}from"./index-0205daf8.js";var H=function(){return{prefixCls:String,checked:{type:Boolean,default:void 0},onChange:{type:Function},onClick:{type:Function},"onUpdate:checked":Function}},J=F({compatConfig:{MODE:3},name:"ACheckableTag",props:H(),setup:function(e,i){var l=i.slots,r=i.emit,g=S("tag",e),u=g.prefixCls,o=function(C){var v=e.checked;r("update:checked",!v),r("change",!v),r("click",C)},p=k(function(){var a;return j(u.value,(a={},d(a,"".concat(u.value,"-checkable"),!0),d(a,"".concat(u.value,"-checkable-checked"),e.checked),a))});return function(){var a;return s("span",{class:p.value,onClick:o},[(a=l.default)===null||a===void 0?void 0:a.call(l)])}}});const b=J;var K=new RegExp("^(".concat(U.join("|"),")(-inverse)?$")),L=new RegExp("^(".concat(W.join("|"),")$")),Q=function(){return{prefixCls:String,color:{type:String},closable:{type:Boolean,default:!1},closeIcon:N.any,visible:{type:Boolean,default:void 0},onClose:{type:Function},"onUpdate:visible":Function,icon:N.any}},f=F({compatConfig:{MODE:3},name:"ATag",props:Q(),slots:["closeIcon","icon"],setup:function(e,i){var l=i.slots,r=i.emit,g=i.attrs,u=S("tag",e),o=u.prefixCls,p=u.direction,a=q(!0);G(function(){e.visible!==void 0&&(a.value=e.visible)});var C=function(t){t.stopPropagation(),r("update:visible",!1),r("close",t),!t.defaultPrevented&&e.visible===void 0&&(a.value=!1)},v=k(function(){var n=e.color;return n?K.test(n)||L.test(n):!1}),E=k(function(){var n;return j(o.value,(n={},d(n,"".concat(o.value,"-").concat(e.color),v.value),d(n,"".concat(o.value,"-has-color"),e.color&&!v.value),d(n,"".concat(o.value,"-hidden"),!a.value),d(n,"".concat(o.value,"-rtl"),p.value==="rtl"),n))});return function(){var n,t,h,m=e.icon,w=m===void 0?(n=l.icon)===null||n===void 0?void 0:n.call(l):m,y=e.color,_=e.closeIcon,P=_===void 0?(t=l.closeIcon)===null||t===void 0?void 0:t.call(l):_,x=e.closable,R=x===void 0?!1:x,B=function(){return R?P?s("span",{class:"".concat(o.value,"-close-icon"),onClick:C},[P]):s(z,{class:"".concat(o.value,"-close-icon"),onClick:C},null):null},O={backgroundColor:y&&!v.value?y:void 0},I=w||null,T=(h=l.default)===null||h===void 0?void 0:h.call(l),A=I?s(V,null,[I,s("span",null,[T])]):T,D="onClick"in g,$=s("span",{class:E.value,style:O},[A,B()]);return D?s(Z,null,{default:function(){return[$]}}):$}}});f.CheckableTag=b;f.install=function(c){return c.component(f.name,f),c.component(b.name,b),c};const Y=f;export{Y as _};

View File

@ -1 +1 @@
import{cw as j,ay as z,d as K,j as U,dv as $,w as g,r as b,G as S,m as A,u as D,o as E,az as G,h as d,c as s,a as C,aw as H,bf as L,g as x,dw as W,P as c,dx as _}from"./index-d6594e8e.js";var R=z("small","default"),q=function(){return{id:String,prefixCls:String,size:c.oneOf(R),disabled:{type:Boolean,default:void 0},checkedChildren:c.any,unCheckedChildren:c.any,tabindex:c.oneOfType([c.string,c.number]),autofocus:{type:Boolean,default:void 0},loading:{type:Boolean,default:void 0},checked:c.oneOfType([c.string,c.number,c.looseBool]),checkedValue:c.oneOfType([c.string,c.number,c.looseBool]).def(!0),unCheckedValue:c.oneOfType([c.string,c.number,c.looseBool]).def(!1),onChange:{type:Function},onClick:{type:Function},onKeydown:{type:Function},onMouseup:{type:Function},"onUpdate:checked":{type:Function},onBlur:Function,onFocus:Function}},J=K({compatConfig:{MODE:3},name:"ASwitch",__ANT_SWITCH:!0,inheritAttrs:!1,props:q(),slots:["checkedChildren","unCheckedChildren"],setup:function(n,r){var o=r.attrs,y=r.slots,B=r.expose,l=r.emit,m=U();$(function(){g(!("defaultChecked"in o),"Switch","'defaultChecked' is deprecated, please use 'v-model:checked'"),g(!("value"in o),"Switch","`value` is not validate prop, do you mean `checked`?")});var h=b(n.checked!==void 0?n.checked:o.defaultChecked),f=S(function(){return h.value===n.checkedValue});A(function(){return n.checked},function(){h.value=n.checked});var v=D("switch",n),u=v.prefixCls,F=v.direction,T=v.size,i=b(),w=function(){var e;(e=i.value)===null||e===void 0||e.focus()},V=function(){var e;(e=i.value)===null||e===void 0||e.blur()};B({focus:w,blur:V}),E(function(){G(function(){n.autofocus&&!n.disabled&&i.value.focus()})});var k=function(e,t){n.disabled||(l("update:checked",e),l("change",e,t),m.onFieldChange())},I=function(e){l("blur",e)},N=function(e){w();var t=f.value?n.unCheckedValue:n.checkedValue;k(t,e),l("click",t,e)},M=function(e){e.keyCode===_.LEFT?k(n.unCheckedValue,e):e.keyCode===_.RIGHT&&k(n.checkedValue,e),l("keydown",e)},O=function(e){var t;(t=i.value)===null||t===void 0||t.blur(),l("mouseup",e)},P=S(function(){var a;return a={},d(a,"".concat(u.value,"-small"),T.value==="small"),d(a,"".concat(u.value,"-loading"),n.loading),d(a,"".concat(u.value,"-checked"),f.value),d(a,"".concat(u.value,"-disabled"),n.disabled),d(a,u.value,!0),d(a,"".concat(u.value,"-rtl"),F.value==="rtl"),a});return function(){var a;return s(W,{insertExtraNode:!0},{default:function(){return[s("button",C(C(C({},H(n,["prefixCls","checkedChildren","unCheckedChildren","checked","autofocus","checkedValue","unCheckedValue","id","onChange","onUpdate:checked"])),o),{},{id:(a=n.id)!==null&&a!==void 0?a:m.id.value,onKeydown:M,onClick:N,onBlur:I,onMouseup:O,type:"button",role:"switch","aria-checked":h.value,disabled:n.disabled||n.loading,class:[o.class,P.value],ref:i}),[s("div",{class:"".concat(u.value,"-handle")},[n.loading?s(L,{class:"".concat(u.value,"-loading-icon")},null):null]),s("span",{class:"".concat(u.value,"-inner")},[f.value?x(y,n,"checkedChildren"):x(y,n,"unCheckedChildren")])])]}})}}});const X=j(J);export{X as _}; import{cw as j,ay as z,d as K,j as U,dv as $,w as g,r as b,G as S,m as A,u as D,o as E,az as G,h as d,c as s,a as C,aw as H,bf as L,g as x,dw as W,P as c,dx as _}from"./index-0205daf8.js";var R=z("small","default"),q=function(){return{id:String,prefixCls:String,size:c.oneOf(R),disabled:{type:Boolean,default:void 0},checkedChildren:c.any,unCheckedChildren:c.any,tabindex:c.oneOfType([c.string,c.number]),autofocus:{type:Boolean,default:void 0},loading:{type:Boolean,default:void 0},checked:c.oneOfType([c.string,c.number,c.looseBool]),checkedValue:c.oneOfType([c.string,c.number,c.looseBool]).def(!0),unCheckedValue:c.oneOfType([c.string,c.number,c.looseBool]).def(!1),onChange:{type:Function},onClick:{type:Function},onKeydown:{type:Function},onMouseup:{type:Function},"onUpdate:checked":{type:Function},onBlur:Function,onFocus:Function}},J=K({compatConfig:{MODE:3},name:"ASwitch",__ANT_SWITCH:!0,inheritAttrs:!1,props:q(),slots:["checkedChildren","unCheckedChildren"],setup:function(n,r){var o=r.attrs,y=r.slots,B=r.expose,l=r.emit,m=U();$(function(){g(!("defaultChecked"in o),"Switch","'defaultChecked' is deprecated, please use 'v-model:checked'"),g(!("value"in o),"Switch","`value` is not validate prop, do you mean `checked`?")});var h=b(n.checked!==void 0?n.checked:o.defaultChecked),f=S(function(){return h.value===n.checkedValue});A(function(){return n.checked},function(){h.value=n.checked});var v=D("switch",n),u=v.prefixCls,F=v.direction,T=v.size,i=b(),w=function(){var e;(e=i.value)===null||e===void 0||e.focus()},V=function(){var e;(e=i.value)===null||e===void 0||e.blur()};B({focus:w,blur:V}),E(function(){G(function(){n.autofocus&&!n.disabled&&i.value.focus()})});var k=function(e,t){n.disabled||(l("update:checked",e),l("change",e,t),m.onFieldChange())},I=function(e){l("blur",e)},N=function(e){w();var t=f.value?n.unCheckedValue:n.checkedValue;k(t,e),l("click",t,e)},M=function(e){e.keyCode===_.LEFT?k(n.unCheckedValue,e):e.keyCode===_.RIGHT&&k(n.checkedValue,e),l("keydown",e)},O=function(e){var t;(t=i.value)===null||t===void 0||t.blur(),l("mouseup",e)},P=S(function(){var a;return a={},d(a,"".concat(u.value,"-small"),T.value==="small"),d(a,"".concat(u.value,"-loading"),n.loading),d(a,"".concat(u.value,"-checked"),f.value),d(a,"".concat(u.value,"-disabled"),n.disabled),d(a,u.value,!0),d(a,"".concat(u.value,"-rtl"),F.value==="rtl"),a});return function(){var a;return s(W,{insertExtraNode:!0},{default:function(){return[s("button",C(C(C({},H(n,["prefixCls","checkedChildren","unCheckedChildren","checked","autofocus","checkedValue","unCheckedValue","id","onChange","onUpdate:checked"])),o),{},{id:(a=n.id)!==null&&a!==void 0?a:m.id.value,onKeydown:M,onClick:N,onBlur:I,onMouseup:O,type:"button",role:"switch","aria-checked":h.value,disabled:n.disabled||n.loading,class:[o.class,P.value],ref:i}),[s("div",{class:"".concat(u.value,"-handle")},[n.loading?s(L,{class:"".concat(u.value,"-loading-icon")},null):null]),s("span",{class:"".concat(u.value,"-inner")},[f.value?x(y,n,"checkedChildren"):x(y,n,"unCheckedChildren")])])]}})}}});const X=j(J);export{X as _};

View File

@ -1 +1 @@
import{r as o,o as t,cJ as n}from"./index-d6594e8e.js";const a=function(){var e=o(!1);return t(function(){e.value=n()}),e};export{a as u}; import{r as o,o as t,cL as n}from"./index-0205daf8.js";const a=function(){var e=o(!1);return t(function(){e.value=n()}),e};export{a as u};

View File

@ -1 +1 @@
import{d as w,bC as D,av as A,cK as j,az as k,n as V,cL as B,cM as y,e as $,c as a,_ as M,h as r,a as P,cN as T,P as b}from"./index-d6594e8e.js";var K=["class","style"],L=function(){return{prefixCls:String,spinning:{type:Boolean,default:void 0},size:String,wrapperClassName:String,tip:b.any,delay:Number,indicator:b.any}},p=null;function O(t,n){return!!t&&!!n&&!isNaN(Number(n))}function q(t){var n=t.indicator;p=typeof n=="function"?n:function(){return a(n,null,null)}}const F=w({compatConfig:{MODE:3},name:"ASpin",inheritAttrs:!1,props:D(L(),{size:"default",spinning:!0,wrapperClassName:""}),setup:function(){return{originalUpdateSpinning:null,configProvider:A("configProvider",j)}},data:function(){var n=this.spinning,e=this.delay,i=O(n,e);return{sSpinning:n&&!i}},created:function(){this.originalUpdateSpinning=this.updateSpinning,this.debouncifyUpdateSpinning(this.$props)},mounted:function(){this.updateSpinning()},updated:function(){var n=this;k(function(){n.debouncifyUpdateSpinning(),n.updateSpinning()})},beforeUnmount:function(){this.cancelExistingSpin()},methods:{debouncifyUpdateSpinning:function(n){var e=n||this.$props,i=e.delay;i&&(this.cancelExistingSpin(),this.updateSpinning=V(this.originalUpdateSpinning,i))},updateSpinning:function(){var n=this.spinning,e=this.sSpinning;e!==n&&(this.sSpinning=n)},cancelExistingSpin:function(){var n=this.updateSpinning;n&&n.cancel&&n.cancel()},renderIndicator:function(n){var e="".concat(n,"-dot"),i=B(this,"indicator");return i===null?null:(Array.isArray(i)&&(i=i.length===1?i[0]:i),y(i)?$(i,{class:e}):p&&y(p())?$(p(),{class:e}):a("span",{class:"".concat(e," ").concat(n,"-dot-spin")},[a("i",{class:"".concat(n,"-dot-item")},null),a("i",{class:"".concat(n,"-dot-item")},null),a("i",{class:"".concat(n,"-dot-item")},null),a("i",{class:"".concat(n,"-dot-item")},null)]))}},render:function(){var n,e,i,o=this.$props,f=o.size,N=o.prefixCls,h=o.tip,d=h===void 0?(n=(e=this.$slots).tip)===null||n===void 0?void 0:n.call(e):h,x=o.wrapperClassName,l=this.$attrs,v=l.class,_=l.style,C=M(l,K),S=this.configProvider,U=S.getPrefixCls,z=S.direction,s=U("spin",N),u=this.sSpinning,E=(i={},r(i,s,!0),r(i,"".concat(s,"-sm"),f==="small"),r(i,"".concat(s,"-lg"),f==="large"),r(i,"".concat(s,"-spinning"),u),r(i,"".concat(s,"-show-text"),!!d),r(i,"".concat(s,"-rtl"),z==="rtl"),r(i,v,!!v),i),m=a("div",P(P({},C),{},{style:_,class:E}),[this.renderIndicator(s),d?a("div",{class:"".concat(s,"-text")},[d]):null]),g=T(this);if(g&&g.length){var c,I=(c={},r(c,"".concat(s,"-container"),!0),r(c,"".concat(s,"-blur"),u),c);return a("div",{class:["".concat(s,"-nested-loading"),x]},[u&&a("div",{key:"loading"},[m]),a("div",{class:I,key:"container"},[g])])}return m}});export{F as S,q as s}; import{d as w,bC as D,av as A,cM as j,az as k,n as V,cN as B,cO as y,e as $,c as a,_ as M,h as r,a as P,cP as O,P as b}from"./index-0205daf8.js";var T=["class","style"],W=function(){return{prefixCls:String,spinning:{type:Boolean,default:void 0},size:String,wrapperClassName:String,tip:b.any,delay:Number,indicator:b.any}},p=null;function q(t,n){return!!t&&!!n&&!isNaN(Number(n))}function G(t){var n=t.indicator;p=typeof n=="function"?n:function(){return a(n,null,null)}}const H=w({compatConfig:{MODE:3},name:"ASpin",inheritAttrs:!1,props:D(W(),{size:"default",spinning:!0,wrapperClassName:""}),setup:function(){return{originalUpdateSpinning:null,configProvider:A("configProvider",j)}},data:function(){var n=this.spinning,e=this.delay,i=q(n,e);return{sSpinning:n&&!i}},created:function(){this.originalUpdateSpinning=this.updateSpinning,this.debouncifyUpdateSpinning(this.$props)},mounted:function(){this.updateSpinning()},updated:function(){var n=this;k(function(){n.debouncifyUpdateSpinning(),n.updateSpinning()})},beforeUnmount:function(){this.cancelExistingSpin()},methods:{debouncifyUpdateSpinning:function(n){var e=n||this.$props,i=e.delay;i&&(this.cancelExistingSpin(),this.updateSpinning=V(this.originalUpdateSpinning,i))},updateSpinning:function(){var n=this.spinning,e=this.sSpinning;e!==n&&(this.sSpinning=n)},cancelExistingSpin:function(){var n=this.updateSpinning;n&&n.cancel&&n.cancel()},renderIndicator:function(n){var e="".concat(n,"-dot"),i=B(this,"indicator");return i===null?null:(Array.isArray(i)&&(i=i.length===1?i[0]:i),y(i)?$(i,{class:e}):p&&y(p())?$(p(),{class:e}):a("span",{class:"".concat(e," ").concat(n,"-dot-spin")},[a("i",{class:"".concat(n,"-dot-item")},null),a("i",{class:"".concat(n,"-dot-item")},null),a("i",{class:"".concat(n,"-dot-item")},null),a("i",{class:"".concat(n,"-dot-item")},null)]))}},render:function(){var n,e,i,o=this.$props,f=o.size,N=o.prefixCls,h=o.tip,d=h===void 0?(n=(e=this.$slots).tip)===null||n===void 0?void 0:n.call(e):h,x=o.wrapperClassName,l=this.$attrs,v=l.class,_=l.style,C=M(l,T),S=this.configProvider,U=S.getPrefixCls,z=S.direction,s=U("spin",N),u=this.sSpinning,E=(i={},r(i,s,!0),r(i,"".concat(s,"-sm"),f==="small"),r(i,"".concat(s,"-lg"),f==="large"),r(i,"".concat(s,"-spinning"),u),r(i,"".concat(s,"-show-text"),!!d),r(i,"".concat(s,"-rtl"),z==="rtl"),r(i,v,!!v),i),m=a("div",P(P({},C),{},{style:_,class:E}),[this.renderIndicator(s),d?a("div",{class:"".concat(s,"-text")},[d]):null]),g=O(this);if(g&&g.length){var c,I=(c={},r(c,"".concat(s,"-container"),!0),r(c,"".concat(s,"-blur"),u),c);return a("div",{class:["".concat(s,"-nested-loading"),x]},[u&&a("div",{key:"loading"},[m]),a("div",{class:I,key:"container"},[g])])}return m}});export{H as S,G as s};

View File

@ -1 +0,0 @@
import{d as x,a1 as $,aK as g,cT as b,r as w,U as p,V as i,W as a,c as r,a3 as d,X as u,Y as n,Z as B,a8 as I,a4 as m,y as V,z as _,B as v,aj as W,ak as D,cU as N,a0 as R}from"./index-d6594e8e.js";/* empty css */const U={class:"container"},F={class:"actions"},K={class:"uni-desc"},L={class:"snapshot"},T=x({__name:"index",props:{tabIdx:{},paneIdx:{},id:{},paneKey:{}},setup(j){const h=$(),t=g(),f=e=>{h.tabList=V(e.tabs)},k=b(async e=>{await N(`workspace_snapshot_${e.id}`),t.snapshots=t.snapshots.filter(c=>c.id!==e.id),_.success(v("deleteSuccess"))}),o=w(""),y=async()=>{if(!o.value){_.error(v("nameRequired"));return}const e=t.createSnapshot(o.value);await t.addSnapshot(e),_.success(v("saveCompleted"))};return(e,c)=>{const C=W,l=D;return p(),i("div",U,[a("div",F,[r(C,{value:o.value,"onUpdate:value":c[0]||(c[0]=s=>o.value=s),placeholder:e.$t("name"),style:{"max-width":"300px"}},null,8,["value","placeholder"]),r(l,{type:"primary",onClick:y},{default:d(()=>[u(n(e.$t("saveWorkspaceSnapshot")),1)]),_:1})]),a("p",K,n(e.$t("WorkspaceSnapshotDesc")),1),a("ul",L,[(p(!0),i(B,null,I(m(t).snapshots,s=>(p(),i("li",{key:s.id},[a("div",null,[a("span",null,n(s.name),1)]),a("div",null,[r(l,{onClick:S=>f(s)},{default:d(()=>[u(n(e.$t("restore")),1)]),_:2},1032,["onClick"]),r(l,{onClick:S=>m(k)(s)},{default:d(()=>[u(n(e.$t("remove")),1)]),_:2},1032,["onClick"])])]))),128))])])}}});const A=R(T,[["__scopeId","data-v-e55e3025"]]);export{A as default};

View File

@ -1 +1 @@
import{av as M,G as l,ax as D,ay as P,d as F,u as I,r as K,o as L,cx as _,b as y,bk as T,cy as A,an as $,h as o,c as B,a as G}from"./index-d6594e8e.js";import{u as V}from"./index-154b94da.js";var E=Symbol("rowContextKey"),W=function(r){D(E,r)},k=function(){return M(E,{gutter:l(function(){}),wrap:l(function(){}),supportFlexGap:l(function(){})})};P("top","middle","bottom","stretch");P("start","end","center","space-around","space-between");var U=function(){return{align:String,justify:String,prefixCls:String,gutter:{type:[Number,Array,Object],default:0},wrap:{type:Boolean,default:void 0}}},q=F({compatConfig:{MODE:3},name:"ARow",props:U(),setup:function(r,N){var g=N.slots,v=I("row",r),d=v.prefixCls,h=v.direction,j,x=K({xs:!0,sm:!0,md:!0,lg:!0,xl:!0,xxl:!0,xxxl:!0}),w=V();L(function(){j=_.subscribe(function(e){var t=r.gutter||0;(!Array.isArray(t)&&y(t)==="object"||Array.isArray(t)&&(y(t[0])==="object"||y(t[1])==="object"))&&(x.value=e)})}),T(function(){_.unsubscribe(j)});var S=l(function(){var e=[0,0],t=r.gutter,n=t===void 0?0:t,s=Array.isArray(n)?n:[n,0];return s.forEach(function(i,b){if(y(i)==="object")for(var a=0;a<A.length;a++){var p=A[a];if(x.value[p]&&i[p]!==void 0){e[b]=i[p];break}}else e[b]=i||0}),e});W({gutter:S,supportFlexGap:w,wrap:l(function(){return r.wrap})});var R=l(function(){var e;return $(d.value,(e={},o(e,"".concat(d.value,"-no-wrap"),r.wrap===!1),o(e,"".concat(d.value,"-").concat(r.justify),r.justify),o(e,"".concat(d.value,"-").concat(r.align),r.align),o(e,"".concat(d.value,"-rtl"),h.value==="rtl"),e))}),O=l(function(){var e=S.value,t={},n=e[0]>0?"".concat(e[0]/-2,"px"):void 0,s=e[1]>0?"".concat(e[1]/-2,"px"):void 0;return n&&(t.marginLeft=n,t.marginRight=n),w.value?t.rowGap="".concat(e[1],"px"):s&&(t.marginTop=s,t.marginBottom=s),t});return function(){var e;return B("div",{class:R.value,style:O.value},[(e=g.default)===null||e===void 0?void 0:e.call(g)])}}});const Y=q;function H(c){return typeof c=="number"?"".concat(c," ").concat(c," auto"):/^\d+(\.\d+)?(px|em|rem|%)$/.test(c)?"0 0 ".concat(c):c}var J=function(){return{span:[String,Number],order:[String,Number],offset:[String,Number],push:[String,Number],pull:[String,Number],xs:{type:[String,Number,Object],default:void 0},sm:{type:[String,Number,Object],default:void 0},md:{type:[String,Number,Object],default:void 0},lg:{type:[String,Number,Object],default:void 0},xl:{type:[String,Number,Object],default:void 0},xxl:{type:[String,Number,Object],default:void 0},xxxl:{type:[String,Number,Object],default:void 0},prefixCls:String,flex:[String,Number]}};const Z=F({compatConfig:{MODE:3},name:"ACol",props:J(),setup:function(r,N){var g=N.slots,v=k(),d=v.gutter,h=v.supportFlexGap,j=v.wrap,x=I("col",r),w=x.prefixCls,S=x.direction,R=l(function(){var e,t=r.span,n=r.order,s=r.offset,i=r.push,b=r.pull,a=w.value,p={};return["xs","sm","md","lg","xl","xxl","xxxl"].forEach(function(m){var f,u={},C=r[m];typeof C=="number"?u.span=C:y(C)==="object"&&(u=C||{}),p=G(G({},p),{},(f={},o(f,"".concat(a,"-").concat(m,"-").concat(u.span),u.span!==void 0),o(f,"".concat(a,"-").concat(m,"-order-").concat(u.order),u.order||u.order===0),o(f,"".concat(a,"-").concat(m,"-offset-").concat(u.offset),u.offset||u.offset===0),o(f,"".concat(a,"-").concat(m,"-push-").concat(u.push),u.push||u.push===0),o(f,"".concat(a,"-").concat(m,"-pull-").concat(u.pull),u.pull||u.pull===0),o(f,"".concat(a,"-rtl"),S.value==="rtl"),f))}),$(a,(e={},o(e,"".concat(a,"-").concat(t),t!==void 0),o(e,"".concat(a,"-order-").concat(n),n),o(e,"".concat(a,"-offset-").concat(s),s),o(e,"".concat(a,"-push-").concat(i),i),o(e,"".concat(a,"-pull-").concat(b),b),e),p)}),O=l(function(){var e=r.flex,t=d.value,n={};if(t&&t[0]>0){var s="".concat(t[0]/2,"px");n.paddingLeft=s,n.paddingRight=s}if(t&&t[1]>0&&!h.value){var i="".concat(t[1]/2,"px");n.paddingTop=i,n.paddingBottom=i}return e&&(n.flex=H(e),j.value===!1&&!n.minWidth&&(n.minWidth=0)),n});return function(){var e;return B("div",{class:R.value,style:O.value},[(e=g.default)===null||e===void 0?void 0:e.call(g)])}}});export{Z as C,Y as R}; import{av as M,G as l,ax as D,ay as P,d as F,u as I,r as K,o as L,cx as _,b as y,bk as T,cy as A,an as $,h as o,c as B,a as G}from"./index-0205daf8.js";import{u as V}from"./index-859cb083.js";var E=Symbol("rowContextKey"),W=function(r){D(E,r)},k=function(){return M(E,{gutter:l(function(){}),wrap:l(function(){}),supportFlexGap:l(function(){})})};P("top","middle","bottom","stretch");P("start","end","center","space-around","space-between");var U=function(){return{align:String,justify:String,prefixCls:String,gutter:{type:[Number,Array,Object],default:0},wrap:{type:Boolean,default:void 0}}},q=F({compatConfig:{MODE:3},name:"ARow",props:U(),setup:function(r,N){var g=N.slots,v=I("row",r),d=v.prefixCls,h=v.direction,j,x=K({xs:!0,sm:!0,md:!0,lg:!0,xl:!0,xxl:!0,xxxl:!0}),w=V();L(function(){j=_.subscribe(function(e){var t=r.gutter||0;(!Array.isArray(t)&&y(t)==="object"||Array.isArray(t)&&(y(t[0])==="object"||y(t[1])==="object"))&&(x.value=e)})}),T(function(){_.unsubscribe(j)});var S=l(function(){var e=[0,0],t=r.gutter,n=t===void 0?0:t,s=Array.isArray(n)?n:[n,0];return s.forEach(function(i,b){if(y(i)==="object")for(var a=0;a<A.length;a++){var p=A[a];if(x.value[p]&&i[p]!==void 0){e[b]=i[p];break}}else e[b]=i||0}),e});W({gutter:S,supportFlexGap:w,wrap:l(function(){return r.wrap})});var R=l(function(){var e;return $(d.value,(e={},o(e,"".concat(d.value,"-no-wrap"),r.wrap===!1),o(e,"".concat(d.value,"-").concat(r.justify),r.justify),o(e,"".concat(d.value,"-").concat(r.align),r.align),o(e,"".concat(d.value,"-rtl"),h.value==="rtl"),e))}),O=l(function(){var e=S.value,t={},n=e[0]>0?"".concat(e[0]/-2,"px"):void 0,s=e[1]>0?"".concat(e[1]/-2,"px"):void 0;return n&&(t.marginLeft=n,t.marginRight=n),w.value?t.rowGap="".concat(e[1],"px"):s&&(t.marginTop=s,t.marginBottom=s),t});return function(){var e;return B("div",{class:R.value,style:O.value},[(e=g.default)===null||e===void 0?void 0:e.call(g)])}}});const Y=q;function H(c){return typeof c=="number"?"".concat(c," ").concat(c," auto"):/^\d+(\.\d+)?(px|em|rem|%)$/.test(c)?"0 0 ".concat(c):c}var J=function(){return{span:[String,Number],order:[String,Number],offset:[String,Number],push:[String,Number],pull:[String,Number],xs:{type:[String,Number,Object],default:void 0},sm:{type:[String,Number,Object],default:void 0},md:{type:[String,Number,Object],default:void 0},lg:{type:[String,Number,Object],default:void 0},xl:{type:[String,Number,Object],default:void 0},xxl:{type:[String,Number,Object],default:void 0},xxxl:{type:[String,Number,Object],default:void 0},prefixCls:String,flex:[String,Number]}};const Z=F({compatConfig:{MODE:3},name:"ACol",props:J(),setup:function(r,N){var g=N.slots,v=k(),d=v.gutter,h=v.supportFlexGap,j=v.wrap,x=I("col",r),w=x.prefixCls,S=x.direction,R=l(function(){var e,t=r.span,n=r.order,s=r.offset,i=r.push,b=r.pull,a=w.value,p={};return["xs","sm","md","lg","xl","xxl","xxxl"].forEach(function(m){var f,u={},C=r[m];typeof C=="number"?u.span=C:y(C)==="object"&&(u=C||{}),p=G(G({},p),{},(f={},o(f,"".concat(a,"-").concat(m,"-").concat(u.span),u.span!==void 0),o(f,"".concat(a,"-").concat(m,"-order-").concat(u.order),u.order||u.order===0),o(f,"".concat(a,"-").concat(m,"-offset-").concat(u.offset),u.offset||u.offset===0),o(f,"".concat(a,"-").concat(m,"-push-").concat(u.push),u.push||u.push===0),o(f,"".concat(a,"-").concat(m,"-pull-").concat(u.pull),u.pull||u.pull===0),o(f,"".concat(a,"-rtl"),S.value==="rtl"),f))}),$(a,(e={},o(e,"".concat(a,"-").concat(t),t!==void 0),o(e,"".concat(a,"-order-").concat(n),n),o(e,"".concat(a,"-offset-").concat(s),s),o(e,"".concat(a,"-push-").concat(i),i),o(e,"".concat(a,"-pull-").concat(b),b),e),p)}),O=l(function(){var e=r.flex,t=d.value,n={};if(t&&t[0]>0){var s="".concat(t[0]/2,"px");n.paddingLeft=s,n.paddingRight=s}if(t&&t[1]>0&&!h.value){var i="".concat(t[1]/2,"px");n.paddingTop=i,n.paddingBottom=i}return e&&(n.flex=H(e),j.value===!1&&!n.minWidth&&(n.minWidth=0)),n});return function(){var e;return B("div",{class:R.value,style:O.value},[(e=g.default)===null||e===void 0?void 0:e.call(g)])}}});export{Z as C,Y as R};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{cl as e,cm as i,cn as r,co as a,b1 as n}from"./index-0205daf8.js";function c(s,t){return e(i(s,t,r),s+"")}function b(s){return a(s)&&n(s)}export{c as b,b as i};

View File

@ -1 +0,0 @@
import{cl as e,cm as i,cn as r,co as a,b1 as n}from"./index-d6594e8e.js";function c(s,t){return e(i(s,t,r),s+"")}function b(s){return a(s)&&n(s)}export{c as b,b as i};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{d as Z,a1 as ee,r as F,J as te,K as le,o as ie,U as v,V as N,c as i,a4 as e,W as g,a3 as n,X as k,Y as u,a5 as R,L as se,a6 as ae,af as oe,ag as $,$ as A,a2 as ne,z as w,B as re,cX as ce,cY as de,ak as ue,ai as me,T as fe,a0 as pe}from"./index-0205daf8.js";import{u as ve,c as ge,a as ke,F as we,d as he}from"./FileItem-cc53e03a.js";import{a as Ce,b as Se,c as _e,M as Ie,o as z,L as ye,R as xe,f as be}from"./MultiSelectKeep-74181f4c.js";import"./numInput.vue_vue_type_style_index_0_scoped_bd954eda_lang-e54a5eff.js";/* empty css */import"./index-6a8edab1.js";import"./_isIterateeCall-7008db8e.js";import"./index-6d8e3499.js";import"./index-e9cc5bd5.js";import"./shortcut-eca2d427.js";import"./Checkbox-951f37ba.js";import"./index-728b29ca.js";const Ve={class:"refresh-button"},Me={class:"hint"},Te={key:0,class:"preview-switch"},Fe=Z({__name:"randomImage",props:{tabIdx:{},paneIdx:{},id:{},paneKey:{}},setup(Ne){const B=ee(),m=F(!1),l=F([]),r=l,h=te(`${le}randomImageSettingNotificationShown`,!1),P=()=>{h.value||(w.info({content:re("randomImageSettingNotification"),duration:6,key:"randomImageSetting"}),h.value=!0)},f=async()=>{try{m.value=!0;const s=await ce();s.length===0&&w.warn("No data, please generate index in image search page first"),l.value=s}finally{m.value=!1,_()}},C=()=>{if(l.value.length===0){w.warn("没有图片可以浏览");return}z(l.value,o.value||0)};ie(()=>{f(),setTimeout(()=>{P()},2e3)});const{stackViewEl:K,multiSelectedIdxs:p,stack:L,scroller:U}=ve({images:l}).toRefs(),{onClearAllSelected:D,onSelectAll:E,onReverseSelect:G}=ge();Ce();const{itemSize:S,gridItems:O,cellWidth:W,onScroll:_}=ke(),{showGenInfo:c,imageGenInfo:I,q:X,onContextMenuClick:Y,onFileItemClick:q}=Se({openNext:de}),{previewIdx:o,previewing:y,onPreviewVisibleChange:H,previewImgMove:x,canPreview:b}=_e(),V=async(s,t,d)=>{L.value=[{curr:"",files:l.value}],await Y(s,t,d)};return(s,t)=>{var M;const d=ue,J=me,Q=fe;return v(),N("div",{class:"container",ref_key:"stackViewEl",ref:K},[i(Ie,{show:!!e(p).length||e(B).keepMultiSelect,onClearAllSelected:e(D),onSelectAll:e(E),onReverseSelect:e(G)},null,8,["show","onClearAllSelected","onSelectAll","onReverseSelect"]),g("div",Ve,[i(d,{onClick:f,onTouchstart:R(f,["prevent"]),type:"primary",loading:m.value,shape:"round"},{default:n(()=>[k(u(s.$t("shuffle")),1)]),_:1},8,["onTouchstart","loading"]),i(d,{onClick:C,onTouchstart:R(C,["prevent"]),type:"default",disabled:!((M=l.value)!=null&&M.length),shape:"round"},{default:n(()=>[k(u(s.$t("tiktokView")),1)]),_:1},8,["onTouchstart","disabled"])]),i(Q,{visible:e(c),"onUpdate:visible":t[1]||(t[1]=a=>ae(c)?c.value=a:null),width:"70vw","mask-closable":"",onOk:t[2]||(t[2]=a=>c.value=!1)},{cancelText:n(()=>[]),default:n(()=>[i(J,{active:"",loading:!e(X).isIdle},{default:n(()=>[g("div",{style:{width:"100%","word-break":"break-all","white-space":"pre-line","max-height":"70vh",overflow:"auto"},onDblclick:t[0]||(t[0]=a=>e(se)(e(I)))},[g("div",Me,u(s.$t("doubleClickToCopy")),1),k(" "+u(e(I)),1)],32)]),_:1},8,["loading"])]),_:1},8,["visible"]),i(e(he),{ref_key:"scroller",ref:U,class:"file-list",items:l.value.slice(),"item-size":e(S).first,"key-field":"fullpath","item-secondary-size":e(S).second,gridItems:e(O),onScroll:e(_)},{default:n(({item:a,index:T})=>[i(we,{idx:T,file:a,"cell-width":e(W),"full-screen-preview-image-url":e(r)[e(o)]?e(oe)(e(r)[e(o)]):"",onContextMenuClick:V,onPreviewVisibleChange:e(H),"is-selected-mutil-files":e(p).length>1,selected:e(p).includes(T),onFileItemClick:e(q),onTiktokView:(Re,j)=>e(z)(l.value,j)},null,8,["idx","file","cell-width","full-screen-preview-image-url","onPreviewVisibleChange","is-selected-mutil-files","selected","onFileItemClick","onTiktokView"])]),_:1},8,["items","item-size","item-secondary-size","gridItems","onScroll"]),e(y)?(v(),N("div",Te,[i(e(ye),{onClick:t[3]||(t[3]=a=>e(x)("prev")),class:$({disable:!e(b)("prev")})},null,8,["class"]),i(e(xe),{onClick:t[4]||(t[4]=a=>e(x)("next")),class:$({disable:!e(b)("next")})},null,8,["class"])])):A("",!0),e(y)&&e(r)&&e(r)[e(o)]?(v(),ne(be,{key:1,file:e(r)[e(o)],idx:e(o),onContextMenuClick:V},null,8,["file","idx"])):A("",!0)],512)}}});const We=pe(Fe,[["__scopeId","data-v-e1531e89"]]);export{We as default};

View File

@ -1 +0,0 @@
import{d as Z,a1 as ee,r as F,J as te,K as le,o as ie,U as v,V as N,c as i,a4 as e,W as g,a3 as n,X as k,Y as u,a5 as R,L as se,a6 as ae,af as oe,ag as $,$ as A,a2 as ne,z as w,B as re,cV as ce,cW as de,ak as ue,ai as me,T as fe,a0 as pe}from"./index-d6594e8e.js";import{u as ve,c as ge,a as ke,F as we,d as he}from"./FileItem-2eb00024.js";import{a as Ce,b as Se,c as _e,M as Ie,o as z,L as ye,R as xe,f as be}from"./MultiSelectKeep-ba3817a4.js";import"./numInput.vue_vue_type_style_index_0_scoped_bd954eda_lang-c8c8013d.js";/* empty css */import"./index-cb6a3d31.js";import"./_isIterateeCall-bfd79848.js";import"./index-30b8f89a.js";import"./index-9b184148.js";import"./shortcut-0468cdd7.js";import"./Checkbox-59427a1c.js";import"./index-e620c28b.js";const Ve={class:"refresh-button"},Me={class:"hint"},Te={key:0,class:"preview-switch"},Fe=Z({__name:"randomImage",props:{tabIdx:{},paneIdx:{},id:{},paneKey:{}},setup(Ne){const B=ee(),m=F(!1),l=F([]),r=l,h=te(`${le}randomImageSettingNotificationShown`,!1),P=()=>{h.value||(w.info({content:re("randomImageSettingNotification"),duration:6,key:"randomImageSetting"}),h.value=!0)},f=async()=>{try{m.value=!0;const s=await ce();s.length===0&&w.warn("No data, please generate index in image search page first"),l.value=s}finally{m.value=!1,_()}},C=()=>{if(l.value.length===0){w.warn("没有图片可以浏览");return}z(l.value,o.value||0)};ie(()=>{f(),setTimeout(()=>{P()},2e3)});const{stackViewEl:K,multiSelectedIdxs:p,stack:L,scroller:U}=ve({images:l}).toRefs(),{onClearAllSelected:W,onSelectAll:D,onReverseSelect:E}=ge();Ce();const{itemSize:S,gridItems:G,cellWidth:O,onScroll:_}=ke(),{showGenInfo:c,imageGenInfo:I,q,onContextMenuClick:H,onFileItemClick:J}=Se({openNext:de}),{previewIdx:o,previewing:y,onPreviewVisibleChange:Q,previewImgMove:x,canPreview:b}=_e(),V=async(s,t,d)=>{L.value=[{curr:"",files:l.value}],await H(s,t,d)};return(s,t)=>{var M;const d=ue,X=me,Y=fe;return v(),N("div",{class:"container",ref_key:"stackViewEl",ref:K},[i(Ie,{show:!!e(p).length||e(B).keepMultiSelect,onClearAllSelected:e(W),onSelectAll:e(D),onReverseSelect:e(E)},null,8,["show","onClearAllSelected","onSelectAll","onReverseSelect"]),g("div",Ve,[i(d,{onClick:f,onTouchstart:R(f,["prevent"]),type:"primary",loading:m.value,shape:"round"},{default:n(()=>[k(u(s.$t("shuffle")),1)]),_:1},8,["onTouchstart","loading"]),i(d,{onClick:C,onTouchstart:R(C,["prevent"]),type:"default",disabled:!((M=l.value)!=null&&M.length),shape:"round"},{default:n(()=>[k(u(s.$t("tiktokView")),1)]),_:1},8,["onTouchstart","disabled"])]),i(Y,{visible:e(c),"onUpdate:visible":t[1]||(t[1]=a=>ae(c)?c.value=a:null),width:"70vw","mask-closable":"",onOk:t[2]||(t[2]=a=>c.value=!1)},{cancelText:n(()=>[]),default:n(()=>[i(X,{active:"",loading:!e(q).isIdle},{default:n(()=>[g("div",{style:{width:"100%","word-break":"break-all","white-space":"pre-line","max-height":"70vh",overflow:"auto"},onDblclick:t[0]||(t[0]=a=>e(se)(e(I)))},[g("div",Me,u(s.$t("doubleClickToCopy")),1),k(" "+u(e(I)),1)],32)]),_:1},8,["loading"])]),_:1},8,["visible"]),i(e(he),{ref_key:"scroller",ref:U,class:"file-list",items:l.value.slice(),"item-size":e(S).first,"key-field":"fullpath","item-secondary-size":e(S).second,gridItems:e(G),onScroll:e(_)},{default:n(({item:a,index:T})=>[i(we,{idx:T,file:a,"cell-width":e(O),"full-screen-preview-image-url":e(r)[e(o)]?e(oe)(e(r)[e(o)]):"",onContextMenuClick:V,onPreviewVisibleChange:e(Q),"is-selected-mutil-files":e(p).length>1,selected:e(p).includes(T),onFileItemClick:e(J),onTiktokView:(Re,j)=>e(z)(l.value,j)},null,8,["idx","file","cell-width","full-screen-preview-image-url","onPreviewVisibleChange","is-selected-mutil-files","selected","onFileItemClick","onTiktokView"])]),_:1},8,["items","item-size","item-secondary-size","gridItems","onScroll"]),e(y)?(v(),N("div",Te,[i(e(ye),{onClick:t[3]||(t[3]=a=>e(x)("prev")),class:$({disable:!e(b)("prev")})},null,8,["class"]),i(e(xe),{onClick:t[4]||(t[4]=a=>e(x)("next")),class:$({disable:!e(b)("next")})},null,8,["class"])])):A("",!0),e(y)&&e(r)&&e(r)[e(o)]?(v(),ne(be,{key:1,file:e(r)[e(o)],idx:e(o),onContextMenuClick:V},null,8,["file","idx"])):A("",!0)],512)}}});const Oe=pe(Fe,[["__scopeId","data-v-e1531e89"]]);export{Oe as default};

View File

@ -1 +1 @@
import{R as y,C as v}from"./index-68461333.js";import{cw as f,c as d,A as w,d as P,U as a,V as c,W as r,Z as S,a8 as V,aG as O,a3 as R,X as u,Y as p,a4 as b,ak as $,a0 as x,R as H,J as _,K as m}from"./index-d6594e8e.js";const A=f(y),E=f(v);var L={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M878.3 392.1L631.9 145.7c-6.5-6.5-15-9.7-23.5-9.7s-17 3.2-23.5 9.7L423.8 306.9c-12.2-1.4-24.5-2-36.8-2-73.2 0-146.4 24.1-206.5 72.3-15.4 12.3-16.6 35.4-2.7 49.4l181.7 181.7-215.4 215.2a15.8 15.8 0 00-4.6 9.8l-3.4 37.2c-.9 9.4 6.6 17.4 15.9 17.4.5 0 1 0 1.5-.1l37.2-3.4c3.7-.3 7.2-2 9.8-4.6l215.4-215.4 181.7 181.7c6.5 6.5 15 9.7 23.5 9.7 9.7 0 19.3-4.2 25.9-12.4 56.3-70.3 79.7-158.3 70.2-243.4l161.1-161.1c12.9-12.8 12.9-33.8 0-46.8z"}}]},name:"pushpin",theme:"filled"};const C=L;function h(t){for(var e=1;e<arguments.length;e++){var s=arguments[e]!=null?Object(arguments[e]):{},n=Object.keys(s);typeof Object.getOwnPropertySymbols=="function"&&(n=n.concat(Object.getOwnPropertySymbols(s).filter(function(i){return Object.getOwnPropertyDescriptor(s,i).enumerable}))),n.forEach(function(i){N(t,i,s[i])})}return t}function N(t,e,s){return e in t?Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[e]=s,t}var l=function(e,s){var n=h({},e,s.attrs);return d(w,h({},n,{icon:C}),null)};l.displayName="PushpinFilled";l.inheritAttrs=!1;const z=l,F={class:"record-container"},k={style:{flex:"1"}},I={class:"rec-actions"},B=["onClick"],J=P({__name:"HistoryRecord",props:{records:{}},emits:["reuseRecord"],setup(t){return(e,s)=>{const n=$;return a(),c("div",null,[r("ul",F,[(a(!0),c(S,null,V(e.records.getRecords(),i=>(a(),c("li",{key:i.id,class:"record"},[r("div",k,[O(e.$slots,"default",{record:i},void 0,!0)]),r("div",I,[d(n,{onClick:g=>e.$emit("reuseRecord",i),type:"primary"},{default:R(()=>[u(p(e.$t("restore")),1)]),_:2},1032,["onClick"]),r("div",{class:"pin",onClick:g=>e.records.switchPin(i)},[d(b(z)),u(" "+p(e.records.isPinned(i)?e.$t("unpin"):e.$t("pin")),1)],8,B)])]))),128))])])}}});const q=x(J,[["__scopeId","data-v-fff181dd"]]);class o{constructor(e=128,s=[],n=[]){this.maxLength=e,this.records=s,this.pinnedValues=n}isPinned(e){return this.pinnedValues.some(s=>s.id===e.id)}add(e){this.records.length>=this.maxLength&&this.records.pop(),this.records.unshift({...e,id:H()+Date.now(),time:new Date().toLocaleString()})}pin(e){const s=this.records.findIndex(n=>n.id===e.id);s!==-1&&this.records.splice(s,1),this.pinnedValues.push(e)}unpin(e){const s=this.pinnedValues.findIndex(n=>n.id===e.id);s!==-1&&this.pinnedValues.splice(s,1),this.records.unshift(e)}switchPin(e){this.isPinned(e)?this.unpin(e):this.pin(e)}getRecords(){return[...this.pinnedValues,...this.records]}getPinnedValues(){return this.pinnedValues}}const G=_(`${m}fuzzy-search-HistoryRecord`,new o,{serializer:{read:t=>{const e=JSON.parse(t);return new o(e.maxLength,e.records,e.pinnedValues)},write:JSON.stringify}}),M=_(`${m}tag-search-HistoryRecord`,new o,{serializer:{read:t=>{const e=JSON.parse(t);return new o(e.maxLength,e.records,e.pinnedValues)},write:JSON.stringify}});export{q as H,E as _,A as a,G as f,M as t}; import{R as y,C as v}from"./index-b9ffc995.js";import{cw as f,c as d,A as w,d as P,U as a,V as c,W as r,Z as S,a8 as V,aG as O,a3 as R,X as u,Y as p,a4 as b,ak as $,a0 as x,R as H,J as _,K as m}from"./index-0205daf8.js";const A=f(y),E=f(v);var L={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M878.3 392.1L631.9 145.7c-6.5-6.5-15-9.7-23.5-9.7s-17 3.2-23.5 9.7L423.8 306.9c-12.2-1.4-24.5-2-36.8-2-73.2 0-146.4 24.1-206.5 72.3-15.4 12.3-16.6 35.4-2.7 49.4l181.7 181.7-215.4 215.2a15.8 15.8 0 00-4.6 9.8l-3.4 37.2c-.9 9.4 6.6 17.4 15.9 17.4.5 0 1 0 1.5-.1l37.2-3.4c3.7-.3 7.2-2 9.8-4.6l215.4-215.4 181.7 181.7c6.5 6.5 15 9.7 23.5 9.7 9.7 0 19.3-4.2 25.9-12.4 56.3-70.3 79.7-158.3 70.2-243.4l161.1-161.1c12.9-12.8 12.9-33.8 0-46.8z"}}]},name:"pushpin",theme:"filled"};const C=L;function h(t){for(var e=1;e<arguments.length;e++){var s=arguments[e]!=null?Object(arguments[e]):{},n=Object.keys(s);typeof Object.getOwnPropertySymbols=="function"&&(n=n.concat(Object.getOwnPropertySymbols(s).filter(function(i){return Object.getOwnPropertyDescriptor(s,i).enumerable}))),n.forEach(function(i){N(t,i,s[i])})}return t}function N(t,e,s){return e in t?Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[e]=s,t}var l=function(e,s){var n=h({},e,s.attrs);return d(w,h({},n,{icon:C}),null)};l.displayName="PushpinFilled";l.inheritAttrs=!1;const z=l,F={class:"record-container"},k={style:{flex:"1"}},I={class:"rec-actions"},B=["onClick"],J=P({__name:"HistoryRecord",props:{records:{}},emits:["reuseRecord"],setup(t){return(e,s)=>{const n=$;return a(),c("div",null,[r("ul",F,[(a(!0),c(S,null,V(e.records.getRecords(),i=>(a(),c("li",{key:i.id,class:"record"},[r("div",k,[O(e.$slots,"default",{record:i},void 0,!0)]),r("div",I,[d(n,{onClick:g=>e.$emit("reuseRecord",i),type:"primary"},{default:R(()=>[u(p(e.$t("restore")),1)]),_:2},1032,["onClick"]),r("div",{class:"pin",onClick:g=>e.records.switchPin(i)},[d(b(z)),u(" "+p(e.records.isPinned(i)?e.$t("unpin"):e.$t("pin")),1)],8,B)])]))),128))])])}}});const q=x(J,[["__scopeId","data-v-fff181dd"]]);class o{constructor(e=128,s=[],n=[]){this.maxLength=e,this.records=s,this.pinnedValues=n}isPinned(e){return this.pinnedValues.some(s=>s.id===e.id)}add(e){this.records.length>=this.maxLength&&this.records.pop(),this.records.unshift({...e,id:H()+Date.now(),time:new Date().toLocaleString()})}pin(e){const s=this.records.findIndex(n=>n.id===e.id);s!==-1&&this.records.splice(s,1),this.pinnedValues.push(e)}unpin(e){const s=this.pinnedValues.findIndex(n=>n.id===e.id);s!==-1&&this.pinnedValues.splice(s,1),this.records.unshift(e)}switchPin(e){this.isPinned(e)?this.unpin(e):this.pin(e)}getRecords(){return[...this.pinnedValues,...this.records]}getPinnedValues(){return this.pinnedValues}}const G=_(`${m}fuzzy-search-HistoryRecord`,new o,{serializer:{read:t=>{const e=JSON.parse(t);return new o(e.maxLength,e.records,e.pinnedValues)},write:JSON.stringify}}),M=_(`${m}tag-search-HistoryRecord`,new o,{serializer:{read:t=>{const e=JSON.parse(t);return new o(e.maxLength,e.records,e.pinnedValues)},write:JSON.stringify}});export{q as H,E as _,A as a,G as f,M as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{u as G,g as d}from"./FileItem-2eb00024.js";import{r as b,t as j,ct as m,cu as y,cv as D}from"./index-d6594e8e.js";const r=new Map,A=()=>{const{useEventListen:k,sortedFiles:f,getViewableAreaFiles:w}=G().toRefs(),c=b(d.defaultChangeIndchecked),u=b(d.defaultSeedChangeChecked),g=async()=>{if(await j(100),!c.value)return;const o=w.value().filter(e=>m(e.fullpath)&&!e.gen_info_obj);if(!o.length)return;const t=await y(o.map(e=>e.fullpath).filter(e=>!r.has(e)));o.forEach(e=>{const i=t[e.fullpath]||r.get(e.fullpath)||"";r.set(e.fullpath,i),e.gen_info_obj=D(i),e.gen_info_raw=i})};k.value("viewableAreaFilesChange",g);const F=o=>{const t=f.value;return[o,u.value,t[o-1],t[o],t[o+1]]};function I(o,t,e,i){const a={diff:{},empty:!0,ownFile:"",otherFile:""};if(t+e<0||t+e>=f.value.length||f.value[t]==null||!("gen_info_obj"in f.value[t])||!("gen_info_obj"in f.value[t+e]))return a;const l=o,s=f.value[t+e].gen_info_obj;if(s==null)return a;const h=["hashes","resources"];a.diff={},a.ownFile=i.name,a.otherFile=f.value[t+e].name,a.empty=!1,u.value||h.push("seed");for(const n in l)if(!h.includes(n)){if(!(n in s)){a.diff[n]="+";continue}if(l[n]!=s[n])if(n.includes("rompt")&&l[n]!=""&&s[n]!=""){const p=l[n].split(","),C=s[n].split(",");let _=0;for(const v in p)p[v]!=C[v]&&_++;a.diff[n]=_}else a.diff[n]=[l[n],s[n]]}return a}return{getGenDiff:I,changeIndchecked:c,seedChangeChecked:u,getRawGenParams:()=>g(),getGenDiffWatchDep:F}};export{A as u}; import{u as G,g as d}from"./FileItem-cc53e03a.js";import{r as b,t as j,ct as m,cu as y,cv as D}from"./index-0205daf8.js";const r=new Map,A=()=>{const{useEventListen:k,sortedFiles:f,getViewableAreaFiles:w}=G().toRefs(),c=b(d.defaultChangeIndchecked),u=b(d.defaultSeedChangeChecked),g=async()=>{if(await j(100),!c.value)return;const o=w.value().filter(e=>m(e.fullpath)&&!e.gen_info_obj);if(!o.length)return;const t=await y(o.map(e=>e.fullpath).filter(e=>!r.has(e)));o.forEach(e=>{const i=t[e.fullpath]||r.get(e.fullpath)||"";r.set(e.fullpath,i),e.gen_info_obj=D(i),e.gen_info_raw=i})};k.value("viewableAreaFilesChange",g);const F=o=>{const t=f.value;return[o,u.value,t[o-1],t[o],t[o+1]]};function I(o,t,e,i){const a={diff:{},empty:!0,ownFile:"",otherFile:""};if(t+e<0||t+e>=f.value.length||f.value[t]==null||!("gen_info_obj"in f.value[t])||!("gen_info_obj"in f.value[t+e]))return a;const l=o,s=f.value[t+e].gen_info_obj;if(s==null)return a;const h=["hashes","resources"];a.diff={},a.ownFile=i.name,a.otherFile=f.value[t+e].name,a.empty=!1,u.value||h.push("seed");for(const n in l)if(!h.includes(n)){if(!(n in s)){a.diff[n]="+";continue}if(l[n]!=s[n])if(n.includes("rompt")&&l[n]!=""&&s[n]!=""){const p=l[n].split(","),C=s[n].split(",");let _=0;for(const v in p)p[v]!=C[v]&&_++;a.diff[n]=_}else a.diff[n]=[l[n],s[n]]}return a}return{getGenDiff:I,changeIndchecked:c,seedChangeChecked:u,getRawGenParams:()=>g(),getGenDiffWatchDep:F}};export{A as u};

2
vue/dist/index.html vendored
View File

@ -7,7 +7,7 @@
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Infinite Image Browsing</title> <title>Infinite Image Browsing</title>
<script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-d6594e8e.js"></script> <script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-0205daf8.js"></script>
<link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-af514ea9.css"> <link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-af514ea9.css">
</head> </head>

View File

@ -313,8 +313,6 @@ export const searchIibOutputByPrompt = async (req: PromptSearchReq) => {
// ===== Hierarchical Tag Graph ===== // ===== Hierarchical Tag Graph =====
export interface TagGraphReq { export interface TagGraphReq {
folder_paths: string[] folder_paths: string[]
top_n_tags?: number
top_n_clusters?: number
lang?: string lang?: string
} }

View File

@ -12,6 +12,27 @@ export const de: Partial<IIBI18nMap> = {
'fuzzy-search': 'Schnellsuche', 'fuzzy-search': 'Schnellsuche',
autoUpdate: 'Erkannte Änderungen, automatische Aktualisierung wird ausgeführt', autoUpdate: 'Erkannte Änderungen, automatische Aktualisierung wird ausgeführt',
faq: 'FAQ', faq: 'FAQ',
helpFeedback: 'Hilfe / Feedback',
helpFeedbackWay1: 'FAQ ansehen / ähnliche Issues suchen',
helpFeedbackSearchIssues: 'Issues durchsuchen',
helpFeedbackWay2: 'Neues Issue erstellen',
helpFeedbackNewIssue: 'Auf GitHub erstellen',
helpFeedbackWay3: 'Dem Maintainer eine E-Mail senden',
// ===== Tag Graph (Topic Search) =====
tagGraphGenerating: 'Diagramm wird erzeugt…',
tagGraphStatLayers: 'Ebenen',
tagGraphStatNodes: 'Knoten',
tagGraphStatLinks: 'Verbindungen',
tagGraphAllLayers: 'Alle Ebenen',
tagGraphFilterPlaceholder: 'Stichwort-Filter (Treffer + Nachbarn)',
tagGraphFilterHopsTitle: 'Erweitern (N Hops)',
tagGraphFilterApply: 'Filtern',
tagGraphFilterReset: 'Zurücksetzen',
tagGraphTooltipFilter: 'Filtern',
tagGraphTooltipOpenCluster: 'Cluster öffnen',
tagGraphFullscreenUnsupported: 'Vollbild wird in dieser Umgebung nicht unterstützt',
tagGraphFullscreenFailed: 'Vollbild konnte nicht gestartet werden',
selectExactMatchTag: 'Wähle Tags für exakte Übereinstimmung aus', selectExactMatchTag: 'Wähle Tags für exakte Übereinstimmung aus',
selectAnyMatchTag: '(Optional) Wähle Tags für beliebige Übereinstimmung aus', selectAnyMatchTag: '(Optional) Wähle Tags für beliebige Übereinstimmung aus',
selectExcludeTag: '(Optional) Wähle Tags zum Ausschliessen aus', selectExcludeTag: '(Optional) Wähle Tags zum Ausschliessen aus',

View File

@ -249,6 +249,27 @@ You can specify which snapshot to restore to when starting IIB in the global set
'fuzzy-search': 'Fuzzy search', 'fuzzy-search': 'Fuzzy search',
autoUpdate: 'Detected changes, automatically updating', autoUpdate: 'Detected changes, automatically updating',
faq: 'FAQ', faq: 'FAQ',
helpFeedback: 'Help / Feedback',
helpFeedbackWay1: 'Check FAQ / search related issues',
helpFeedbackSearchIssues: 'Search issues',
helpFeedbackWay2: 'Open a new issue',
helpFeedbackNewIssue: 'Create on GitHub',
helpFeedbackWay3: 'Email the maintainer',
// ===== Tag Graph (Topic Search) =====
tagGraphGenerating: 'Generating graph...',
tagGraphStatLayers: 'Layers',
tagGraphStatNodes: 'Nodes',
tagGraphStatLinks: 'Links',
tagGraphAllLayers: 'All layers',
tagGraphFilterPlaceholder: 'Keyword filter (match + neighbors)',
tagGraphFilterHopsTitle: 'Expand hops (N)',
tagGraphFilterApply: 'Filter',
tagGraphFilterReset: 'Reset',
tagGraphTooltipFilter: 'Filter',
tagGraphTooltipOpenCluster: 'Open cluster',
tagGraphFullscreenUnsupported: 'Fullscreen is not supported in this environment',
tagGraphFullscreenFailed: 'Failed to enter fullscreen',
selectExactMatchTag: 'Select Exact Match Tags. You can search by entering partial characters', selectExactMatchTag: 'Select Exact Match Tags. You can search by entering partial characters',
selectAnyMatchTag: 'Optional, Select Any Match Tags. You can search by entering partial characters', selectAnyMatchTag: 'Optional, Select Any Match Tags. You can search by entering partial characters',
selectExcludeTag: 'Optional, Select Exclude Tags. You can search by entering partial characters', selectExcludeTag: 'Optional, Select Exclude Tags. You can search by entering partial characters',

View File

@ -266,6 +266,27 @@ export const zhHans = {
selectAnyMatchTag: '可选,选择匹配其中一个或多个的 Tag。 您可以输入部分字符进行搜索', selectAnyMatchTag: '可选,选择匹配其中一个或多个的 Tag。 您可以输入部分字符进行搜索',
selectExcludeTag: '可选,选择需要排除掉的 Tag。 您可以输入部分字符进行搜索', selectExcludeTag: '可选,选择需要排除掉的 Tag。 您可以输入部分字符进行搜索',
faq: '常见问题', faq: '常见问题',
helpFeedback: '寻求帮助/反馈',
helpFeedbackWay1: '先看看常见问题 / 找找相关 issue',
helpFeedbackSearchIssues: '搜索 issues',
helpFeedbackWay2: '提一个新的 issue',
helpFeedbackNewIssue: '去 GitHub 创建',
helpFeedbackWay3: '直接发邮件给维护者',
// ===== Tag Graph (Topic Search) =====
tagGraphGenerating: '正在生成关系图...',
tagGraphStatLayers: '层级',
tagGraphStatNodes: '节点',
tagGraphStatLinks: '连线',
tagGraphAllLayers: '全部层级',
tagGraphFilterPlaceholder: '关键字过滤(命中 + 上下游)',
tagGraphFilterHopsTitle: '扩展层数N 跳)',
tagGraphFilterApply: '筛选',
tagGraphFilterReset: '重置',
tagGraphTooltipFilter: '过滤',
tagGraphTooltipOpenCluster: '打开聚类',
tagGraphFullscreenUnsupported: '当前环境不支持全屏',
tagGraphFullscreenFailed: '全屏失败',
autoUpdate: '检测到发生改变自动更新', autoUpdate: '检测到发生改变自动更新',
'fuzzy-search': '模糊搜索', 'fuzzy-search': '模糊搜索',
'fuzzy-search-placeholder': '输入图像信息或者文件名的一部分来进行搜索', 'fuzzy-search-placeholder': '输入图像信息或者文件名的一部分来进行搜索',

View File

@ -273,6 +273,27 @@ export const zhHant: Partial<IIBI18nMap> = {
selectAnyMatchTag: '可選,選擇匹配其中一個或多個的 Tag。 您可以輸入部分字符進行搜索', selectAnyMatchTag: '可選,選擇匹配其中一個或多個的 Tag。 您可以輸入部分字符進行搜索',
selectExcludeTag: '可選,選擇需要排除掉的 Tag。 您可以輸入部分字符進行搜索', selectExcludeTag: '可選,選擇需要排除掉的 Tag。 您可以輸入部分字符進行搜索',
faq: '常見問題', faq: '常見問題',
helpFeedback: '尋求幫助/回饋',
helpFeedbackWay1: '先看看常見問題 / 找找相關 issue',
helpFeedbackSearchIssues: '搜尋 issues',
helpFeedbackWay2: '提一個新的 issue',
helpFeedbackNewIssue: '去 GitHub 建立',
helpFeedbackWay3: '直接發郵件給維護者',
// ===== Tag Graph (Topic Search) =====
tagGraphGenerating: '正在生成關係圖...',
tagGraphStatLayers: '層級',
tagGraphStatNodes: '節點',
tagGraphStatLinks: '連線',
tagGraphAllLayers: '全部層級',
tagGraphFilterPlaceholder: '關鍵字過濾(命中 + 上下游)',
tagGraphFilterHopsTitle: '擴展層數N 跳)',
tagGraphFilterApply: '篩選',
tagGraphFilterReset: '重置',
tagGraphTooltipFilter: '過濾',
tagGraphTooltipOpenCluster: '打開聚類',
tagGraphFullscreenUnsupported: '目前環境不支援全螢幕',
tagGraphFullscreenFailed: '全螢幕失敗',
autoUpdate: '檢測到發生改變自動更新', autoUpdate: '檢測到發生改變自動更新',
'fuzzy-search': '模糊搜尋', 'fuzzy-search': '模糊搜尋',
'fuzzy-search-placeholder': '輸入圖片信息或者文件名的一部分來進行搜尋', 'fuzzy-search-placeholder': '輸入圖片信息或者文件名的一部分來進行搜尋',

View File

@ -2,9 +2,9 @@
import { useGlobalStore, type TabPane } from '@/store/useGlobalStore' import { useGlobalStore, type TabPane } from '@/store/useGlobalStore'
import { Snapshot, useWorkspeaceSnapshot } from '@/store/useWorkspeaceSnapshot' import { Snapshot, useWorkspeaceSnapshot } from '@/store/useWorkspeaceSnapshot'
import { uniqueId } from 'lodash-es' import { uniqueId } from 'lodash-es'
import { computed } from 'vue' import { computed, ref } from 'vue'
import { ok } from 'vue3-ts-util' import { ok } from 'vue3-ts-util'
import { FileDoneOutlined, LockOutlined, PlusOutlined, QuestionCircleOutlined } from '@/icon' import { FileDoneOutlined, GithubOutlined, LockOutlined, MailOutlined, PlusOutlined, QuestionCircleOutlined } from '@/icon'
import { t } from '@/i18n' import { t } from '@/i18n'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { useImgSliStore } from '@/store/useImgSli' import { useImgSliStore } from '@/store/useImgSli'
@ -35,6 +35,12 @@ onMounted(() => {
const sync = useSettingSync() const sync = useSettingSync()
const helpModalOpen = ref(false)
const FAQ_URL = 'https://github.com/zanllp/sd-webui-infinite-image-browsing/issues/90'
const ISSUES_SEARCH_URL = 'https://github.com/zanllp/sd-webui-infinite-image-browsing/issues?q='
const NEW_ISSUE_URL = 'https://github.com/zanllp/sd-webui-infinite-image-browsing/issues/new'
const FEEDBACK_MAIL = 'mailto:qc@zanllp.cn'
const compCnMap: Partial<Record<TabPane['type'], string>> = { const compCnMap: Partial<Record<TabPane['type'], string>> = {
local: t('local'), local: t('local'),
@ -198,8 +204,7 @@ const modes = computed(() => {
</a-badge> </a-badge>
<a href="https://github.com/zanllp/sd-webui-infinite-image-browsing/wiki/Change-log" target="_blank" <a href="https://github.com/zanllp/sd-webui-infinite-image-browsing/wiki/Change-log" target="_blank"
class="quick-action">{{ $t('changlog') }}</a> class="quick-action">{{ $t('changlog') }}</a>
<a href="https://github.com/zanllp/sd-webui-infinite-image-browsing/issues/90" target="_blank" <a href="#" class="quick-action" @click.prevent="helpModalOpen = true">{{ $t('helpFeedback') }}</a>
class="quick-action">{{ $t('faq') }}</a>
<div class="quick-action" v-if="!isTauri"> <div class="quick-action" v-if="!isTauri">
{{ $t('sync') }} <a-tooltip :title="$t('syncDesc')"> {{ $t('sync') }} <a-tooltip :title="$t('syncDesc')">
<QuestionCircleOutlined/> <QuestionCircleOutlined/>
@ -211,6 +216,48 @@ const modes = computed(() => {
<a-radio-button value="dark">Dark</a-radio-button> <a-radio-button value="dark">Dark</a-radio-button>
</a-radio-group> </a-radio-group>
</div> </div>
<a-modal
v-model:visible="helpModalOpen"
:title="$t('helpFeedback')"
:footer="null"
:mask-closable="true"
width="520px"
>
<div style="display: grid; gap: 10px;">
<div style="display: flex; gap: 10px; align-items: flex-start;">
<QuestionCircleOutlined style="margin-top: 2px; opacity: 0.85;" />
<div style="flex: 1; min-width: 0;">
<div style="font-weight: 600;">{{ $t('helpFeedbackWay1') }}</div>
<div style="margin-top: 6px; display: flex; gap: 10px; flex-wrap: wrap;">
<a :href="FAQ_URL" target="_blank" rel="noopener noreferrer">{{ $t('faq') }}</a>
<a :href="ISSUES_SEARCH_URL" target="_blank" rel="noopener noreferrer">{{ $t('helpFeedbackSearchIssues') }}</a>
</div>
</div>
</div>
<div style="display: flex; gap: 10px; align-items: flex-start;">
<GithubOutlined style="margin-top: 2px; opacity: 0.85;" />
<div style="flex: 1; min-width: 0;">
<div style="font-weight: 600;">{{ $t('helpFeedbackWay2') }}</div>
<div style="margin-top: 6px;">
<a :href="NEW_ISSUE_URL" target="_blank" rel="noopener noreferrer">{{ $t('helpFeedbackNewIssue') }}</a>
</div>
</div>
</div>
<div style="display: flex; gap: 10px; align-items: flex-start;">
<MailOutlined style="margin-top: 2px; opacity: 0.85;" />
<div style="flex: 1; min-width: 0;">
<div style="font-weight: 600;">{{ $t('helpFeedbackWay3') }}</div>
<div style="margin-top: 6px;">
<a :href="FEEDBACK_MAIL">qc@zanllp.cn</a>
</div>
</div>
</div>
</div>
</a-modal>
<a-alert show-icon v-if="global.conf?.enable_access_control && !global.dontShowAgain"> <a-alert show-icon v-if="global.conf?.enable_access_control && !global.dontShowAgain">
<template #message> <template #message>
<div class="access-mode-message"> <div class="access-mode-message">

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="tag-hierarchy-graph"> <div ref="fullscreenRef" class="tag-hierarchy-graph">
<div v-if="loading" class="loading-container"> <div v-if="loading" class="loading-container">
<a-spin size="large" /> <a-spin size="large" />
<div class="loading-text">Generating hierarchical graph...</div> <div class="loading-text">{{ t('tagGraphGenerating') }}</div>
</div> </div>
<div v-else-if="error" class="error-container"> <div v-else-if="error" class="error-container">
@ -12,10 +12,51 @@
<div v-else-if="graphData" class="graph-container"> <div v-else-if="graphData" class="graph-container">
<!-- Control Panel --> <!-- Control Panel -->
<div class="control-panel"> <div class="control-panel">
<a-space> <div style="display:flex; align-items:center; gap:10px; flex-wrap:wrap;">
<a-tag>Layers: {{ graphData.layers.length }}</a-tag> <a-space>
<a-tag>Total Links: {{ graphData.stats.total_links }}</a-tag> <a-tag>{{ t('tagGraphStatLayers') }}: {{ displayGraphData?.layers?.length ?? 0 }}</a-tag>
</a-space> <a-tag>{{ t('tagGraphStatNodes') }}: {{ displayNodeCount }}</a-tag>
<a-tag>{{ t('tagGraphStatLinks') }}: {{ displayLinkCount }}</a-tag>
</a-space>
<div style="flex: 1 1 auto;"></div>
<!-- Filter Form (compact) -->
<a-space :size="8">
<a-select
v-model:value="filterLayer"
:options="layerOptions"
style="width: 140px;"
:getPopupContainer="(trigger: HTMLElement) => trigger.parentElement || trigger"
/>
<a-input
v-model:value="filterKeyword"
style="width: 200px;"
allow-clear
:placeholder="t('tagGraphFilterPlaceholder')"
@keydown.enter="applyFilterManual"
/>
<a-input-number
v-model:value="filterHops"
size="small"
:min="1"
:max="20"
:step="1"
style="width: 92px;"
:title="t('tagGraphFilterHopsTitle')"
/>
<a-button size="small" @click="applyFilterManual">{{ t('tagGraphFilterApply') }}</a-button>
<a-button size="small" @click="resetFilter">{{ t('tagGraphFilterReset') }}</a-button>
<a-button
size="small"
:title="isFullscreen ? t('exitFullscreen') : t('fullscreen')"
@click="toggleFullscreen"
>
<FullscreenExitOutlined v-if="isFullscreen" />
<FullscreenOutlined v-else />
</a-button>
</a-space>
</div>
</div> </div>
<!-- ECharts Container --> <!-- ECharts Container -->
@ -25,10 +66,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, watch, nextTick, onUnmounted } from 'vue' import { computed, ref, onMounted, watch, nextTick, onUnmounted } from 'vue'
import { getClusterTagGraph, type TagGraphReq, type TagGraphResp } from '@/api/db' import { getClusterTagGraph, type TagGraphReq, type TagGraphResp } from '@/api/db'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { t } from '@/i18n'
import { FullscreenExitOutlined, FullscreenOutlined } from '@/icon'
interface Props { interface Props {
folders: string[] folders: string[]
@ -44,9 +87,54 @@ const emit = defineEmits<{
const loading = ref(false) const loading = ref(false)
const error = ref<string>('') const error = ref<string>('')
const graphData = ref<TagGraphResp | null>(null) const graphData = ref<TagGraphResp | null>(null)
const displayGraphData = ref<TagGraphResp | null>(null)
const chartRef = ref<HTMLDivElement>() const chartRef = ref<HTMLDivElement>()
const fullscreenRef = ref<HTMLElement>()
let chartInstance: echarts.ECharts | null = null let chartInstance: echarts.ECharts | null = null
let _handleResize: (() => void) | null = null let _handleResize: (() => void) | null = null
let _docClickHandler: ((e: MouseEvent) => void) | null = null
let _fsChangeHandler: (() => void) | null = null
let _indexById: Record<string, number> = {}
type LayerOption = { label: string; value: string }
const filterLayer = ref<string>('__all__')
const filterKeyword = ref<string>('')
// Expand matched nodes by N hops to keep chains connected.
const filterHops = ref<number>(3)
// When set, filter is anchored to this exact node id (so same-layer only keeps that node itself)
const filterExactNodeId = ref<string>('')
const isFullscreen = ref(false)
const toggleFullscreen = async () => {
try {
if (document.fullscreenElement) {
await document.exitFullscreen()
return
}
const el = fullscreenRef.value
if (!el || !(el as any).requestFullscreen) {
message.warning(t('tagGraphFullscreenUnsupported'))
return
}
await (el as any).requestFullscreen()
} catch (e: any) {
message.error(e?.message || t('tagGraphFullscreenFailed'))
}
}
const layerOptions = computed<LayerOption[]>(() => {
const layers = graphData.value?.layers ?? []
const names = layers.map((l) => String((l as any).name ?? '')).filter(Boolean)
const uniq = Array.from(new Set(names))
return [{ label: t('tagGraphAllLayers'), value: '__all__' }, ...uniq.map((n) => ({ label: n, value: n }))]
})
const displayNodeCount = computed(() => {
const layers = displayGraphData.value?.layers ?? []
return layers.reduce((acc: number, l: any) => acc + (l?.nodes?.length ?? 0), 0)
})
const displayLinkCount = computed(() => (displayGraphData.value?.links?.length ?? 0))
// Layer colors (different for each layer) // Layer colors (different for each layer)
const layerColors = [ const layerColors = [
@ -72,12 +160,11 @@ const fetchGraphData = async () => {
try { try {
const req: TagGraphReq = { const req: TagGraphReq = {
folder_paths: props.folders, folder_paths: props.folders,
top_n_tags: 50,
top_n_clusters: 20,
lang: props.lang || 'en', lang: props.lang || 'en',
} }
graphData.value = await getClusterTagGraph(req) graphData.value = await getClusterTagGraph(req)
displayGraphData.value = graphData.value
} catch (err: any) { } catch (err: any) {
error.value = err.response?.data?.detail || err.message || 'Failed to load graph' error.value = err.response?.data?.detail || err.message || 'Failed to load graph'
message.error(error.value) message.error(error.value)
@ -86,8 +173,147 @@ const fetchGraphData = async () => {
} }
} }
const refreshChart = () => {
if (!chartRef.value) return
nextTick(() => {
renderChart()
})
}
const applyFilterCore = () => {
const raw = graphData.value
if (!raw) return
const keyword = (filterKeyword.value || '').trim().toLowerCase()
const layer = filterLayer.value
const hops = Math.max(1, Math.min(20, Number(filterHops.value || 1)))
// No filter -> show all
if (!filterExactNodeId.value && !keyword && (layer === '__all__' || !layer)) {
displayGraphData.value = raw
refreshChart()
return
}
// Flatten nodes with layer context
const nodeById = new Map<string, { id: string; label: string; layerName: string; layerLevel: number; metadata?: any }>()
for (const l of raw.layers as any[]) {
const layerName = String(l?.name ?? '')
const layerLevel = Number(l?.level ?? 0)
for (const n of (l?.nodes ?? []) as any[]) {
const id = String(n?.id ?? '')
if (!id) continue
nodeById.set(id, { id, label: String(n?.label ?? ''), layerName, layerLevel, metadata: n?.metadata })
}
}
const matched = new Set<string>()
// 1) match set
if (filterExactNodeId.value) {
if (nodeById.has(filterExactNodeId.value)) {
matched.add(filterExactNodeId.value)
}
} else {
// manual mode: layer + keyword contains
for (const [id, n] of nodeById) {
if (layer && layer !== '__all__' && n.layerName !== layer) continue
if (keyword) {
const hay = `${n.label} ${id}`.toLowerCase()
if (!hay.includes(keyword)) continue
}
matched.add(id)
}
}
const links = raw.links as any[]
// 2) include matched + N-hop neighbors (both directions)
const adj = new Map<string, Set<string>>()
const addEdge = (a: string, b: string) => {
if (!a || !b) return
if (!adj.has(a)) adj.set(a, new Set())
adj.get(a)!.add(b)
}
for (const lk of links) {
const s = String(lk?.source ?? '')
const t2 = String(lk?.target ?? '')
if (!s || !t2) continue
addEdge(s, t2)
addEdge(t2, s)
}
const include = new Set<string>()
const q: Array<{ id: string; d: number }> = []
for (const id of matched) {
include.add(id)
q.push({ id, d: 0 })
}
while (q.length) {
const cur = q.shift()!
if (cur.d >= hops) continue
const ns = adj.get(cur.id)
if (!ns) continue
for (const nxt of ns) {
if (!include.has(nxt)) {
include.add(nxt)
q.push({ id: nxt, d: cur.d + 1 })
}
}
}
// 3) filter layers/nodes
const filteredLayers: any[] = []
for (const l of raw.layers as any[]) {
const nodes = (l?.nodes ?? []).filter((n: any) => include.has(String(n?.id ?? '')))
if (nodes.length) {
filteredLayers.push({ ...l, nodes })
}
}
// 4) filter links among included nodes
const filteredLinks = links.filter((lk) => include.has(String(lk?.source ?? '')) && include.has(String(lk?.target ?? '')))
displayGraphData.value = {
layers: filteredLayers,
links: filteredLinks,
stats: {
...(raw as any).stats,
total_links: filteredLinks.length
}
} as any
refreshChart()
}
const applyFilterManual = () => {
// switching to manual mode clears exact-anchor
filterExactNodeId.value = ''
applyFilterCore()
}
const applyFilterByNode = (nodeId: string, layerName: string, nodeName: string, nodeType: string) => {
// Keep UI in sync, but anchor by exact id to avoid matching multiple same-layer nodes
filterLayer.value = layerName || '__all__'
filterKeyword.value = nodeName || ''
filterExactNodeId.value = nodeId
// Suggested hops to reach Abstract-2 from different starting layers:
// cluster -> tag -> abstract-1 -> abstract-2 : 3 hops
// tag -> abstract-1 -> abstract-2 : 2 hops
// abstract-1 -> abstract-2 : 1 hop
const suggested = nodeType === 'cluster' ? 3 : (nodeType === 'tag' ? 2 : (nodeType === 'abstract' ? 1 : 2))
filterHops.value = Math.max(Number(filterHops.value || 1), suggested)
applyFilterCore()
}
const resetFilter = () => {
filterLayer.value = '__all__'
filterKeyword.value = ''
filterHops.value = 3
filterExactNodeId.value = ''
if (graphData.value) displayGraphData.value = graphData.value
refreshChart()
}
const renderChart = () => { const renderChart = () => {
if (!graphData.value || !chartRef.value) { if (!displayGraphData.value || !chartRef.value) {
return return
} }
@ -98,14 +324,15 @@ const renderChart = () => {
chartInstance = echarts.init(chartRef.value) chartInstance = echarts.init(chartRef.value)
const layers = graphData.value.layers const layers = displayGraphData.value.layers
// Reverse to show abstract on left // Reverse to show abstract on left
const reversedLayers = [...layers].reverse() const reversedLayers = [...layers].reverse()
// Build nodes with scattered positions for better visualization // Build nodes with scattered positions for better visualization
const nodes: any[] = [] const nodes: any[] = []
const layerSpacing = 1200 / (reversedLayers.length + 1) // Increased from 1000 to 1200 const layerSpacing = 1500 / (reversedLayers.length + 1) // Increased from 1000 to 1200
const horizontalRange = 150 // Horizontal scatter range const horizontalRange = 200 // Horizontal scatter range
_indexById = {}
reversedLayers.forEach((layer, layerIdx) => { reversedLayers.forEach((layer, layerIdx) => {
const baseX = layerSpacing * (layerIdx + 1) const baseX = layerSpacing * (layerIdx + 1)
@ -152,11 +379,13 @@ const renderChart = () => {
metadata: node.metadata, metadata: node.metadata,
layerName: layer.name, layerName: layer.name,
}) })
_indexById[node.id] = nodes.length - 1
}) })
}) })
// Build links // Build links
const links = graphData.value.links.map(link => ({ const links = displayGraphData.value.links.map(link => ({
source: link.source, source: link.source,
target: link.target, target: link.target,
value: link.weight, value: link.weight,
@ -174,15 +403,63 @@ const renderChart = () => {
const option: echarts.EChartsOption = { const option: echarts.EChartsOption = {
tooltip: { tooltip: {
renderMode: 'html',
// In fullscreen mode, only the fullscreen element subtree is rendered.
// If tooltip is appended to document.body, it will not be visible.
appendToBody: false,
className: 'iib-tg-tooltip',
backgroundColor: 'rgba(15, 23, 42, 0.92)',
borderColor: 'rgba(255,255,255,0.14)',
borderWidth: 1,
padding: [10, 12],
textStyle: {
color: '#fff'
},
extraCssText: 'border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,0.35); z-index: 9999;',
triggerOn: 'none',
enterable: true,
formatter: (params: any) => { formatter: (params: any) => {
if (params.dataType === 'node') { if (params.dataType === 'node') {
const node = params.data const node = params.data
let html = `<strong>${params.name}</strong><br/>` const nodeId = String(node.id || '')
html += `Layer: ${node.layerName}<br/>` const meta = node.metadata || {}
if (node.metadata?.image_count) { const imgCount = Number(meta.image_count ?? node.value ?? 0)
html += `Images: ${node.metadata.image_count}` const clusterCount = meta.cluster_count != null ? Number(meta.cluster_count) : null
} const level = meta.level != null ? Number(meta.level) : null
return html const type = String(meta.type || '')
const chips: string[] = []
if (!Number.isNaN(imgCount) && imgCount > 0) chips.push(`🖼️ ${imgCount}`)
if (clusterCount != null && !Number.isNaN(clusterCount)) chips.push(`🧩 ${clusterCount}`)
if (level != null && !Number.isNaN(level)) chips.push(`🏷️ L${level}`)
const canSearch = type === 'tag'
const canFilter = type === 'tag' || type === 'abstract' || type === 'cluster'
const canOpenCluster = type === 'cluster'
const actionBtns = [
canSearch
? `<button data-action="search" data-nodeid="${nodeId}" style="border:1px solid rgba(255,255,255,0.35); background: rgba(24,144,255,0.18); color:#fff; padding:4px 10px; border-radius:999px; cursor:pointer;">${t('search')}</button>`
: '',
canFilter
? `<button data-action="filter" data-nodeid="${nodeId}" style="border:1px solid rgba(255,255,255,0.30); background: rgba(255,255,255,0.10); color:#fff; padding:4px 10px; border-radius:999px; cursor:pointer;">${t('tagGraphTooltipFilter')}</button>`
: '',
canOpenCluster
? `<button data-action="openCluster" data-nodeid="${nodeId}" style="border:1px solid rgba(255,255,255,0.35); background: rgba(255,255,255,0.12); color:#fff; padding:4px 10px; border-radius:999px; cursor:pointer;">${t('tagGraphTooltipOpenCluster')}</button>`
: '',
`<button data-action="close" data-nodeid="${nodeId}" style="border:1px solid rgba(255,255,255,0.25); background: rgba(255,255,255,0.10); color:#fff; padding:4px 10px; border-radius:999px; cursor:pointer;">${t('close')}</button>`
].filter(Boolean).join('')
return `
<div class="iib-tg-tip" data-nodeid="${nodeId}" style="min-width: 180px;">
<div style="font-weight: 700; margin-bottom: 6px; color:#fff;">${params.name}</div>
<div style="display:flex; gap:10px; flex-wrap:wrap; font-size:12px; opacity:.9; color:#fff;">
${chips.map((c) => `<span>${c}</span>`).join('')}
</div>
<div style="margin-top: 10px; display:flex; gap:8px; flex-wrap:wrap;">
${actionBtns}
</div>
</div>
`
} }
return '' return ''
} }
@ -208,6 +485,17 @@ const renderChart = () => {
max: 5 max: 5
}, },
draggable: false, draggable: false,
blur: {
itemStyle: {
opacity: 0.15
},
lineStyle: {
opacity: 0.08
},
label: {
opacity: 0.25
}
},
label: { label: {
show: true, show: true,
position: 'inside' position: 'inside'
@ -228,29 +516,101 @@ const renderChart = () => {
chartInstance.setOption(option) chartInstance.setOption(option)
const hideTipOnly = () => {
if (!chartInstance) return
chartInstance.dispatchAction({ type: 'hideTip' })
}
// Handle click events // Handle click events
chartInstance.on('click', (params: any) => { chartInstance.on('click', (params: any) => {
if (params.dataType === 'node') { if (params.dataType === 'node') {
const node = params.data const node = params.data
if (node.metadata?.type === 'tag') { if (node.metadata?.type === 'tag') {
emit('searchTag', params.name) // Show tooltip; search is triggered from tooltip button
message.info(`Searching for tag: ${params.name}`) const idx = _indexById[String(node.id || '')]
if (idx != null) chartInstance?.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: idx })
} else if (node.metadata?.type === 'cluster') { } else if (node.metadata?.type === 'cluster') {
// Open cluster directly with bound images // Show tooltip; open is triggered from tooltip button
if (node.metadata.paths && node.metadata.paths.length > 0) { const idx = _indexById[String(node.id || '')]
emit('openCluster', { if (idx != null) chartInstance?.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: idx })
title: params.name, } else if (node.metadata?.type === 'abstract') {
paths: node.metadata.paths, const idx = _indexById[String(node.id || '')]
size: node.metadata.image_count || node.metadata.paths.length if (idx != null) chartInstance?.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: idx })
})
} else {
message.warning('No images found in this cluster')
}
} else { } else {
message.info(`Abstract category: ${params.name}`) message.info(`Abstract category: ${params.name}`)
} }
} }
}) })
// Click blank area: hide tooltip
chartInstance.getZr().on('click', (e: any) => {
if (!e?.target) {
hideTipOnly()
}
})
// Tooltip action buttons (search / close)
if (_docClickHandler) {
document.removeEventListener('click', _docClickHandler, true)
_docClickHandler = null
}
_docClickHandler = (ev: MouseEvent) => {
const target = ev.target as HTMLElement | null
if (!target) return
// Click on tooltip button
const btn = target.closest?.('button[data-action]') as HTMLElement | null
if (btn) {
const action = btn.getAttribute('data-action') || ''
const nodeId = btn.getAttribute('data-nodeid') || ''
const idx = _indexById[nodeId]
if (action === 'search' && idx != null) {
// Only tags have search button
const nodeName = (nodes[idx] && nodes[idx].name) || ''
if (nodeName) {
emit('searchTag', nodeName)
message.info(`${t('search')}: ${nodeName}`)
}
hideTipOnly()
} else if (action === 'filter' && idx != null) {
// Filter by this node (layer + keyword), keep 1-hop neighbors
const layerName = (nodes[idx] && nodes[idx].layerName) || '__all__'
const nodeName = (nodes[idx] && nodes[idx].name) || ''
const targetNodeId = String((nodes[idx] && nodes[idx].id) || nodeId)
const nodeType = String((nodes[idx] && nodes[idx].metadata && nodes[idx].metadata.type) || '')
filterLayer.value = layerName || '__all__'
filterKeyword.value = nodeName
applyFilterByNode(targetNodeId, String(layerName || '__all__'), String(nodeName || ''), nodeType)
// best-effort hide tip after applying
hideTipOnly()
} else if (action === 'openCluster' && idx != null) {
const meta = (nodes[idx] && nodes[idx].metadata) || {}
const paths = (meta.paths || []) as string[]
const title = (nodes[idx] && nodes[idx].name) || ''
const size = Number(meta.image_count || paths.length || 0)
if (paths && paths.length) {
emit('openCluster', { title, paths, size })
} else {
message.warning('No images found in this cluster')
}
hideTipOnly()
} else if (action === 'close') {
hideTipOnly()
}
ev.preventDefault()
ev.stopPropagation()
return
}
// Click elsewhere (outside chart and tooltip): hide tooltip
const tip = target.closest?.('.iib-tg-tip')
if (tip) return
const inChart = chartRef.value?.contains(target) ?? false
if (!inChart) {
hideTipOnly()
}
}
document.addEventListener('click', _docClickHandler, true)
} }
// Watch for folder changes // Watch for folder changes
@ -264,9 +624,9 @@ watch(
// Watch for graphData and chartRef to trigger rendering // Watch for graphData and chartRef to trigger rendering
watch( watch(
[graphData, chartRef], [displayGraphData, chartRef],
() => { () => {
if (graphData.value && chartRef.value) { if (displayGraphData.value && chartRef.value) {
nextTick(() => { nextTick(() => {
renderChart() renderChart()
}) })
@ -282,6 +642,14 @@ onMounted(() => {
} }
} }
window.addEventListener('resize', _handleResize) window.addEventListener('resize', _handleResize)
_fsChangeHandler = () => {
isFullscreen.value = !!document.fullscreenElement
nextTick(() => {
chartInstance?.resize()
})
}
document.addEventListener('fullscreenchange', _fsChangeHandler)
}) })
onUnmounted(() => { onUnmounted(() => {
@ -289,6 +657,14 @@ onUnmounted(() => {
window.removeEventListener('resize', _handleResize) window.removeEventListener('resize', _handleResize)
_handleResize = null _handleResize = null
} }
if (_fsChangeHandler) {
document.removeEventListener('fullscreenchange', _fsChangeHandler)
_fsChangeHandler = null
}
if (_docClickHandler) {
document.removeEventListener('click', _docClickHandler, true)
_docClickHandler = null
}
if (chartInstance) { if (chartInstance) {
chartInstance.dispose() chartInstance.dispose()
} }