庫存與銷售監控面板分倉版・離線

同一產品分散多倉的明細會正確加總 · 類別由品名前綴判定 · 全程本機處理、不連網

資料匯入

支援 .xls / .xlsx,在瀏覽器內解析,不上傳(點標題可收摺)
Jolly Pet

開始使用

請點上方「資料匯入」,載入你的庫存檔銷售檔(.xls / .xlsx)。
帶入資料後即可開始分析,此畫面會自動消失。
還沒有檔案?可先「下載庫存/銷售/通路銷售範本」,填好再匯入。

倉別篩選

勾選計入總額的倉庫(可排除報廢/瑕疵/樣品等)

品牌庫存金額

各品牌長條

品牌庫存金額及數量

依關鍵字判斷品牌(不受上方品牌篩選影響)

不同倉別庫存金額

長條

倉別佔比

圓餅

每月銷售數據

營業額/數量/利潤/成長率/利潤率/利潤成長率

品牌業績分布

依營業額

品牌毛利分布

依利潤金額

品牌銷售數量

依數量

銷售前 10 名

依銷量/營業額/利潤(可用上方品牌篩選)

銷售熱力圖

成長率前 30 名 × 各月營業額

各通路業績額與佔比

通路類型營業額佔比

依通路類型

線上線下業績分布

依線上/線下

自有/合作通路比例

依自有/合作

客戶分析(依通路)

業績/佔比/成長率/毛利/毛利率・點欄位排序
成長率比較

業績組成

依月份與通路・同品項加總

原始銷售數據

依月份與通路的逐筆交易

商品週轉天數

≤30 天 健康31–60 天 注意>60 天 偏慢

採購建議篩選

門檻可自行調整
品牌篩選
近幾個月有銷售 毛利率 ≥% 週轉天數 ≤ 建議採購 = 近3月均銷 ×
建議採購量 = 近 3 個月平均月銷量 × 倍數(可自行設定,預設 3)。均銷月數可在「週轉」頁設定。匯出欄位:品項名稱、條碼、型號、實際在庫數量、建議採購量。

庫存原始資料

品牌 倉庫
關鍵字可用空白鍵分隔多個,需全部符合才顯示(例:大樹 麻繩)。

商品價格策略

'; var blob=new Blob([s],{type:"text/html;charset=utf-8"});var a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download="商品價格表_"+priceRoleName()+"_"+priceDateMMDD()+".html";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(a.href);a.remove();},1500); } // ================= 共用 ================= function renderActive(){if(state.tab==="inv")renderInv();else if(state.tab==="sales")renderSales();else if(state.tab==="chan")renderChannel();else if(state.tab==="turn")renderTurn();else if(state.tab==="buy")renderBuy();else if(state.tab==="raw")renderRaw();else if(state.tab==="price")renderPrice();} // ---------------- 示範資料 ---------------- function loadDemo(){ // [name, code, barcode, cost, {warehouse:qty,...}] var P=[ ["寵物玩具-麻繩球","TOY-001","4710001",35,{"MIT":200,"總倉":120}], ["寵物玩具-逗貓棒","TOY-002","4710002",22,{"MIT":300,"長興12-9":80}], ["寵物玩具-發聲鴨","TOY-003","4710003",48,{"總倉":60}], ["寵物玩具-滾球","TOY-004","4710004",60,{"MIT":15}], ["寵物服飾-毛衣M","CLO-001","4710011",120,{"MIT":90,"總倉":40}], ["寵物服飾-雨衣L","CLO-002","4710012",150,{"MIT":50}], ["寵物服飾-領巾","CLO-003","4710013",18,{"總倉":400}], ["寵物服飾-帽子","CLO-004","4710014",40,{"總倉":250}], ["包裝材料-紙箱S","PKG-001","4710021",7,{"長興12-9":800,"MIT":200}], ["包裝材料-膠帶","PKG-002","4710022",20,{"長興12-9":700}], ["寵物窩-PETSNOWY雪屋保暖窩","SNW-001","4720001",320,{"總倉":60,"MIT":25}], ["寵物玩具-PURRPY羽毛逗貓","PUR-001","4720002",45,{"MIT":150}], ["寵物推車-FIDA輕便寵物推車","FID-001","4720003",1800,{"總倉":12}] ]; state.lines=[]; P.forEach(function(p){var byW=p[4];var rc=catOf(p[0]);var bd=brandOf(p[0]);for(var w in byW){var q=byW[w];state.lines.push({name:p[0],code:p[1],barcode:p[2],cost:p[3],qty:q,value:q*p[3],warehouse:w,rawCat:rc,category:groupCat(rc),brand:bd});}}); var price={"寵物玩具-麻繩球":99,"寵物玩具-逗貓棒":59,"寵物玩具-發聲鴨":120,"寵物玩具-滾球":159,"寵物服飾-毛衣M":299,"寵物服飾-雨衣L":390,"寵物服飾-領巾":59,"寵物服飾-帽子":119,"包裝材料-紙箱S":20,"包裝材料-膠帶":45,"寵物窩-PETSNOWY雪屋保暖窩":899,"寵物玩具-PURRPY羽毛逗貓":129,"寵物推車-FIDA輕便寵物推車":3990}; var qty={ "寵物玩具-麻繩球":[80,95,110,130,150,180],"寵物玩具-逗貓棒":[120,130,125,140,160,175],"寵物玩具-發聲鴨":[20,28,35,44,55,70], "寵物玩具-滾球":[6,5,4,4,3,2],"寵物服飾-毛衣M":[40,45,38,30,22,18],"寵物服飾-雨衣L":[10,14,20,28,40,55], "寵物服飾-領巾":[60,72,80,88,95,110],"寵物服飾-帽子":[8,7,6,6,5,4],"包裝材料-紙箱S":[300,320,310,330,360,400],"包裝材料-膠帶":[150,160,155,170,180,200], "寵物窩-PETSNOWY雪屋保暖窩":[8,10,14,20,26,30],"寵物玩具-PURRPY羽毛逗貓":[40,55,60,52,70,85],"寵物推車-FIDA輕便寵物推車":[2,3,3,4,5,6] }; var bc={"寵物玩具-麻繩球":"4710001","寵物玩具-逗貓棒":"4710002","寵物玩具-發聲鴨":"4710003","寵物玩具-滾球":"4710004","寵物服飾-毛衣M":"4710011","寵物服飾-雨衣L":"4710012","寵物服飾-領巾":"4710013","寵物服飾-帽子":"4710014","包裝材料-紙箱S":"4710021","包裝材料-膠帶":"4710022","寵物窩-PETSNOWY雪屋保暖窩":"4720001","寵物玩具-PURRPY羽毛逗貓":"4720002","寵物推車-FIDA輕便寵物推車":"4720003"}; var months=["2026.01月","2026.02月","2026.03月","2026.04月","2026.05月","2026.06月"]; state.salesByMonth={};state.monthOrder=months.slice(); months.forEach(function(mn,mi){var agg={};for(var nm in qty){var q=qty[nm][mi],pr=price[nm];agg[norm(nm)]={name:nm,barcode:bc[nm],qty:q,revenue:q*pr};}state.salesByMonth[mn]=agg;}); finishLoad("已載入示範資料(仿你的分倉格式:多倉別、類別由品名前綴判定、每月分頁)。"); } // ---------------- 解析 Excel ---------------- function aoa(ws){return XLSX.utils.sheet_to_json(ws,{header:1,raw:true,defval:null});} function loadInventoryWB(wb){ var pick=null; for(var i=0;i=0||h.idx.value>=0||h.idx.cost>=0)){pick={a:a,row:h.row,idx:h.idx};break;}} if(!pick){var a0=aoa(wb.Sheets[wb.SheetNames[0]]);var h0=detectHeader(a0,INV_ALIAS);pick={a:a0,row:h0?h0.row:0,idx:h0?h0.idx:headerIdx(a0[0]||[],INV_ALIAS)};} var a=pick.a,idx=pick.idx,lines=[],n=0; for(var r=pick.row+1;r=0?numv(row[idx.cost]):0;var qty=idx.qty>=0?numv(row[idx.qty]):0; var actual=idx.actual>=0?numv(row[idx.actual]):null; var val=idx.value>=0?numv(row[idx.value]):0;if(!val)val=qty*cost; var rawCat=idx.category>=0?clean(row[idx.category]):"";if(!rawCat)rawCat=catOf(name); lines.push({name:name,barcode:idx.barcode>=0?clean(row[idx.barcode]):"",code:idx.code>=0?clean(row[idx.code]):"",cost:cost,qty:qty,actual:actual,value:val,warehouse:idx.warehouse>=0?(clean(row[idx.warehouse])||"未指定"):"未指定",rawCat:rawCat,category:groupCat(rawCat),brand:brandOf(name)}); n++;} return {lines:lines,n:n,hasCat:idx.category>=0,hasActual:idx.actual>=0}; } function loadSalesWB(wb){ var byMonth={},order=[]; wb.SheetNames.forEach(function(sn){var a=aoa(wb.Sheets[sn]);if(a.length<1)return;var h=detectHeader(a,SALES_ALIAS);if(!h||h.idx.name<0)return;var idx=h.idx; var agg={};for(var r=h.row+1;r=0?numv(row[idx.qty]):0;var price=idx.price>=0?numv(row[idx.price]):0;var rev=idx.revenue>=0?numv(row[idx.revenue]):0;if(!rev)rev=qty*price; var k=norm(name);if(!agg[k])agg[k]={name:name,barcode:idx.barcode>=0?clean(row[idx.barcode]):"",qty:0,revenue:0};agg[k].qty+=qty;agg[k].revenue+=rev;} if(Object.keys(agg).length){byMonth[sn]=agg;order.push(sn);}}); order.sort(function(x,y){return monthKey(x)-monthKey(y);}); return {byMonth:byMonth,order:order}; } function readFileToWB(file,cb){ if(typeof XLSX==="undefined"){alert("找不到 Excel 引擎 xlsx.full.min.js");return;} var rd=new FileReader();rd.onload=function(){try{cb(XLSX.read(new Uint8Array(rd.result),{type:"array"}));}catch(e){setStatus("讀取失敗:"+e.message,true);}};rd.onerror=function(){setStatus("讀取失敗。",true);};rd.readAsArrayBuffer(file); } // ---------------- 彙總 ---------------- function rebuildMeta(){ // warehouses var wseen={},ws=[];state.lines.forEach(function(l){if(!wseen[l.warehouse]){wseen[l.warehouse]=1;ws.push(l.warehouse);}}); state.warehouses=ws; if(!state.whSel)state.whSel=new Set(ws); else {var keep=new Set();ws.forEach(function(w){if(state.whSel.has(w))keep.add(w);});if(!keep.size)keep=new Set(ws);state.whSel=keep;} buildProd(); var cseen={},cs=[];state.lines.forEach(function(l){if(!cseen[l.category]){cseen[l.category]=1;cs.push(l.category);}}); cs.sort();state.cats=cs; if(!state.monthOrder.length)state.monthOrder=Object.keys(state.salesByMonth); if(!state.month||state.monthOrder.indexOf(state.month)<0)state.month=state.monthOrder[state.monthOrder.length-1]||null; } function buildProd(){ var prod={}; state.lines.forEach(function(l){if(!state.whSel||!state.whSel.has(l.warehouse))return;var p=prod[norm(l.name)];if(!p){p={name:l.name,category:l.category,barcode:l.barcode,code:l.code,stock:0,value:0,actualStock:0,hasActual:false};prod[norm(l.name)]=p;}p.stock+=l.qty;p.value+=l.value;if(l.actual!=null){p.actualStock+=l.actual;p.hasActual=true;}if(l.barcode&&!p.barcode)p.barcode=l.barcode;if(l.code&&!p.code)p.code=l.code;}); for(var k in prod){var p=prod[k];p.cost=p.stock>0?p.value/p.stock:0;p.actualValue=p.actualStock*p.cost;} state.prod=prod; } function pStock(p){return state.qtyMode==="actual"?p.actualStock:p.stock;} function pValue(p){return state.qtyMode==="actual"?p.actualValue:p.value;} function lQty(l){return state.qtyMode==="actual"?(l.actual!=null?l.actual:0):l.qty;} function lVal(l){return state.qtyMode==="actual"?(l.actual!=null?l.actual:0)*l.cost:l.value;} function prevMonth(m){var i=state.monthOrder.indexOf(m);return i>0?state.monthOrder[i-1]:null;} function salesOf(m,nk){var a=state.salesByMonth[m];if(!a)return null;return a[nk]||null;} // per product metric for a month (nk = norm name) function pm(nk,m){var s=salesOf(m,nk)||{qty:0,revenue:0};var p=state.prod[nk];var cost=p?p.cost:0;var profit=s.revenue-s.qty*cost;return {qty:s.qty,revenue:s.revenue,profit:profit,margin:s.revenue?profit/s.revenue*100:0};} function monthTotals(m){var a=state.salesByMonth[m]||{};var rev=0,qty=0,profit=0;for(var nk in a){if(!passBrand(a[nk].name))continue;var x=pm(nk,m);rev+=x.revenue;qty+=x.qty;profit+=x.profit;}return {rev:rev,qty:qty,profit:profit,margin:rev?profit/rev*100:0};} function win3(){var n=Math.max(1,Math.min(24,state.avgMonths||WIN));return state.monthOrder.slice(Math.max(0,state.monthOrder.length-n));} function avgQty3(nk){var w=win3();var t=0;w.forEach(function(m){var s=salesOf(m,nk);if(s)t+=s.qty;});return w.length?t/w.length:0;} function sum3(nk){var w=win3(),rev=0,qty=0,profit=0;w.forEach(function(m){var x=pm(nk,m);rev+=x.revenue;qty+=x.qty;profit+=x.profit;});return {rev:rev,qty:qty,profit:profit,margin:rev?profit/rev*100:0,n:w.length};} function turnoverOf(nk){var p=state.prod[nk];if(!p)return null;var aq=avgQty3(nk);var avgCogs=aq*p.cost;return avgCogs>0?p.value/avgCogs*TURN_DAYS:null;} // ---------------- tooltip ---------------- var TIP=$("#tip"),TIPMAP={},TK=0; function showTip(n,v,x,y){TIP.innerHTML='
'+esc(n)+'
'+esc(v)+'
';TIP.style.display="block";TIP.style.left=(x+14)+"px";TIP.style.top=(y+14)+"px";} function showTipRich(t,x,y){var h='
'+esc(t.title)+'
'+t.items.map(function(it){return '';}).join("")+'
'+esc(it.name)+''+esc(fmtMoney(it.val))+''+it.pct.toFixed(1)+'%
';TIP.innerHTML=h;TIP.style.display="block";TIP.style.left=(x+14)+"px";TIP.style.top=(y+14)+"px";} function hideTip(){TIP.style.display="none";} function attachTip(svg){if(!svg)return;svg.addEventListener("mousemove",function(e){var rk=e.target.closest("[data-tipk]");if(rk&&TIPMAP[rk.getAttribute("data-tipk")]){showTipRich(TIPMAP[rk.getAttribute("data-tipk")],e.clientX,e.clientY);return;}var b=e.target.closest("[data-name]");if(b)showTip(b.getAttribute("data-name"),b.getAttribute("data-val"),e.clientX,e.clientY);else hideTip();});svg.addEventListener("mouseleave",hideTip);} // ---------------- 圖:水平長條 ---------------- function drawHBar(host,rows,opt){ rows=rows.filter(function(r){return r.value!=null&&isFinite(r.value);}); if(!rows.length){host.innerHTML='
沒有可顯示的資料
';return;} var unit=opt.unit,div=!!opt.diverging,W=Math.max(280,host.clientWidth||540),rh=24,top=6,bot=22,lw=opt.labelW||112,vp=56; var H=top+rows.length*rh+bot,pl=lw,pr=W-vp,pw=Math.max(40,pr-pl); var vals=rows.map(function(r){return r.value;}),mn,mx; if(div){mn=Math.min.apply(null,[0].concat(vals));mx=Math.max.apply(null,[0].concat(vals));}else{mn=0;mx=Math.max.apply(null,[0].concat(vals));} var rg=mx-mn;if(rg===0)rg=1;function x(v){return pl+((v-mn)/rg)*pw;}var zx=x(0); var s=''; [div?mn:0,div?0:mx/2,mx].forEach(function(t){var tx=x(t);s+='';s+=''+esc(unit==="currency"?fmtCompact(t):unit==="percent"?Math.round(t)+"%":Math.round(t))+'';}); rows.forEach(function(r,i){var cy=top+i*rh+rh/2,bh=14,by=cy-bh/2,bx,bw;if(div){if(r.value>=0){bx=zx;bw=x(r.value)-zx;}else{bx=x(r.value);bw=zx-x(r.value);}}else{bx=pl;bw=x(r.value)-pl;}bw=Math.max(0,bw); var vt=r.label?r.label:(unit==="currency"?fmtMoney(r.value):unit==="percent"?fmtPctSigned(r.value):unit==="days"?fmtDays(r.value):fmtInt(r.value)); s+=''; s+=''+esc(trunc(r.name,opt.labelChars||8))+''; if(div&&r.value<0)s+=''+esc(vt)+''; else s+=''+esc(vt)+'';}); s+='';host.innerHTML=s;attachTip(host.querySelector("svg")); } // ---------------- 圖:圓餅 ---------------- function arcPath(cx,cy,rO,rI,a0,a1){function P(r,a){return [(cx+r*Math.cos(a)).toFixed(2),(cy+r*Math.sin(a)).toFixed(2)];}var lg=(a1-a0)>Math.PI?1:0;var o0=P(rO,a0),o1=P(rO,a1),i1=P(rI,a1),i0=P(rI,a0);return "M"+o0[0]+","+o0[1]+" A"+rO+","+rO+" 0 "+lg+" 1 "+o1[0]+","+o1[1]+" L"+i1[0]+","+i1[1]+" A"+rI+","+rI+" 0 "+lg+" 0 "+i0[0]+","+i0[1]+" Z";} function drawPie(host,leg,data,fmt,opts){ fmt=fmt||fmtMoney;opts=opts||{}; if(!data.length){host.innerHTML='
尚無資料
';if(leg)leg.innerHTML="";return;} var size=180,cx=90,cy=90,rO=84,rI=48,total=0;data.forEach(function(d){total+=d.value;});if(total<=0)total=1; function tipAttr(d,fr){if(opts.tipData){var t=opts.tipData(d);if(t){var kk="tk"+(TK++);TIPMAP[kk]=t;return ' data-tipk="'+kk+'"';}}return ' data-name="'+esc(d.name)+'" data-val="'+esc(fmt(d.value)+"("+(fr*100).toFixed(1)+"%)")+'"';} var s=''; if(data.length===1){s+='';} else{var a0=-Math.PI/2;data.forEach(function(d){var fr=d.value/total,a1=a0+fr*Math.PI*2;s+='';a0=a1;});} s+='';host.innerHTML=s;attachTip(host.querySelector("svg")); if(leg){var sorted=data.slice().sort(function(a,b){return b.value-a.value;});leg.innerHTML=''+sorted.map(function(d){var pct=((d.value/total)*100).toFixed(1)+'%';var nc='';return opts.legendAmount?(''+nc+''):(''+nc+'');}).join("")+'
'+esc(trunc(d.name,18))+'
'+esc(fmt(d.value))+''+pct+'
'+pct+'
';} } // ---------------- 圖:折線 ---------------- function drawLine(host,pts,unit){ if(pts.length<1){host.innerHTML='
尚無資料
';return;} var W=Math.max(300,host.clientWidth||540),H=200,top=12,bot=28,left=56,right=16,pw=W-left-right,ph=H-top-bot; var vals=pts.map(function(p){return p.value;}),mx=Math.max.apply(null,[1].concat(vals)),mn=Math.min.apply(null,[0].concat(vals)),rg=mx-mn||1; function x(i){return left+(pts.length===1?pw/2:(i/(pts.length-1))*pw);}function y(v){return top+(1-(v-mn)/rg)*ph;} var s=''; [0,.5,1].forEach(function(t){var v=mn+rg*t,yy=y(v);s+='';s+=''+esc(fmtCompact(v))+'';}); var d="";pts.forEach(function(p,i){d+=(i?" L":"M")+x(i).toFixed(1)+","+y(p.value).toFixed(1);}); s+=''; pts.forEach(function(p,i){s+='';s+=''+esc(p.label)+'';}); s+='';host.innerHTML=s;attachTip(host.querySelector("svg")); } // ================= 共用:可排序表格 ================= function sortTable(cfg){ var cols=cfg.cols,s=cfg.sort,rows=cfg.rows.slice(); if(s.k){var col=null;for(var ci=0;cicfg.limit)rows=rows.slice(0,cfg.limit); var head=""+cols.map(function(c){var ind=(s.k===c.k)?(s.dir<0?' ':' '):'';return ''+esc(c.label)+ind+'';}).join("")+""; var body=rows.length?(""+rows.map(function(r){return ""+cols.map(function(c){return c.cell(r);}).join("")+"";}).join("")+""):(''+esc(cfg.empty||"無資料")+''); var foot=(cfg.footerHtml&&rows.length)?(''+cfg.footerHtml+''):""; var host=$(cfg.host);host.innerHTML='
'+head+body+foot+'
'; var ths=host.querySelectorAll("th.sortable");for(var t=0;t尚未載入庫存檔。請至上方「資料匯入」載入庫存檔(.xls / .xlsx)後即可顯示。';["invBrandBar","invBrandTable","invWhBar","invWhPie","invWhPieLeg","whChips"].forEach(function(id){var e=$("#"+id);if(e)e.innerHTML="";});return;} renderWhChips(); var actMode=state.qtyMode==="actual"; var totVal=0,totQty=0,prodN=0;for(var k in state.prod){var p0=state.prod[k];if(!passBrand(p0.name))continue;totVal+=pValue(p0);totQty+=pStock(p0);prodN++;} var qtyLbl=actMode?"總實際在庫數量":"總現有數量"; $("#invKpis").innerHTML=[ {l:"總庫存金額",v:fmtMoney(totVal),s:(actMode?"依實際在庫":"依現有數量")+"・"+state.whSel.size+" 個倉別"+(state.brand!=="ALL"?("・"+state.brand):"")}, {l:qtyLbl,v:fmtInt(totQty),s:"件"}, {l:"商品數",v:fmtInt(prodN),s:"不同品項"}, {l:"倉別數",v:fmtInt(state.warehouses.length),s:"全部倉庫"} ].map(function(k){return '
'+esc(k.l)+'
'+esc(k.v)+'
'+esc(k.s)+'
';}).join(""); // by brand (固定顯示全部品牌,僅受倉別篩選影響) var br={};state.lines.forEach(function(l){if(!state.whSel.has(l.warehouse))return;if(!br[l.brand])br[l.brand]={value:0,qty:0};br[l.brand].value+=lVal(l);br[l.brand].qty+=lQty(l);}); var brSorted=BRAND_ORDER.filter(function(b){return br[b];}).map(function(b){return {name:b,value:br[b].value,qty:br[b].qty};}).sort(function(a,b){return b.value-a.value;}); drawHBar($("#invBrandBar"),brSorted.map(function(d){return {name:d.name,value:d.value,color:brandColor(d.name)};}),{unit:"currency",labelW:100}); $("#invBrandTable").innerHTML='
'+ brSorted.map(function(d){return '';}).join("")+'
品牌庫存金額'+(actMode?"實際在庫":"現有")+'數量
'+esc(d.name)+''+fmtMoney(d.value)+''+fmtInt(d.qty)+'
'; // by warehouse (品牌篩選) var wh={};state.lines.forEach(function(l){if(!state.whSel.has(l.warehouse))return;if(!passBrand(l.name))return;wh[l.warehouse]=(wh[l.warehouse]||0)+lVal(l);}); var whArr=Object.keys(wh).map(function(w){return {name:w,value:wh[w]};}).sort(function(a,b){return b.value-a.value;}); drawHBar($("#invWhBar"),whArr.map(function(d,i){return {name:d.name,value:d.value,color:PALETTE[i%PALETTE.length]};}),{unit:"currency",labelW:120}); drawPie($("#invWhPie"),$("#invWhPieLeg"),whArr.map(function(d,i){return {name:d.name,value:d.value,color:PALETTE[i%PALETTE.length]};})); } // ================= 銷售 tab ================= var MONTH_ALL="__ALLM__"; function effMonths(){return state.month===MONTH_ALL?state.monthOrder.slice():[state.month];} function aggProducts(){var months=effMonths(),out={};months.forEach(function(m){var a=state.salesByMonth[m]||{};for(var nk in a){var x=pm(nk,m);var o=out[nk];if(!o){o={name:a[nk].name,qty:0,revenue:0,profit:0};out[nk]=o;}o.qty+=x.qty;o.revenue+=x.revenue;o.profit+=x.profit;}});return out;} function growthPair(){var mo=state.monthOrder;if(state.month===MONTH_ALL)return {cur:mo[mo.length-1],prev:mo[0]};return {cur:state.month,prev:prevMonth(state.month)};} function renderMonthSel(){var s=$("#monthSel");s.innerHTML=''+state.monthOrder.map(function(m){return '';}).join("");s.onchange=function(){state.month=s.value;renderSales();};} function renderSales(){ renderMonthSel(); // 每月數據表(可排序) var mrows=[],pr=null,tR=0,tQ=0,tP=0; state.monthOrder.forEach(function(m){var t=monthTotals(m);var g=pr&&pr.rev>0?((t.rev-pr.rev)/pr.rev*100):null;var pg=pr&&pr.profit>0?((t.profit-pr.profit)/pr.profit*100):null;mrows.push({m:m,rev:t.rev,qty:t.qty,profit:t.profit,g:g,margin:t.margin,pg:pg});tR+=t.rev;tQ+=t.qty;tP+=t.profit;pr=t;}); function mg(v){if(v==null)return '—';return ''+fmtPctSigned(v)+'';} var mcols=[ {k:"m",label:"月份",align:"tl",val:function(r){return monthKey(r.m);},cell:function(r){return ''+esc(r.m)+'';}}, {k:"rev",label:"營業額",align:"tr",val:function(r){return r.rev;},cell:function(r){return ''+fmtMoney(r.rev)+'';}}, {k:"qty",label:"數量",align:"tr",val:function(r){return r.qty;},cell:function(r){return ''+fmtInt(r.qty)+'';}}, {k:"profit",label:"利潤金額",align:"tr",val:function(r){return r.profit;},cell:function(r){return ''+fmtMoney(r.profit)+'';}}, {k:"g",label:"成長率",align:"tr",val:function(r){return r.g==null?-1/0:r.g;},cell:function(r){return mg(r.g);}}, {k:"margin",label:"利潤率",align:"tr",val:function(r){return r.margin;},cell:function(r){return ''+fmtPct(r.margin)+'';}}, {k:"pg",label:"利潤成長率",align:"tr",val:function(r){return r.pg==null?-1/0:r.pg;},cell:function(r){return mg(r.pg);}} ]; var mfoot='總計'+fmtMoney(tR)+''+fmtInt(tQ)+''+fmtMoney(tP)+'—'+fmtPct(tR?tP/tR*100:0)+'—'; sortTable({host:"#monthlyTable",cols:mcols,rows:mrows,sort:salesMonthSort,rerender:renderSales,empty:"尚無資料",footerHtml:mfoot}); drawLine($("#monthlyTrend"),state.monthOrder.map(function(m){return {label:m,value:monthTotals(m).rev};}),"currency"); renderBrandPies(); renderTop10(); renderHeat(); } function renderBrandPies(){ var ap=aggProducts(),br={};for(var nk in ap){var b=brandOf(ap[nk].name);if(!br[b])br[b]={rev:0,profit:0,qty:0};br[b].rev+=ap[nk].revenue;br[b].profit+=ap[nk].profit;br[b].qty+=ap[nk].qty;} function pieData(key){var arr=[],b;for(b in br){var v=br[b][key];if(v>0)arr.push({name:b,value:v,color:brandColor(b)});}return arr.sort(function(x,y){return y.value-x.value;});} drawPie($("#brandRevPie"),$("#brandRevLeg"),pieData("rev"),fmtMoney); drawPie($("#brandProfitPie"),$("#brandProfitLeg"),pieData("profit"),fmtMoney); drawPie($("#brandQtyPie"),$("#brandQtyLeg"),pieData("qty"),fmtInt); } function growthList(){ // products with prev>0, sorted by growth desc(單月=環比上月;全月加總=末月比首月) var gp=growthPair();if(!gp.prev||gp.cur===gp.prev)return [];var cur=state.salesByMonth[gp.cur]||{},prev=state.salesByMonth[gp.prev]||{};var out=[]; for(var nk in cur){if(!passBrand(cur[nk].name))continue;var pv=prev[nk];if(pv&&pv.revenue>0){out.push({name:cur[nk].name,nk:nk,growth:(cur[nk].revenue-pv.revenue)/pv.revenue*100});}} out.sort(function(a,b){return b.growth-a.growth;});return out; } function miniTable(title,rows,valFn,unit){ var body=rows.map(function(d,i){return ''+(i+1)+'. '+esc(d.name)+''+(unit==="currency"?fmtMoney(valFn(d)):fmtInt(valFn(d)))+'';}).join("")||'無資料'; return '

'+esc(title)+'

'+body+'
'; } function renderTop10(){ var ap=aggProducts(),arr=[]; for(var nk in ap){if(!passBrand(ap[nk].name))continue;arr.push({name:ap[nk].name,qty:ap[nk].qty,revenue:ap[nk].revenue,profit:ap[nk].profit});} var byQty=arr.slice().sort(function(a,b){return b.qty-a.qty;}).slice(0,10); var byRev=arr.slice().sort(function(a,b){return b.revenue-a.revenue;}).slice(0,10); var byPft=arr.slice().sort(function(a,b){return b.profit-a.profit;}).slice(0,10); $("#top10").innerHTML= miniTable("銷量前 10",byQty,function(d){return d.qty;},"int")+ miniTable("營業額前 10",byRev,function(d){return d.revenue;},"currency")+ miniTable("利潤前 10",byPft,function(d){return d.profit;},"currency"); } function heatColor(t){t=Math.max(0,Math.min(1,t));var a=[234,243,241],b=[20,82,74];return "rgb("+Math.round(a[0]+(b[0]-a[0])*t)+","+Math.round(a[1]+(b[1]-a[1])*t)+","+Math.round(a[2]+(b[2]-a[2])*t)+")";} function renderHeat(){ var L=growthList().slice(0,30); if(!L.length){$("#heatmap").innerHTML='
需有上一個月資料才能排成長率
';return;} var months=state.monthOrder;var mx=0; L.forEach(function(d){months.forEach(function(m){var s=salesOf(m,d.nk);if(s&&s.revenue>mx)mx=s.revenue;});});if(mx<=0)mx=1; var h=''+months.map(function(m){return '';}).join("")+''; L.forEach(function(d){h+='';months.forEach(function(m){var s=salesOf(m,d.nk);var v=s?s.revenue:0;var t=v/mx;var col=heatColor(t);var tc=t>0.55?"#fff":C.ink;h+='';});h+='';}); h+='
商品(成長率前30)'+esc(m.replace("2026.",""))+'成長率
'+esc(d.name)+''+(v?fmtCompact(v):"")+''+fmtPctSigned(d.growth)+'
';$("#heatmap").innerHTML=h; } // ================= 週轉 tab ================= function renderTurn(){ renderTurnTable(); } function renderTurnTable(){ var arr=[];for(var nk in state.prod){var p=state.prod[nk];if(!passBrand(p.name))continue;var t=turnoverOf(nk);arr.push({name:p.name,code:p.code,barcode:p.barcode,stock:p.stock,actual:(p.hasActual?p.actualStock:null),value:p.value,aq:avgQty3(nk),t:t});} var nWin=win3().length; $("#turnCount").textContent="共 "+arr.length+" 項"+(arr.length>80?"(依排序顯示 80 項)":"")+" · 近"+nWin+"個月均銷"; var cols=[ {k:"name",label:"品項",align:"tl",val:function(r){return r.name;},cell:function(r){return ''+esc(r.name)+'';}}, {k:"code",label:"型號",align:"tl",val:function(r){return r.code||"";},cell:function(r){return ''+esc(r.code||"-")+'';}}, {k:"barcode",label:"國際條碼",align:"tl",val:function(r){return r.barcode||"";},cell:function(r){return ''+esc(r.barcode||"-")+'';}}, {k:"actual",label:"實際在庫數量",align:"tr",val:function(r){return r.actual==null?-Infinity:r.actual;},cell:function(r){return ''+(r.actual==null?"—":fmtInt(r.actual))+'';}}, {k:"value",label:"庫存金額",align:"tr",val:function(r){return r.value;},cell:function(r){return ''+fmtMoney(r.value)+'';}}, {k:"aq",label:"近"+nWin+"月均銷",align:"tr",val:function(r){return r.aq;},cell:function(r){return ''+r.aq.toFixed(1)+'';}}, {k:"t",label:"週轉天數",align:"tr",val:function(r){return r.t==null?-1:r.t;},cell:function(r){return ''+(r.t==null?"無銷售":Math.round(r.t))+'';}} ]; sortTable({host:"#turnTable",cols:cols,rows:arr,sort:turnSort,limit:80,rerender:renderTurnTable,empty:"無資料"}); } function exportTurn(){ if(typeof XLSX==="undefined"){alert("Excel 引擎未載入");return;} var arr=[];for(var nk in state.prod){var p=state.prod[nk];if(!passBrand(p.name))continue;var t=turnoverOf(nk);arr.push({name:p.name,code:p.code,barcode:p.barcode,actual:(p.hasActual?p.actualStock:null),value:p.value,aq:avgQty3(nk),t:t});} if(!arr.length){alert("目前沒有可匯出的資料。");return;} var s=turnSort&&turnSort.k?turnSort:{k:"t",dir:-1}; arr.sort(function(a,b){var x=a[s.k],y=b[s.k];if(x==null)x=-Infinity;if(y==null)y=-Infinity;if(typeof x==="string")return s.dir*String(x).localeCompare(String(y),"zh-Hant");return s.dir*(x-y);}); var nWin=win3().length; var data=[["品項","型號","國際條碼","實際在庫數量","庫存金額","近"+nWin+"月均銷","週轉天數","健康度"]]; arr.forEach(function(d){var lvl=d.t==null?"無銷售":(d.t<=30?"健康":(d.t<=60?"注意":"偏慢"));data.push([d.name,d.code||"",d.barcode||"",(d.actual==null?"":d.actual),Math.round(d.value),Number(d.aq.toFixed(1)),(d.t==null?"":Math.round(d.t)),lvl]);}); var ws=XLSX.utils.aoa_to_sheet(data);ws["!cols"]=[{wch:40},{wch:14},{wch:16},{wch:14},{wch:12},{wch:12},{wch:10},{wch:10}]; var wb=XLSX.utils.book_new();XLSX.utils.book_append_sheet(wb,ws,"週轉分析"); XLSX.writeFile(wb,"週轉分析"+(state.brand!=="ALL"?("_"+state.brand):"")+".xlsx"); } // ================= 採購建議 tab ================= function buyList(){ var out=[];for(var nk in state.prod){var p=state.prod[nk];if(!passBrand(p.name))continue;var s3=sum3(nk);var aq=avgQty3(nk);var t=turnoverOf(nk); if(s3.qty<=0)continue; // 近N月需有銷售量 if(s3.marginstate.pTurn)continue; // 週轉天數門檻 out.push({name:p.name,barcode:p.barcode,code:p.code,stock:p.stock,actual:(p.hasActual?p.actualStock:null),aq:aq,suggest:Math.round(aq*state.pMult),margin:s3.margin,t:t});} out.sort(function(a,b){return b.suggest-a.suggest;});return out; } function renderBuy(){ var nWin=win3().length;var e1=$("#pWinLbl"),e2=$("#pWinLbl2");if(e1)e1.textContent=nWin;if(e2)e2.textContent=nWin; var L=buyList(); $("#buyCount").textContent="符合條件 "+L.length+" 項 (近 "+state.pMonths+" 個月有銷售、毛利率 ≥ "+state.pMargin+"%、週轉 ≤ "+state.pTurn+" 天)"; var cols=[ {k:"name",label:"品項名稱",align:"tl",val:function(r){return r.name;},cell:function(r){return ''+esc(r.name)+'';}}, {k:"barcode",label:"條碼",align:"tl",val:function(r){return r.barcode||"";},cell:function(r){return ''+esc(r.barcode||"-")+'';}}, {k:"code",label:"型號",align:"tl",val:function(r){return r.code||"";},cell:function(r){return ''+esc(r.code||"-")+'';}}, {k:"actual",label:"實際在庫數量",align:"tr",val:function(r){return r.actual==null?-Infinity:r.actual;},cell:function(r){return ''+(r.actual==null?"—":fmtInt(r.actual))+'';}}, {k:"aq",label:"近"+win3().length+"月均銷",align:"tr",val:function(r){return r.aq;},cell:function(r){return ''+r.aq.toFixed(1)+'';}}, {k:"margin",label:"毛利率",align:"tr",val:function(r){return r.margin;},cell:function(r){return ''+fmtPct(r.margin)+'';}}, {k:"t",label:"週轉天數",align:"tr",val:function(r){return r.t==null?-1:r.t;},cell:function(r){return ''+Math.round(r.t)+'';}}, {k:"suggest",label:"建議採購量",align:"tr",val:function(r){return r.suggest;},cell:function(r){return ''+fmtInt(r.suggest)+'';}} ]; sortTable({host:"#buyTable",cols:cols,rows:L,sort:buySort,rerender:renderBuy,empty:"沒有符合條件的商品,可放寬門檻"}); } function exportBuy(){ if(typeof XLSX==="undefined"){alert("Excel 引擎未載入");return;} var L=buyList();if(!L.length){alert("目前沒有符合條件的商品可匯出。");return;} var data=[["品項名稱","條碼","型號","實際在庫數量","建議採購量"]];L.forEach(function(d){data.push([d.name,d.barcode||"",d.code||"",(d.actual==null?"":d.actual),d.suggest]);}); var ws=XLSX.utils.aoa_to_sheet(data);ws["!cols"]=[{wch:40},{wch:16},{wch:14},{wch:10},{wch:12}]; var wb=XLSX.utils.book_new();XLSX.utils.book_append_sheet(wb,ws,"採購建議"); XLSX.writeFile(wb,"採購建議_"+(state.month||"").replace(/[^0-9]/g,"")+".xlsx"); } // ================= 庫存數據(原始資料)================= function renderRawSelectors(){ var ws=$("#rawWhSel");ws.innerHTML=''+state.warehouses.map(function(w){return '';}).join("");ws.value=state.rawWh; } function renderRaw(){ renderRawSelectors(); var kws=String(state.rawKw||"").trim().split(/\s+/).map(norm).filter(Boolean); function baseMatch(l){ if(!passBrand(l.name))return false; if(kws.length){var hay=norm((l.name||"")+" "+(l.barcode||"")+" "+(l.code||"")+" "+(l.rawCat||"")+" "+(l.warehouse||"")+" "+(l.brand||""));for(var i=0;i0?o.value/o.qty:0;o.whLabel=Object.keys(o.whs).length+" 倉合計";rows.push(o);} } else { state.lines.forEach(function(l){if(!baseMatch(l))return;if(state.rawWh!=="ALL"&&l.warehouse!==state.rawWh)return;rows.push({name:l.name,brand:l.brand,barcode:l.barcode,code:l.code,qty:l.qty,actual:l.actual,cost:l.cost,value:l.value,rawCat:l.rawCat,whLabel:l.warehouse});}); } var total=rows.length,cap=1500,sumQty=0,sumVal=0;rows.forEach(function(r){sumQty+=r.qty;sumVal+=r.value;}); $("#rawSummary").innerHTML= '
'+(merged?"合併品項數":"篩選筆數")+''+fmtInt(total)+'
'+ '
總數量'+fmtInt(sumQty)+'
'+ '
總庫存金額'+fmtMoney(sumVal)+'
'; $("#rawCount").textContent="共 "+total+" 筆"+(merged?"(同品名+型號已合併加總)":"")+(total>cap?("(依排序顯示前 "+cap+" 筆)"):""); var cols=[ {k:"name",label:"品名規格",align:"tl",val:function(r){return r.name;},cell:function(r){return ''+esc(r.name)+'';}}, {k:"brand",label:"品牌",align:"tl",val:function(r){return r.brand||"";},cell:function(r){return ''+esc(r.brand||"-")+'';}}, {k:"barcode",label:"條碼編號",align:"tl",val:function(r){return r.barcode||"";},cell:function(r){return ''+esc(r.barcode||"-")+'';}}, {k:"code",label:"產品編號",align:"tl",val:function(r){return r.code||"";},cell:function(r){return ''+esc(r.code||"-")+'';}}, {k:"qty",label:"現有數量",align:"tr",val:function(r){return r.qty;},cell:function(r){return ''+fmtInt(r.qty)+'';}}, {k:"actual",label:"實際在庫數量",align:"tr",val:function(r){return r.actual==null?-Infinity:r.actual;},cell:function(r){return ''+(r.actual==null?"—":fmtInt(r.actual))+'';}}, {k:"cost",label:"平均成本",align:"tr",val:function(r){return r.cost;},cell:function(r){return ''+(Math.round(r.cost*100)/100).toLocaleString("en-US")+'';}}, {k:"value",label:"總成本",align:"tr",val:function(r){return r.value;},cell:function(r){return ''+fmtInt(r.value)+'';}}, {k:"whLabel",label:"倉庫名稱",align:"tl",val:function(r){return r.whLabel;},cell:function(r){return ''+esc(r.whLabel)+'';}}, {k:"rawCat",label:"類別名稱",align:"tl",val:function(r){return r.rawCat||"";},cell:function(r){return ''+esc(r.rawCat||"-")+'';}} ]; sortTable({host:"#rawTable",cols:cols,rows:rows,sort:rawSort,limit:cap,rerender:renderRaw,empty:"沒有符合條件的資料"}); } // ================= 載入輔助 ================= function finishLoad(msg){rebuildMeta();renderActive();if(msg)setStatus(msg,false);checkSetup();} function setStatus(msg,warn){var el=$("#importStatus");el.textContent=msg;el.className=warn?"warn":"";} function checkSetup(){if(typeof XLSX==="undefined"){$("#setupNotice").innerHTML='
尚未偵測到 Excel 引擎。請下載 xlsx.full.min.js 放到與本檔同一資料夾後重新整理:https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
';}else{$("#setupNotice").innerHTML="";}} // tabs document.querySelectorAll(".tabs button").forEach(function(b){b.onclick=function(){state.tab=b.getAttribute("data-tab");document.querySelectorAll(".tabs button").forEach(function(x){x.classList.toggle("on",x===b);});document.querySelectorAll(".panel").forEach(function(p){p.classList.remove("on");});$("#panel-"+state.tab).classList.add("on");renderActive();};}); // 資料匯入可收摺 function setImpCollapsed(c){var b=$("#impBody"),ch=$("#impChevron");if(b)b.style.display=c?"none":"block";if(ch)ch.textContent=c?"▼":"▲";} $("#impToggle").addEventListener("click",function(){setImpCollapsed($("#impBody").style.display!=="none");}); // 品牌篩選(所有頁面共用同一選擇) function brandOptsHtml(){return ''+BRAND_ORDER.map(function(b){return '';}).join("");} function syncBrandSelects(){var a=document.querySelectorAll(".brandSel");for(var i=0;i=1)?Math.min(24,v):3;this.value=state.avgMonths;renderPrice();}); $("#priceExport").addEventListener("click",exportPrice); $("#priceExportHTML").addEventListener("click",exportPriceHTML); // purchase controls function readThr(){state.pMonths=Math.max(1,Math.min(6,parseInt($("#pMonths").value)||3));state.pMargin=parseFloat($("#pMargin").value)||0;state.pTurn=parseFloat($("#pTurn").value)||30;var mv=parseFloat($("#pMult").value);state.pMult=(isFinite(mv)&&mv>=0)?mv:3;} $("#pApply").addEventListener("click",function(){readThr();renderBuy();}); $("#pExport").addEventListener("click",function(){readThr();exportBuy();}); $("#tAvgMonths").addEventListener("change",function(){var v=parseInt(this.value);state.avgMonths=(isFinite(v)&&v>=1)?Math.min(24,v):3;this.value=state.avgMonths;renderActive();}); $("#turnExport").addEventListener("click",exportTurn); var rt;window.addEventListener("resize",function(){clearTimeout(rt);rt=setTimeout(renderActive,160);}); // ---------------- 範本下載(離線產生 .xlsx)---------------- function dlInvTpl(){ if(typeof XLSX==="undefined"){alert("Excel 引擎未載入,無法產生範本。");return;} var d=[["品名規格","條碼編號","產品編號","現有數量","實際在庫數量","平均成本","總成本","倉庫名稱","類別名稱"], ["寵物玩具-麻繩球","4710001","TOY-001",200,198,35,7000,"MIT","寵物玩具"], ["寵物玩具-麻繩球","4710001","TOY-001",120,120,35,4200,"總倉","寵物玩具"], ["寵物服飾-毛衣M","4710011","CLO-001",90,88,120,10800,"MIT","寵物服飾"], ["包裝材料-紙箱S","4710021","PKG-001",800,800,7,5600,"長興12-9","包裝材料"]]; var note=[["庫存範本 填寫說明"],[""], ["1. 類別請直接填在『類別名稱』欄(這是分類的依據);若該欄留空,工具才會改用品名『-』前綴自動判定。"], ["2. 同一產品分散多倉時,每個倉各填一列(如上方『麻繩球』在 MIT 與 總倉 各一列)。"], ["3. 總成本 = 現有數量 × 平均成本(沒填總成本時工具會自動以數量×平均成本計算)。"], ["4. 欄位標題那一列請勿更動名稱;標題上方若有公司名稱/報表抬頭等列,工具會自動略過。"], ["5. 條碼編號、產品編號可留空,但建議至少填產品編號(採購建議的『型號』會用它)。"]]; var wb=XLSX.utils.book_new(); var ws=XLSX.utils.aoa_to_sheet(d);ws["!cols"]=[{wch:26},{wch:14},{wch:12},{wch:10},{wch:12},{wch:10},{wch:10},{wch:14},{wch:14}]; XLSX.utils.book_append_sheet(wb,ws,"Page1"); XLSX.utils.book_append_sheet(wb,XLSX.utils.aoa_to_sheet(note),"說明"); XLSX.writeFile(wb,"庫存範本_分倉.xlsx"); } function dlSalesTpl(){ if(typeof XLSX==="undefined"){alert("Excel 引擎未載入,無法產生範本。");return;} var months=["2026.01月","2026.02月","2026.03月"]; var rows={ "2026.01月":[["寵物玩具-麻繩球","4710001",10,99,990],["寵物服飾-毛衣M","4710011",4,299,1196],["包裝材料-紙箱S","4710021",300,20,6000]], "2026.02月":[["寵物玩具-麻繩球","4710001",12,99,1188],["寵物服飾-毛衣M","4710011",5,299,1495],["包裝材料-紙箱S","4710021",320,20,6400]], "2026.03月":[["寵物玩具-麻繩球","4710001",15,99,1485],["寵物服飾-毛衣M","4710011",3,299,897],["包裝材料-紙箱S","4710021",310,20,6200]]}; var note=[["銷售範本 填寫說明"],[""], ["1. 每個月一個分頁,分頁名稱用『年.月』格式,例如 2026.01月、2026.02月…工具會自動依序排列。"], ["2. 『產品名稱』需與庫存的『品名規格』寫法一致,工具才能對應到成本與類別。"], ["3. 每筆交易一列即可,工具會自動依產品彙總當月數量與營業額。"], ["4. 含稅金額 = 數量 × 單價(沒填金額時工具會自動以數量×單價計算)。"], ["5. 要新增月份:在下方分頁標籤上按右鍵 →『移動或複製』→ 勾選『建立複本』→ 再把分頁改名成新月份。"]]; var wb=XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb,XLSX.utils.aoa_to_sheet(note),"說明"); months.forEach(function(m){var d=[["產品名稱","條碼編號","數量","單價","含稅金額"]].concat(rows[m]);var ws=XLSX.utils.aoa_to_sheet(d);ws["!cols"]=[{wch:26},{wch:14},{wch:8},{wch:8},{wch:12}];XLSX.utils.book_append_sheet(wb,ws,m);}); XLSX.writeFile(wb,"銷售範本.xlsx"); } function dlChanTpl(){ if(typeof XLSX==="undefined"){alert("Excel 引擎未載入,無法產生範本。");return;} var wb=XLSX.utils.book_new(); var note=[["通路銷售範本 填寫說明"],[""], ["1. 每個月一個分頁,分頁名稱用『N月』,例如 1月、2月…(要跨年度做 YoY 比較,可用『2025.6月』『2026.6月』等含年份的名稱)。"], ["2. 另需一個『客戶分類表』分頁:用『客戶/廠商編號』把每個客戶對應到 通路名稱/通路類型/線上線下分類/自有或合作分類。"], ["3. 月份分頁與分類表以『客戶/廠商編號』對照;同一通路的多個門市(不同編號)會依分類表歸成同一個通路名稱。"], ["4. 『品名規格』需與庫存的『品名規格』一致,才能帶入成本計算毛利。原幣金額=業績金額(未稅)。"], ["5. 分類表『通路名稱』留空的客戶,會以『客戶全稱』單獨呈現、類型顯示未分類。"]]; XLSX.utils.book_append_sheet(wb,XLSX.utils.aoa_to_sheet(note),"說明"); var mHead=["日期","產品編號","品名規格","數量","稅額","原幣單價","原幣金額","客戶/廠商編號","客戶全稱","部門名稱","人員姓名"]; var mRows={ "1月":[["2026/1/5","6153-B001","寵物玩具-麻繩球",10,50,99,990,"FA0001-P0001","大樹寵物八德店","",""],["2026/1/8","6153-C002","寵物窩-PETSNOWY雪屋",2,80,899,1798,"EC001","蝦皮商城","",""]], "2月":[["2026/2/3","6153-B001","寵物玩具-麻繩球",12,60,99,1188,"FA0002","誠品信義","",""]]}; ["1月","2月"].forEach(function(m){var d=[mHead].concat(mRows[m]);var ws=XLSX.utils.aoa_to_sheet(d);ws["!cols"]=[{wch:11},{wch:12},{wch:24},{wch:7},{wch:8},{wch:10},{wch:11},{wch:16},{wch:20},{wch:12},{wch:10}];XLSX.utils.book_append_sheet(wb,ws,m);}); var cHead=["客戶/廠商編號","客戶全稱","部門名稱","人員姓名","通路名稱","通路類型","線上線下分類","自有或合作分類"]; var cRows=[ ["FA0001-P0001","大樹寵物八德店","","","大樹","寵物連鎖","線下","合作"], ["FA0001-P0002","大樹寵物宜蘭店","","","大樹","寵物連鎖","線下","合作"], ["EC001","蝦皮商城","電商部","","蝦皮","EC","線上","自有"], ["EC002","MOMO購物","電商部","","MOMO","EC","線上","自有"], ["FA0002","誠品信義","","","誠品","人通連鎖","線下","合作"]]; var cws=XLSX.utils.aoa_to_sheet([cHead].concat(cRows));cws["!cols"]=[{wch:16},{wch:22},{wch:12},{wch:10},{wch:12},{wch:12},{wch:12},{wch:14}]; XLSX.utils.book_append_sheet(wb,cws,"客戶分類表"); XLSX.writeFile(wb,"通路銷售範本.xlsx"); } $("#btnInvTpl").addEventListener("click",dlInvTpl); $("#btnSalesTpl").addEventListener("click",dlSalesTpl); $("#btnChanTpl").addEventListener("click",dlChanTpl); (function(){var vb=$("#verBadge");if(vb)vb.textContent=APP_VERSION;})(); document.body.classList.add("nodata");checkSetup(); })();
20260806-V3