diff --git a/app/__pycache__/config.cpython-312.pyc b/app/__pycache__/config.cpython-312.pyc index 4b73e69..db8fad9 100644 Binary files a/app/__pycache__/config.cpython-312.pyc and b/app/__pycache__/config.cpython-312.pyc differ diff --git a/app/assets/convert.js b/app/assets/convert.js index 86e8bd6..c7195f2 100644 --- a/app/assets/convert.js +++ b/app/assets/convert.js @@ -1 +1 @@ -import { d as A, o as H, a as n, c as o, b as j, B as z, e as s, F as w, r as F, t as r, f as _, n as E, w as K, u as M, x as q, g as u, h as T, y as J, i as k, E as i, j as L, z as O, A as G, C as Q, _ as W, q as X, s as Y } from "./pywebview-DdV1XQSM.js"; const Z = { class: "page-shell module-page" }, ee = { class: "main-content" }, se = { class: "left-panel" }, te = { class: "upload-zone" }, ae = { class: "selected-files clean-placeholder" }, le = { key: 0, class: "more-line" }, ne = { key: 1 }, oe = { class: "option-group" }, ie = ["value"], re = { class: "template-item-content" }, ce = { class: "label" }, ue = { key: 0, class: "template-tag" }, de = { key: 1, class: "template-tag muted" }, ve = { key: 2, class: "template-tag custom" }, pe = { class: "desc" }, _e = { key: 0, class: "empty-option" }, fe = { class: "option-group" }, me = { class: "radio-item active" }, he = { class: "desc" }, ye = { class: "run-row" }, ge = ["disabled"], be = { class: "loading-msg" }, we = { class: "right-panel" }, ke = { class: "task-list-wrap" }, Ce = { class: "clean-result-summary" }, xe = { class: "summary-card" }, Fe = { class: "summary-card" }, Pe = { class: "summary-card" }, Ee = { class: "result-list-wrap" }, Te = { key: 0, class: "empty-tasks" }, Ie = { key: 1, class: "task-list clean-result-list" }, Be = { class: "left" }, Ne = ["title"], $e = { key: 0, class: "files" }, De = { key: 1, class: "files" }, Re = { class: "task-right" }, Se = ["onClick"], Ue = ["onClick"], Ve = A({ __name: "BrandConvertTab", setup(He) { const v = u([]), g = u(""), f = u([]), m = u(!1), b = u([]), h = u({ total: 0, successCount: 0, failedCount: 0, items: [] }), d = u([]), c = u(""), C = T(() => v.value.slice(0, 8)), I = T(() => d.value.find(a => a.id === c.value) || null); async function P(a) { const e = k(); if (!e?.upload_file_to_java) throw new Error("当前桌面端未提供文件上传桥接能力"); const t = []; for (const l of a) { const p = typeof l == "string" ? l : l.absolutePath, V = typeof l == "string" ? void 0 : l.relativePath, y = await e.upload_file_to_java(p, V); if (!y?.success || !y.data) throw new Error(y?.error || y?.message || `上传失败:${p}`); t.push(y.data) } return t } async function B(a) { const e = await J(); d.value = e || []; const t = d.value.find(p => p.id === c.value); if (t) { c.value = t.id; return } const l = d.value.find(p => p.isDefault); if (l) { c.value = l.id; return } c.value = d.value[0]?.id || "" } async function N(a, e) { v.value = a, g.value = "", f.value = await P(a), i.success(e) } async function $() { const a = k(); if (!a?.select_brand_xlsx_files) { i.warning("当前环境不支持文件选择,请在本机客户端中打开"); return } try { const e = await a.select_brand_xlsx_files(); if (!e?.length) return; await N(e, `已选择 ${e.length} 个待转换文件`) } catch (e) { i.error(e instanceof Error ? e.message : "选择失败") } } async function D() { const a = k(); if (!a?.select_brand_folder) { i.warning("当前环境不支持文件夹选择,请在本机客户端中打开"); return } try { const e = await a.select_brand_folder(); if (!e) return; g.value = e.split(/[/\\]/).filter(Boolean).pop() || ""; const t = await L(e); if (t.success && t.items?.length) { v.value = t.items.map(l => l.relativePath), f.value = await P(t.items), i.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`); return } i.warning(t.error || "该文件夹下没有 xlsx 文件") } catch (e) { i.error(e instanceof Error ? e.message : "选择失败") } } async function R() { if (!f.value.length) { i.warning("请先选择待转换 Excel 文件或文件夹"); return } if (!c.value) { i.warning("请先选择模板"); return } try { m.value = !0; const a = await O({ files: f.value.map(e => ({ fileKey: e.fileKey, originalFilename: e.originalFilename, relativePath: e.relativePath })), templateId: c.value, archiveName: f.value.some(e => !!e.relativePath) && g.value ? g.value : void 0 }); h.value = a, b.value = a.items || [], await x(), i.success("格式转换完成") } catch (a) { i.error(a instanceof Error ? a.message : "格式转换失败") } finally { m.value = !1 } } async function x() { try { const a = await G(); b.value = a.items || [], h.value = { total: a.items?.length || 0, successCount: a.items?.filter(e => e.success).length || 0, failedCount: a.items?.filter(e => !e.success).length || 0, items: a.items || [] } } catch { } } async function S(a) { try { await Q(a), await x(), i.success("已删除") } catch (e) { i.error(e instanceof Error ? e.message : "删除失败") } } async function U(a) { const e = k(); if (!a.downloadUrl) { i.warning("当前结果没有下载地址"); return } const t = a.outputFilename || `${new Date().toISOString().slice(0, 10).replace(/-/g, "")}.txt`; if (e?.save_file_from_url) { const l = await e.save_file_from_url(a.downloadUrl, t); l.success ? i.success(`已保存:${l.path || t}`) : l.error && l.error !== "用户取消" && i.error(l.error); return } window.open(a.downloadUrl, "_blank") } return H(() => { B().catch(() => { }), x().catch(() => { }) }), (a, e) => (n(), o("div", Z, [j(z, { active: "convert" }), s("div", ee, [s("aside", se, [e[5] || (e[5] = s("div", { class: "section-title" }, "选择文件", -1)), s("div", te, [e[1] || (e[1] = s("div", { class: "hint" }, "选择需要转换的 Excel 文件或文件夹,将按所选模板生成 txt 文件。", -1)), s("div", { class: "btns" }, [s("button", { type: "button", class: "opt-btn", onClick: $ }, "选择 Excel 文件"), s("button", { type: "button", class: "opt-btn", onClick: D }, "选择文件夹")]), s("div", ae, [v.value.length ? (n(), o(w, { key: 0 }, [(n(!0), o(w, null, F(C.value, t => (n(), o("span", { key: t }, r(t), 1))), 128)), v.value.length > C.value.length ? (n(), o("span", le, " 还有 " + r(v.value.length - C.value.length) + " 个文件未展开显示 ", 1)) : _("", !0)], 64)) : (n(), o("span", ne, "暂未选择待转换文件"))])]), e[6] || (e[6] = s("div", { class: "section-title" }, "模板选择", -1)), s("div", oe, [(n(!0), o(w, null, F(d.value, t => (n(), o("label", { key: t.id, class: E(["radio-item", { active: c.value === t.id }]) }, [K(s("input", { "onUpdate:modelValue": e[0] || (e[0] = l => c.value = l), type: "radio", value: t.id, name: "convert-template" }, null, 8, ie), [[M, c.value]]), s("div", re, [s("div", null, [s("span", ce, [q(r(t.templateName) + " ", 1), t.isDefault ? (n(), o("span", ue, "默认")) : t.builtIn ? (n(), o("span", de, "内置")) : (n(), o("span", ve, "自定义"))]), s("div", pe, "输出文件:" + r(t.outputFilename), 1)])])], 2))), 128)), d.value.length ? _("", !0) : (n(), o("div", _e, "暂无可用模板"))]), e[7] || (e[7] = s("div", { class: "section-title" }, "转换说明", -1)), s("div", fe, [s("label", me, [e[3] || (e[3] = s("input", { type: "checkbox", checked: "", disabled: "" }, null, -1)), s("div", null, [e[2] || (e[2] = s("span", { class: "label" }, "按当前模板输出", -1)), s("div", he, "当前模板:" + r(I.value?.templateName || "未加载模板"), 1)])]), e[4] || (e[4] = s("label", { class: "radio-item active" }, [s("input", { type: "checkbox", checked: "", disabled: "" }), s("div", null, [s("span", { class: "label" }, "SKU 使用雪花ID-序号"), s("div", { class: "desc" }, "例如 1773816146796-1")])], -1))]), s("div", ye, [s("button", { type: "button", class: "btn-run", disabled: m.value, onClick: R }, r(m.value ? "转换中..." : "开始转换"), 9, ge), s("span", be, r(m.value ? "正在生成并上传结果,请稍候…" : "选择文件后即可执行格式转换,结果会显示在右侧供下载"), 1)])]), s("section", we, [e[12] || (e[12] = s("div", { class: "panel-header" }, "转换结果", -1)), s("div", ke, [s("div", Ce, [s("div", xe, [e[8] || (e[8] = s("span", { class: "summary-label" }, "已处理文件", -1)), s("strong", null, r(h.value.total), 1)]), s("div", Fe, [e[9] || (e[9] = s("span", { class: "summary-label" }, "成功结果", -1)), s("strong", null, r(h.value.successCount), 1)]), s("div", Pe, [e[10] || (e[10] = s("span", { class: "summary-label" }, "失败文件", -1)), s("strong", null, r(h.value.failedCount), 1)])]), s("div", Ee, [e[11] || (e[11] = s("div", { class: "result-list-header" }, [s("span", null, "生成的结果压缩包列表")], -1)), b.value.length === 0 ? (n(), o("div", Te, " 暂无转换结果,完成格式转换后会在这里展示结果压缩包 ")) : (n(), o("ul", Ie, [(n(!0), o(w, null, F(b.value, t => (n(), o("li", { key: `${t.resultId || t.outputFilename || t.sourceFilename}`, class: "task-item" }, [s("div", Be, [s("span", { class: "id", title: t.sourceFilename }, r(t.sourceFilename || "-"), 9, Ne), t.outputFilename ? (n(), o("div", $e, "压缩包文件:" + r(t.outputFilename), 1)) : _("", !0), t.error ? (n(), o("div", De, "错误信息:" + r(t.error), 1)) : _("", !0)]), s("div", Re, [s("span", { class: E(["status", t.success ? "success" : "failed"]) }, r(t.success ? "已完成" : "失败"), 3), t.success && t.downloadUrl ? (n(), o("button", { key: 0, type: "button", class: "download", onClick: l => U(t) }, " 下载压缩包 ", 8, Se)) : _("", !0), t.resultId ? (n(), o("button", { key: 1, type: "button", class: "btn-delete", onClick: l => S(t.resultId) }, " 删除 ", 8, Ue)) : _("", !0)])]))), 128))]))])])])])])) } }), Ae = W(Ve, [["__scopeId", "data-v-89690cc3"]]); X(Ae).use(Y).mount("#app"); +import{d as A,o as H,a as n,c as o,b as j,B as z,e as s,F as w,r as F,t as r,f as _,n as E,w as K,u as M,x as q,g as u,h as T,y as J,i as k,E as i,j as L,z as O,A as G,C as Q,_ as W,q as X,s as Y}from"./pywebview-p4QBqp2b.js";const Z={class:"page-shell module-page"},ee={class:"main-content"},se={class:"left-panel"},te={class:"upload-zone"},ae={class:"selected-files clean-placeholder"},le={key:0,class:"more-line"},ne={key:1},oe={class:"option-group"},ie=["value"],re={class:"template-item-content"},ce={class:"label"},ue={key:0,class:"template-tag"},de={key:1,class:"template-tag muted"},ve={key:2,class:"template-tag custom"},pe={class:"desc"},_e={key:0,class:"empty-option"},fe={class:"option-group"},me={class:"radio-item active"},he={class:"desc"},ye={class:"run-row"},ge=["disabled"],be={class:"loading-msg"},we={class:"right-panel"},ke={class:"task-list-wrap"},Ce={class:"clean-result-summary"},xe={class:"summary-card"},Fe={class:"summary-card"},Pe={class:"summary-card"},Ee={class:"result-list-wrap"},Te={key:0,class:"empty-tasks"},Ie={key:1,class:"task-list clean-result-list"},Be={class:"left"},Ne=["title"],$e={key:0,class:"files"},De={key:1,class:"files"},Re={class:"task-right"},Se=["onClick"],Ue=["onClick"],Ve=A({__name:"BrandConvertTab",setup(He){const v=u([]),g=u(""),f=u([]),m=u(!1),b=u([]),h=u({total:0,successCount:0,failedCount:0,items:[]}),d=u([]),c=u(""),C=T(()=>v.value.slice(0,8)),I=T(()=>d.value.find(a=>a.id===c.value)||null);async function P(a){const e=k();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const l of a){const p=typeof l=="string"?l:l.absolutePath,V=typeof l=="string"?void 0:l.relativePath,y=await e.upload_file_to_java(p,V);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${p}`);t.push(y.data)}return t}async function B(a){const e=await J();d.value=e||[];const t=d.value.find(p=>p.id===c.value);if(t){c.value=t.id;return}const l=d.value.find(p=>p.isDefault);if(l){c.value=l.id;return}c.value=d.value[0]?.id||""}async function N(a,e){v.value=a,g.value="",f.value=await P(a),i.success(e)}async function $(){const a=k();if(!a?.select_brand_xlsx_files){i.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await a.select_brand_xlsx_files();if(!e?.length)return;await N(e,`已选择 ${e.length} 个待转换文件`)}catch(e){i.error(e instanceof Error?e.message:"选择失败")}}async function D(){const a=k();if(!a?.select_brand_folder){i.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await a.select_brand_folder();if(!e)return;g.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await L(e);if(t.success&&t.items?.length){v.value=t.items.map(l=>l.relativePath),f.value=await P(t.items),i.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}i.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){i.error(e instanceof Error?e.message:"选择失败")}}async function R(){if(!f.value.length){i.warning("请先选择待转换 Excel 文件或文件夹");return}if(!c.value){i.warning("请先选择模板");return}try{m.value=!0;const a=await O({files:f.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),templateId:c.value,archiveName:f.value.some(e=>!!e.relativePath)&&g.value?g.value:void 0});h.value=a,b.value=a.items||[],await x(),i.success("格式转换完成")}catch(a){i.error(a instanceof Error?a.message:"格式转换失败")}finally{m.value=!1}}async function x(){try{const a=await G();b.value=a.items||[],h.value={total:a.items?.length||0,successCount:a.items?.filter(e=>e.success).length||0,failedCount:a.items?.filter(e=>!e.success).length||0,items:a.items||[]}}catch{}}async function S(a){try{await Q(a),await x(),i.success("已删除")}catch(e){i.error(e instanceof Error?e.message:"删除失败")}}async function U(a){const e=k();if(!a.downloadUrl){i.warning("当前结果没有下载地址");return}const t=a.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}.txt`;if(e?.save_file_from_url){const l=await e.save_file_from_url(a.downloadUrl,t);l.success?i.success(`已保存:${l.path||t}`):l.error&&l.error!=="用户取消"&&i.error(l.error);return}window.open(a.downloadUrl,"_blank")}return H(()=>{B().catch(()=>{}),x().catch(()=>{})}),(a,e)=>(n(),o("div",Z,[j(z,{active:"convert"}),s("div",ee,[s("aside",se,[e[5]||(e[5]=s("div",{class:"section-title"},"选择文件",-1)),s("div",te,[e[1]||(e[1]=s("div",{class:"hint"},"选择需要转换的 Excel 文件或文件夹,将按所选模板生成 txt 文件。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:$},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:D},"选择文件夹")]),s("div",ae,[v.value.length?(n(),o(w,{key:0},[(n(!0),o(w,null,F(C.value,t=>(n(),o("span",{key:t},r(t),1))),128)),v.value.length>C.value.length?(n(),o("span",le," 还有 "+r(v.value.length-C.value.length)+" 个文件未展开显示 ",1)):_("",!0)],64)):(n(),o("span",ne,"暂未选择待转换文件"))])]),e[6]||(e[6]=s("div",{class:"section-title"},"模板选择",-1)),s("div",oe,[(n(!0),o(w,null,F(d.value,t=>(n(),o("label",{key:t.id,class:E(["radio-item",{active:c.value===t.id}])},[K(s("input",{"onUpdate:modelValue":e[0]||(e[0]=l=>c.value=l),type:"radio",value:t.id,name:"convert-template"},null,8,ie),[[M,c.value]]),s("div",re,[s("div",null,[s("span",ce,[q(r(t.templateName)+" ",1),t.isDefault?(n(),o("span",ue,"默认")):t.builtIn?(n(),o("span",de,"内置")):(n(),o("span",ve,"自定义"))]),s("div",pe,"输出文件:"+r(t.outputFilename),1)])])],2))),128)),d.value.length?_("",!0):(n(),o("div",_e,"暂无可用模板"))]),e[7]||(e[7]=s("div",{class:"section-title"},"转换说明",-1)),s("div",fe,[s("label",me,[e[3]||(e[3]=s("input",{type:"checkbox",checked:"",disabled:""},null,-1)),s("div",null,[e[2]||(e[2]=s("span",{class:"label"},"按当前模板输出",-1)),s("div",he,"当前模板:"+r(I.value?.templateName||"未加载模板"),1)])]),e[4]||(e[4]=s("label",{class:"radio-item active"},[s("input",{type:"checkbox",checked:"",disabled:""}),s("div",null,[s("span",{class:"label"},"SKU 使用雪花ID-序号"),s("div",{class:"desc"},"例如 1773816146796-1")])],-1))]),s("div",ye,[s("button",{type:"button",class:"btn-run",disabled:m.value,onClick:R},r(m.value?"转换中...":"开始转换"),9,ge),s("span",be,r(m.value?"正在生成并上传结果,请稍候…":"选择文件后即可执行格式转换,结果会显示在右侧供下载"),1)])]),s("section",we,[e[12]||(e[12]=s("div",{class:"panel-header"},"转换结果",-1)),s("div",ke,[s("div",Ce,[s("div",xe,[e[8]||(e[8]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,r(h.value.total),1)]),s("div",Fe,[e[9]||(e[9]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,r(h.value.successCount),1)]),s("div",Pe,[e[10]||(e[10]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,r(h.value.failedCount),1)])]),s("div",Ee,[e[11]||(e[11]=s("div",{class:"result-list-header"},[s("span",null,"生成的结果压缩包列表")],-1)),b.value.length===0?(n(),o("div",Te," 暂无转换结果,完成格式转换后会在这里展示结果压缩包 ")):(n(),o("ul",Ie,[(n(!0),o(w,null,F(b.value,t=>(n(),o("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",Be,[s("span",{class:"id",title:t.sourceFilename},r(t.sourceFilename||"-"),9,Ne),t.outputFilename?(n(),o("div",$e,"压缩包文件:"+r(t.outputFilename),1)):_("",!0),t.error?(n(),o("div",De,"错误信息:"+r(t.error),1)):_("",!0)]),s("div",Re,[s("span",{class:E(["status",t.success?"success":"failed"])},r(t.success?"已完成":"失败"),3),t.success&&t.downloadUrl?(n(),o("button",{key:0,type:"button",class:"download",onClick:l=>U(t)}," 下载压缩包 ",8,Se)):_("",!0),t.resultId?(n(),o("button",{key:1,type:"button",class:"btn-delete",onClick:l=>S(t.resultId)}," 删除 ",8,Ue)):_("",!0)])]))),128))]))])])])])]))}}),Ae=W(Ve,[["__scopeId","data-v-89690cc3"]]);X(Ae).use(Y).mount("#app"); diff --git a/app/assets/dedupe.js b/app/assets/dedupe.js index eeabceb..2206740 100644 --- a/app/assets/dedupe.js +++ b/app/assets/dedupe.js @@ -1 +1 @@ -import { d as z, o as W, a as n, c as o, b as q, B as J, e as s, F as C, r as F, t as i, f as b, n as I, w as P, v as B, g as u, h as L, i as x, E as r, j as O, k as G, l as Q, m as X, p as Y, _ as Z, q as ee, s as se } from "./pywebview-DdV1XQSM.js"; const te = { class: "page-shell module-page" }, le = { class: "main-content" }, ae = { class: "left-panel" }, ne = { class: "upload-zone" }, oe = { class: "selected-files clean-placeholder" }, re = { key: 0, class: "more-line" }, ie = { key: 1 }, ue = { class: "option-group column-option-group" }, ce = { class: "column-toolbar" }, de = { class: "column-count" }, ve = { key: 0, class: "column-grid" }, pe = ["value"], fe = { key: 1, class: "empty-column-state" }, _e = { class: "option-group" }, me = { class: "run-row" }, he = ["disabled"], ge = { class: "loading-msg" }, ye = { class: "right-panel" }, be = { class: "task-list-wrap" }, we = { class: "clean-result-summary" }, ke = { class: "summary-card" }, Ce = { class: "summary-card" }, Ie = { class: "summary-card" }, xe = { class: "result-list-wrap" }, Ee = { key: 0, class: "empty-tasks" }, De = { key: 1, class: "task-list clean-result-list" }, Fe = { class: "left" }, Pe = ["title"], Be = { key: 0, class: "files" }, Se = { key: 1, class: "files" }, Ue = { class: "task-right" }, Ne = ["onClick"], $e = ["onClick"], Ae = z({ __name: "BrandDedupeTab", setup(Ke) { const p = u([]), c = u([]), f = u([]), w = u(""), d = u([]), S = u(!1), _ = u(!0), m = u(!0), h = u(!1), k = u([]), g = u({ total: 0, successCount: 0, failedCount: 0, items: [] }), E = L(() => f.value.slice(0, 8)); function $() { c.value = [...p.value] } function A() { c.value = [] } async function U(l) { const e = x(); if (!e?.upload_file_to_java) throw new Error("当前桌面端未提供文件上传桥接能力"); const t = []; for (const a of l) { const v = typeof a == "string" ? a : a.absolutePath, j = typeof a == "string" ? void 0 : a.relativePath, y = await e.upload_file_to_java(v, j); if (!y?.success || !y.data) throw new Error(y?.error || y?.message || `上传失败:${v}`); t.push(y.data) } return t } async function N(l) { const e = await Y(l); if (!e.headers?.length) { r.error("读取 Excel 表头失败"), p.value = [], c.value = []; return } const t = ["id", "ASIN", "国家", "价格", "卖家名称"], a = [...t.filter(v => e.headers?.includes(v)), ...(e.headers || []).filter(v => !t.includes(v))]; p.value = a, c.value = t.filter(v => a.includes(v)) } async function H(l, e) { f.value = l, w.value = "", d.value = await U(l), d.value.length > 0 && await N(d.value[0].fileKey), r.success(e) } async function K() { const l = x(); if (!l?.select_brand_xlsx_files) { r.warning("当前环境不支持文件选择,请在本机客户端中打开"); return } try { const e = await l.select_brand_xlsx_files(); if (!e?.length) return; await H(e, `已选择 ${e.length} 个待清洗文件`) } catch (e) { r.error(e instanceof Error ? e.message : "选择失败") } } async function R() { const l = x(); if (!l?.select_brand_folder) { r.warning("当前环境不支持文件夹选择,请在本机客户端中打开"); return } try { const e = await l.select_brand_folder(); if (!e) return; w.value = e.split(/[/\\]/).filter(Boolean).pop() || ""; const t = await O(e); if (t.success && t.items?.length) { f.value = t.items.map(a => a.relativePath), d.value = await U(t.items), d.value.length > 0 && await N(d.value[0].fileKey), r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`); return } r.warning(t.error || "该文件夹下没有 xlsx 文件") } catch (e) { r.error(e instanceof Error ? e.message : "选择失败") } } async function V() { if (!d.value.length) { r.warning("请先选择待清洗 Excel 文件或文件夹"); return } if (!c.value.length) { r.warning("请至少选择一列保留列"); return } if (!S.value && !_.value && !m.value) { r.warning("请至少选择一种 ID 保留规则"); return } try { h.value = !0; const l = await G({ files: d.value.map(e => ({ fileKey: e.fileKey, originalFilename: e.originalFilename, relativePath: e.relativePath })), selectedColumns: c.value, keepIntegerIds: S.value, keepUnderscoreIds: _.value, keepIntegerMainIdsWhenNoSubIds: m.value, archiveName: d.value.some(e => !!e.relativePath) && w.value ? w.value : void 0 }); g.value = l, k.value = l.items || [], await D(), r.success("数据去重完成") } catch (l) { r.error(l instanceof Error ? l.message : "去重失败") } finally { h.value = !1 } } async function D() { try { const l = await Q(); k.value = l.items || [], g.value = { total: l.items?.length || 0, successCount: l.items?.filter(e => e.success).length || 0, failedCount: l.items?.filter(e => !e.success).length || 0, items: l.items || [] } } catch { } } async function M(l) { try { await X(l), await D(), r.success("已删除") } catch (e) { r.error(e instanceof Error ? e.message : "删除失败") } } async function T(l) { const e = x(); if (!l.downloadUrl) { r.warning("当前结果没有下载地址"); return } const t = l.outputFilename || `${new Date().toISOString().slice(0, 10).replace(/-/g, "")}_cleaned.xlsx`; if (e?.save_file_from_url) { const a = await e.save_file_from_url(l.downloadUrl, t); a.success ? r.success(`已保存:${a.path || t}`) : a.error && a.error !== "用户取消" && r.error(a.error); return } window.open(l.downloadUrl, "_blank") } return W(() => { D().catch(() => { }) }), (l, e) => (n(), o("div", te, [q(J, { active: "dedupe" }), s("div", le, [s("aside", ae, [e[7] || (e[7] = s("div", { class: "section-title" }, "选择文件", -1)), s("div", ne, [e[3] || (e[3] = s("div", { class: "hint" }, "选择需要清洗的 Excel 文件或文件夹,后续将按所选规则输出处理结果。", -1)), s("div", { class: "btns" }, [s("button", { type: "button", class: "opt-btn", onClick: K }, "选择 Excel 文件"), s("button", { type: "button", class: "opt-btn", onClick: R }, "选择文件夹")]), s("div", oe, [f.value.length ? (n(), o(C, { key: 0 }, [(n(!0), o(C, null, F(E.value, t => (n(), o("span", { key: t }, i(t), 1))), 128)), f.value.length > E.value.length ? (n(), o("span", re, " 还有 " + i(f.value.length - E.value.length) + " 个文件未展开显示 ", 1)) : b("", !0)], 64)) : (n(), o("span", ie, "暂未选择待清洗文件"))])]), e[8] || (e[8] = s("div", { class: "section-title" }, "保留列设置", -1)), s("div", ue, [s("div", ce, [s("span", de, "已选择 " + i(c.value.length) + " / " + i(p.value.length) + " 列", 1), s("div", { class: "column-actions" }, [s("button", { type: "button", class: "opt-btn small", onClick: $ }, "全选"), s("button", { type: "button", class: "opt-btn small", onClick: A }, "清空")])]), p.value.length ? (n(), o("div", ve, [(n(!0), o(C, null, F(p.value, t => (n(), o("label", { key: t, class: I(["column-item", { active: c.value.includes(t) }]) }, [P(s("input", { "onUpdate:modelValue": e[0] || (e[0] = a => c.value = a), type: "checkbox", value: t }, null, 8, pe), [[B, c.value]]), s("span", null, i(t), 1)], 2))), 128))])) : (n(), o("div", fe, "请选择 Excel 文件后读取表头并填充可保留列")), e[4] || (e[4] = s("div", { class: "desc" }, "读取首个 Excel 文件的第一行作为表头,用于动态选择需要保留的列。", -1))]), e[9] || (e[9] = s("div", { class: "section-title" }, "ID 保留规则", -1)), s("div", _e, [s("label", { class: I(["radio-item", { active: _.value }]) }, [P(s("input", { "onUpdate:modelValue": e[1] || (e[1] = t => _.value = t), type: "checkbox" }, null, 512), [[B, _.value]]), e[5] || (e[5] = s("div", null, [s("span", { class: "label" }, "保留子链接"), s("div", { class: "desc" }, "例如 1_1、2_3 这种带下划线的子项 ID")], -1))], 2), s("label", { class: I(["radio-item", { active: m.value }]) }, [P(s("input", { "onUpdate:modelValue": e[2] || (e[2] = t => m.value = t), type: "checkbox" }, null, 512), [[B, m.value]]), e[6] || (e[6] = s("div", null, [s("span", { class: "label" }, "仅剩主链接无子链接"), s("div", { class: "desc" }, "当某个主链接只有 13 这类主 ID、没有 13_1 这类对应子 ID 时,自动保留该主 ID")], -1))], 2)]), s("div", me, [s("button", { type: "button", class: "btn-run", disabled: h.value, onClick: V }, i(h.value ? "清洗中..." : "开始清洗"), 9, he), s("span", ge, i(h.value ? "正在处理文件并上传结果,请稍候…" : "选择文件、列和 ID 规则后即可执行清洗,结果会显示在右侧供下载"), 1)])]), s("section", ye, [e[14] || (e[14] = s("div", { class: "panel-header" }, "去重结果", -1)), s("div", be, [s("div", we, [s("div", ke, [e[10] || (e[10] = s("span", { class: "summary-label" }, "已处理文件", -1)), s("strong", null, i(g.value.total), 1)]), s("div", Ce, [e[11] || (e[11] = s("span", { class: "summary-label" }, "成功结果", -1)), s("strong", null, i(g.value.successCount), 1)]), s("div", Ie, [e[12] || (e[12] = s("span", { class: "summary-label" }, "失败文件", -1)), s("strong", null, i(g.value.failedCount), 1)])]), s("div", xe, [e[13] || (e[13] = s("div", { class: "result-list-header" }, [s("span", null, "处理后的 Excel 列表")], -1)), k.value.length === 0 ? (n(), o("div", Ee, " 暂无去重结果,完成数据去重后会在这里展示输出文件 ")) : (n(), o("ul", De, [(n(!0), o(C, null, F(k.value, t => (n(), o("li", { key: `${t.resultId || t.outputFilename || t.sourceFilename}`, class: "task-item" }, [s("div", Fe, [s("span", { class: "id", title: t.sourceFilename }, i(t.sourceFilename || "-"), 9, Pe), t.outputFilename ? (n(), o("div", Be, "输出文件:" + i(t.outputFilename), 1)) : b("", !0), t.error ? (n(), o("div", Se, "错误信息:" + i(t.error), 1)) : b("", !0)]), s("div", Ue, [s("span", { class: I(["status", t.success ? "success" : "failed"]) }, i(t.success ? "已完成" : "失败"), 3), t.success && t.downloadUrl ? (n(), o("button", { key: 0, type: "button", class: "download", onClick: a => T(t) }, " 下载文件 ", 8, Ne)) : b("", !0), t.resultId ? (n(), o("button", { key: 1, type: "button", class: "btn-delete", onClick: a => M(t.resultId) }, " 删除 ", 8, $e)) : b("", !0)])]))), 128))]))])])])])])) } }), He = Z(Ae, [["__scopeId", "data-v-6b14da88"]]); ee(He).use(se).mount("#app"); +import{d as z,o as W,a as n,c as o,b as q,B as J,e as s,F as C,r as F,t as i,f as b,n as I,w as P,v as B,g as u,h as L,i as x,E as r,j as O,k as G,l as Q,m as X,p as Y,_ as Z,q as ee,s as se}from"./pywebview-p4QBqp2b.js";const te={class:"page-shell module-page"},le={class:"main-content"},ae={class:"left-panel"},ne={class:"upload-zone"},oe={class:"selected-files clean-placeholder"},re={key:0,class:"more-line"},ie={key:1},ue={class:"option-group column-option-group"},ce={class:"column-toolbar"},de={class:"column-count"},ve={key:0,class:"column-grid"},pe=["value"],fe={key:1,class:"empty-column-state"},_e={class:"option-group"},me={class:"run-row"},he=["disabled"],ge={class:"loading-msg"},ye={class:"right-panel"},be={class:"task-list-wrap"},we={class:"clean-result-summary"},ke={class:"summary-card"},Ce={class:"summary-card"},Ie={class:"summary-card"},xe={class:"result-list-wrap"},Ee={key:0,class:"empty-tasks"},De={key:1,class:"task-list clean-result-list"},Fe={class:"left"},Pe=["title"],Be={key:0,class:"files"},Se={key:1,class:"files"},Ue={class:"task-right"},Ne=["onClick"],$e=["onClick"],Ae=z({__name:"BrandDedupeTab",setup(Ke){const p=u([]),c=u([]),f=u([]),w=u(""),d=u([]),S=u(!1),_=u(!0),m=u(!0),h=u(!1),k=u([]),g=u({total:0,successCount:0,failedCount:0,items:[]}),E=L(()=>f.value.slice(0,8));function $(){c.value=[...p.value]}function A(){c.value=[]}async function U(l){const e=x();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const a of l){const v=typeof a=="string"?a:a.absolutePath,j=typeof a=="string"?void 0:a.relativePath,y=await e.upload_file_to_java(v,j);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${v}`);t.push(y.data)}return t}async function N(l){const e=await Y(l);if(!e.headers?.length){r.error("读取 Excel 表头失败"),p.value=[],c.value=[];return}const t=["id","ASIN","国家","价格","卖家名称"],a=[...t.filter(v=>e.headers?.includes(v)),...(e.headers||[]).filter(v=>!t.includes(v))];p.value=a,c.value=t.filter(v=>a.includes(v))}async function H(l,e){f.value=l,w.value="",d.value=await U(l),d.value.length>0&&await N(d.value[0].fileKey),r.success(e)}async function K(){const l=x();if(!l?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await l.select_brand_xlsx_files();if(!e?.length)return;await H(e,`已选择 ${e.length} 个待清洗文件`)}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function R(){const l=x();if(!l?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await l.select_brand_folder();if(!e)return;w.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await O(e);if(t.success&&t.items?.length){f.value=t.items.map(a=>a.relativePath),d.value=await U(t.items),d.value.length>0&&await N(d.value[0].fileKey),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function V(){if(!d.value.length){r.warning("请先选择待清洗 Excel 文件或文件夹");return}if(!c.value.length){r.warning("请至少选择一列保留列");return}if(!S.value&&!_.value&&!m.value){r.warning("请至少选择一种 ID 保留规则");return}try{h.value=!0;const l=await G({files:d.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),selectedColumns:c.value,keepIntegerIds:S.value,keepUnderscoreIds:_.value,keepIntegerMainIdsWhenNoSubIds:m.value,archiveName:d.value.some(e=>!!e.relativePath)&&w.value?w.value:void 0});g.value=l,k.value=l.items||[],await D(),r.success("数据去重完成")}catch(l){r.error(l instanceof Error?l.message:"去重失败")}finally{h.value=!1}}async function D(){try{const l=await Q();k.value=l.items||[],g.value={total:l.items?.length||0,successCount:l.items?.filter(e=>e.success).length||0,failedCount:l.items?.filter(e=>!e.success).length||0,items:l.items||[]}}catch{}}async function M(l){try{await X(l),await D(),r.success("已删除")}catch(e){r.error(e instanceof Error?e.message:"删除失败")}}async function T(l){const e=x();if(!l.downloadUrl){r.warning("当前结果没有下载地址");return}const t=l.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}_cleaned.xlsx`;if(e?.save_file_from_url){const a=await e.save_file_from_url(l.downloadUrl,t);a.success?r.success(`已保存:${a.path||t}`):a.error&&a.error!=="用户取消"&&r.error(a.error);return}window.open(l.downloadUrl,"_blank")}return W(()=>{D().catch(()=>{})}),(l,e)=>(n(),o("div",te,[q(J,{active:"dedupe"}),s("div",le,[s("aside",ae,[e[7]||(e[7]=s("div",{class:"section-title"},"选择文件",-1)),s("div",ne,[e[3]||(e[3]=s("div",{class:"hint"},"选择需要清洗的 Excel 文件或文件夹,后续将按所选规则输出处理结果。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:K},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:R},"选择文件夹")]),s("div",oe,[f.value.length?(n(),o(C,{key:0},[(n(!0),o(C,null,F(E.value,t=>(n(),o("span",{key:t},i(t),1))),128)),f.value.length>E.value.length?(n(),o("span",re," 还有 "+i(f.value.length-E.value.length)+" 个文件未展开显示 ",1)):b("",!0)],64)):(n(),o("span",ie,"暂未选择待清洗文件"))])]),e[8]||(e[8]=s("div",{class:"section-title"},"保留列设置",-1)),s("div",ue,[s("div",ce,[s("span",de,"已选择 "+i(c.value.length)+" / "+i(p.value.length)+" 列",1),s("div",{class:"column-actions"},[s("button",{type:"button",class:"opt-btn small",onClick:$},"全选"),s("button",{type:"button",class:"opt-btn small",onClick:A},"清空")])]),p.value.length?(n(),o("div",ve,[(n(!0),o(C,null,F(p.value,t=>(n(),o("label",{key:t,class:I(["column-item",{active:c.value.includes(t)}])},[P(s("input",{"onUpdate:modelValue":e[0]||(e[0]=a=>c.value=a),type:"checkbox",value:t},null,8,pe),[[B,c.value]]),s("span",null,i(t),1)],2))),128))])):(n(),o("div",fe,"请选择 Excel 文件后读取表头并填充可保留列")),e[4]||(e[4]=s("div",{class:"desc"},"读取首个 Excel 文件的第一行作为表头,用于动态选择需要保留的列。",-1))]),e[9]||(e[9]=s("div",{class:"section-title"},"ID 保留规则",-1)),s("div",_e,[s("label",{class:I(["radio-item",{active:_.value}])},[P(s("input",{"onUpdate:modelValue":e[1]||(e[1]=t=>_.value=t),type:"checkbox"},null,512),[[B,_.value]]),e[5]||(e[5]=s("div",null,[s("span",{class:"label"},"保留子链接"),s("div",{class:"desc"},"例如 1_1、2_3 这种带下划线的子项 ID")],-1))],2),s("label",{class:I(["radio-item",{active:m.value}])},[P(s("input",{"onUpdate:modelValue":e[2]||(e[2]=t=>m.value=t),type:"checkbox"},null,512),[[B,m.value]]),e[6]||(e[6]=s("div",null,[s("span",{class:"label"},"仅剩主链接无子链接"),s("div",{class:"desc"},"当某个主链接只有 13 这类主 ID、没有 13_1 这类对应子 ID 时,自动保留该主 ID")],-1))],2)]),s("div",me,[s("button",{type:"button",class:"btn-run",disabled:h.value,onClick:V},i(h.value?"清洗中...":"开始清洗"),9,he),s("span",ge,i(h.value?"正在处理文件并上传结果,请稍候…":"选择文件、列和 ID 规则后即可执行清洗,结果会显示在右侧供下载"),1)])]),s("section",ye,[e[14]||(e[14]=s("div",{class:"panel-header"},"去重结果",-1)),s("div",be,[s("div",we,[s("div",ke,[e[10]||(e[10]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,i(g.value.total),1)]),s("div",Ce,[e[11]||(e[11]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,i(g.value.successCount),1)]),s("div",Ie,[e[12]||(e[12]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,i(g.value.failedCount),1)])]),s("div",xe,[e[13]||(e[13]=s("div",{class:"result-list-header"},[s("span",null,"处理后的 Excel 列表")],-1)),k.value.length===0?(n(),o("div",Ee," 暂无去重结果,完成数据去重后会在这里展示输出文件 ")):(n(),o("ul",De,[(n(!0),o(C,null,F(k.value,t=>(n(),o("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",Fe,[s("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,Pe),t.outputFilename?(n(),o("div",Be,"输出文件:"+i(t.outputFilename),1)):b("",!0),t.error?(n(),o("div",Se,"错误信息:"+i(t.error),1)):b("",!0)]),s("div",Ue,[s("span",{class:I(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&t.downloadUrl?(n(),o("button",{key:0,type:"button",class:"download",onClick:a=>T(t)}," 下载文件 ",8,Ne)):b("",!0),t.resultId?(n(),o("button",{key:1,type:"button",class:"btn-delete",onClick:a=>M(t.resultId)}," 删除 ",8,$e)):b("",!0)])]))),128))]))])])])])]))}}),He=Z(Ae,[["__scopeId","data-v-6b14da88"]]);ee(He).use(se).mount("#app"); diff --git a/app/assets/delete-brand-BgPrpPsj.css b/app/assets/delete-brand-BgPrpPsj.css deleted file mode 100644 index 1ec488e..0000000 --- a/app/assets/delete-brand-BgPrpPsj.css +++ /dev/null @@ -1 +0,0 @@ -.module-page[data-v-ff0a9bae]{min-height:100vh;background:#1a1a1a}.main-content[data-v-ff0a9bae]{display:flex;min-height:calc(100vh - 56px);height:calc(100vh - 56px)}.left-panel[data-v-ff0a9bae]{width:380px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-ff0a9bae]{flex:1;display:flex;flex-direction:column;min-width:0;background:#1a1a1a}.section-title[data-v-ff0a9bae]{font-size:13px;color:#bbb;margin-bottom:10px}.upload-zone[data-v-ff0a9bae]{border:1px dashed #3a3a3a;border-radius:10px;padding:24px;text-align:center;background:#252525;margin-bottom:20px;transition:all .2s ease}.upload-zone[data-v-ff0a9bae]:hover{border-color:#3498db;background:#2a2a2a}.hint[data-v-ff0a9bae]{color:#888;font-size:13px;margin-bottom:12px;line-height:1.5}.btns[data-v-ff0a9bae]{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}.opt-btn[data-v-ff0a9bae],.btn-run[data-v-ff0a9bae],.download[data-v-ff0a9bae],.btn-delete[data-v-ff0a9bae]{border:none;cursor:pointer;transition:all .2s ease}.opt-btn[data-v-ff0a9bae]{padding:8px 16px;font-size:13px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a;border-radius:6px}.opt-btn[data-v-ff0a9bae]:hover{color:#3498db;background:#333;border-color:#3498db}.selected-files[data-v-ff0a9bae]{margin-top:14px;font-size:12px;color:#888;max-height:112px;overflow-y:auto;text-align:left}.selected-files span[data-v-ff0a9bae]{display:block;margin:4px 0;word-break:break-all}.more-line[data-v-ff0a9bae]{color:#b8c1cc}.split-selected-files[data-v-ff0a9bae]{max-height:120px;min-height:72px;padding-right:4px}.option-group[data-v-ff0a9bae]{margin-bottom:20px}.radio-item[data-v-ff0a9bae]{display:flex;align-items:flex-start;gap:10px;cursor:pointer;padding:10px 12px;border-radius:8px;background:#252525;border:1px solid #2a2a2a;margin-bottom:8px;transition:all .2s ease}.radio-item[data-v-ff0a9bae]:hover,.radio-item.active[data-v-ff0a9bae]{background:#2a2a2a;border-color:#3a3a3a}.radio-item input[data-v-ff0a9bae]{margin-top:3px}.label[data-v-ff0a9bae]{font-weight:500;color:#e0e0e0;font-size:13px}.desc[data-v-ff0a9bae]{font-size:12px;color:#888;margin-top:2px;line-height:1.5;font-weight:400}.run-row[data-v-ff0a9bae]{display:flex;align-items:center;flex-wrap:wrap;gap:10px 12px;margin-top:16px}.btn-run[data-v-ff0a9bae]{padding:10px 22px;background:#3498db;color:#fff;border-radius:8px;font-size:14px}.btn-run[data-v-ff0a9bae]:hover{background:#2980b9}.btn-run[data-v-ff0a9bae]:disabled{background:#555;color:#999;cursor:not-allowed}.loading-msg[data-v-ff0a9bae]{color:#3498db;font-size:13px}.panel-header[data-v-ff0a9bae]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-ff0a9bae]{flex:1;overflow-y:auto;padding:16px}.task-list[data-v-ff0a9bae]{list-style:none;margin:0;padding:0}.task-item[data-v-ff0a9bae]{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:10px;background:#1e1e1e}.split-result-item[data-v-ff0a9bae]{align-items:flex-start}.left[data-v-ff0a9bae]{flex:1;min-width:0}.split-result-main[data-v-ff0a9bae]{display:flex;flex-direction:column;gap:4px}.id[data-v-ff0a9bae]{display:inline-block;font-weight:600;color:#e0e0e0;font-size:13px}.files[data-v-ff0a9bae]{font-size:12px;color:#888;margin-top:4px}.time[data-v-ff0a9bae]{font-size:12px;color:#666;margin-top:2px}.split-entry-list[data-v-ff0a9bae]{line-height:1.6;word-break:break-all;max-width:100%}.delete-brand-preview[data-v-ff0a9bae]{white-space:normal}.task-right[data-v-ff0a9bae]{display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:flex-end}.split-result-actions[data-v-ff0a9bae]{flex-shrink:0;min-width:180px;justify-content:flex-end;align-self:center}.status[data-v-ff0a9bae]{padding:4px 10px;border-radius:6px;font-size:12px;white-space:nowrap}.status.success[data-v-ff0a9bae]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-ff0a9bae]{background:#e74c3c2e;color:#ff6b6b}.download[data-v-ff0a9bae]{padding:6px 10px;border-radius:6px;font-size:12px;background:#3498db2e;color:#69b6ff}.download[data-v-ff0a9bae]:hover{background:#3498db47}.btn-delete[data-v-ff0a9bae]{padding:6px 10px;border-radius:6px;font-size:12px;background:#e74c3c1f;color:#ff8f8f}.btn-delete[data-v-ff0a9bae]:hover{background:#e74c3c38}.empty-tasks[data-v-ff0a9bae]{color:#666;font-size:13px;padding:24px 8px}.clean-placeholder[data-v-ff0a9bae]{max-height:112px}.clean-result-summary[data-v-ff0a9bae]{display:grid;grid-template-columns:repeat(3,minmax(0,220px));gap:16px;margin-bottom:18px}.summary-card[data-v-ff0a9bae]{padding:16px 18px;border:1px solid #2a2a2a;border-radius:10px;background:#1e1e1e}.summary-card strong[data-v-ff0a9bae]{display:block;margin-top:8px;font-size:24px;color:#eaf4ff}.summary-label[data-v-ff0a9bae]{font-size:12px;color:#8d8d8d}.result-list-wrap[data-v-ff0a9bae]{border:1px solid #2a2a2a;border-radius:10px;background:#1e1e1e;min-height:260px}.result-list-header[data-v-ff0a9bae]{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid #2a2a2a;font-size:14px;color:#ddd}@media(max-width:1100px){.main-content[data-v-ff0a9bae]{flex-direction:column;height:auto}.left-panel[data-v-ff0a9bae]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.right-panel[data-v-ff0a9bae]{min-height:420px}.task-item[data-v-ff0a9bae]{flex-direction:column;align-items:flex-start}.task-right[data-v-ff0a9bae]{width:100%;justify-content:flex-start}.split-result-actions[data-v-ff0a9bae]{min-width:0;align-self:flex-start}.clean-result-summary[data-v-ff0a9bae]{grid-template-columns:1fr}} diff --git a/app/assets/delete-brand.js b/app/assets/delete-brand.js index e29de2d..baf207a 100644 --- a/app/assets/delete-brand.js +++ b/app/assets/delete-brand.js @@ -1 +1 @@ -import{d as S,o as D,a as l,c as n,b as N,B as j,e as a,F as y,r as x,t as o,f as c,J as H,n as T,g as _,h as V,i as g,E as r,j as A,K,L as M,M as z,_ as J,q as L,s as U}from"./pywebview-DdV1XQSM.js";const q={class:"page-shell module-page"},G={class:"main-content"},O={class:"left-panel"},Q={class:"upload-zone"},W={class:"selected-files clean-placeholder split-selected-files"},X={key:0,class:"more-line"},Y={key:1},Z={class:"run-row"},ss=["disabled"],es={class:"loading-msg"},as={class:"right-panel"},ts={class:"task-list-wrap"},ls={class:"clean-result-summary"},ns={class:"summary-card"},os={class:"summary-card"},is={class:"summary-card"},rs={class:"result-list-wrap"},cs={key:0,class:"empty-tasks"},ds={key:1,class:"task-list clean-result-list"},us={class:"left split-result-main"},vs=["title"],fs={class:"files"},ps={class:"files"},_s={key:0,class:"files"},hs={key:1,class:"files"},bs={key:2,class:"time"},ys={key:3,class:"files split-entry-list delete-brand-preview"},gs={key:4,class:"files"},ms={class:"task-right split-result-actions"},ks=["onClick"],ws=["onClick"],xs=S({__name:"BrandDeleteBrandTab",setup(Bs){const d=_([]),h=_([]),u=_(!1),v=_([]),f=_({total:0,successCount:0,failedCount:0,items:[]}),b=V(()=>d.value.slice(0,8));function C(t){f.value={total:t.length,successCount:t.filter(s=>s.success).length,failedCount:t.filter(s=>!s.success).length,items:t}}async function m(t){const s=g();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const e=[];for(const i of t){const w=typeof i=="string"?i:i.absolutePath,R=typeof i=="string"?void 0:i.relativePath,p=await s.upload_file_to_java(w,R);if(!p?.success||!p.data)throw new Error(p?.error||p?.message||`上传失败:${w}`);e.push(p.data)}return e}async function B(){const t=g();if(!t?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const s=await t.select_brand_xlsx_files();if(!s?.length)return;d.value=s,h.value=await m(s),r.success(`已选择 ${s.length} 个删除品牌文件`)}catch(s){r.error(s instanceof Error?s.message:"选择失败")}}async function E(){const t=g();if(!t?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const s=await t.select_brand_folder();if(!s)return;const e=await A(s);if(!e.success||!e.items?.length){r.warning(e.error||"该文件夹下没有 xlsx 文件");return}d.value=e.items.map(i=>i.relativePath||i.absolutePath),h.value=await m(e.items),r.success(`已选择文件夹内 ${e.items.length} 个 xlsx 文件`)}catch(s){r.error(s instanceof Error?s.message:"选择失败")}}async function P(){if(!h.value.length){r.warning("请先选择待处理文件");return}try{u.value=!0;const t=await K({files:h.value.map(s=>({fileKey:s.fileKey,originalFilename:s.originalFilename,relativePath:s.relativePath}))});f.value=t,v.value=t.items||[],r.success("删除品牌解析完成")}catch(t){r.error(t instanceof Error?t.message:"执行失败")}finally{u.value=!1}}async function k(){try{const t=await M();v.value=t.items||[],C(v.value)}catch{}}async function $(t){try{await z(t),await k(),r.success("已删除")}catch(s){r.error(s instanceof Error?s.message:"删除失败")}}function F(t){const s=t.slice(0,5).map(i=>`${i.country}:${i.asin}${i.status?`(${i.status})`:""}`);return t.length-s.length>0?`${s.join("、")} 等 ${t.length} 条`:s.join("、")}function I(t){window.open(t,"_blank")}return D(()=>{k().catch(()=>{})}),(t,s)=>(l(),n("div",q,[N(j,{active:"delete-brand"}),a("div",G,[a("aside",O,[s[1]||(s[1]=a("div",{class:"section-title"},"选择文件",-1)),a("div",Q,[s[0]||(s[0]=a("div",{class:"hint"},"上传删除品牌 Excel;无论是直接上传文件还是上传文件夹批量导入,都会按每个 Excel 文件名作为店铺名。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:B},"选择 Excel 文件"),a("button",{type:"button",class:"opt-btn",onClick:E},"选择文件夹")]),a("div",W,[d.value.length?(l(),n(y,{key:0},[(l(!0),n(y,null,x(b.value,e=>(l(),n("span",{key:e},o(e),1))),128)),d.value.length>b.value.length?(l(),n("span",X," 还有 "+o(d.value.length-b.value.length)+" 个文件未展开显示 ",1)):c("",!0)],64)):(l(),n("span",Y,"暂未选择删除品牌文件"))])]),s[2]||(s[2]=H('