PageSourceSearch

https://wedraw.kr/assets/WoodOrderAnalysisPage.Bc7DElmz.js

js wedraw.kr collected 2026-10-04 07:44:02 UTC 27,519 bytes, 1 lines download raw bytes

1import{j as e}from"./vendor-ui.BwPBmVwt.js";import{r as f}from"./vendor-react.kR8tqwKZ.js";import{B as S,X as Q,s as V}from"./index.86ltQqcV.js";import{I as Z}from"./input.Bn8hRSEL.js";import{R as q,f as H,X,Y as J,T as z,B as U,g as ee,d as B,P as te,c as se}from"./admin.DlinAKoh.js";import{C as ae}from"./chevron-left.C8eB59fV.js";import{C as ne}from"./chevron-right.BO4QQ722.js";import{f as v,Y as re,s as M}from"./vendor-utils.D2q0l15H.js";import{H as ie}from"./hammer.DvxjaW02.js";import{L as A}from"./loader-circle.PPp0m7l9.js";import{R as oe}from"./refresh-cw.BJ6elI4y.js";import{S as ce}from"./search.CoLV_vkF.js";import{D as le}from"./database.C0RVhMlI.js";import{k as C}from"./ko.CSP0_8Uo.js";import"./vendor-three.C5-HLXBy.js";const R=["#3b82f6","#6366f1","#8b5cf6","#a855f7","#d946ef","#ec4899","#f43f5e","#ef4444","#f97316","#eab308"];function de({rankings:s}){const a=s.slice(0,10).map((n,r)=>({name:`${n.woodType} (${n.thickness})`,count:n.orderCount,qty:n.totalQuantity,pct:n.percentage.toFixed(1),idx:r}));return e.jsxs("div",{className:"bg-white rounded-lg border p-4",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-700 mb-3",children:"목재 종류+두께 랭킹 (건수 기준 Top 10)"}),a.length===0?e.jsx("p",{className:"text-sm text-gray-400 text-center py-8",children:"데이터를 업로드해주세요"}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-[260px]",children:e.jsx(q,{width:"100%",height:"100%",children:e.jsxs(H,{data:a,layout:"vertical",margin:{left:0,right:12},children:[e.jsx(X,{type:"number",fontSize:11,tickLine:!1}),e.jsx(J,{type:"category",dataKey:"name",width:140,fontSize:11,tickLine:!1}),e.jsx(z,{formatter:(n,r)=>r==="count"?[`${n.toLocaleString()}건`,"건수"]:[n,r]}),e.jsxs(U,{dataKey:"count",radius:[0,4,4,0],barSize:18,children:[e.jsx(ee,{dataKey:"count",position:"right",fontSize:10,formatter:n=>n.toLocaleString()}),a.map((n,r)=>e.jsx(B,{fill:R[r%R.length]},r))]})]})})}),e.jsx("div",{className:"mt-3 max-h-[1000px] overflow-y-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"text-gray-500 border-b sticky top-0 bg-white",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left py-1 font-medium",children:"순위"}),e.jsx("th",{className:"text-left py-1 font-medium",children:"목재 (두께)"}),e.jsx("th",{className:"text-right py-1 font-medium",children:"건수"}),e.jsx("th",{className:"text-right py-1 font-medium",children:"수량합"}),e.jsx("th",{className:"text-right py-1 font-medium",children:"비율"})]})}),e.jsx("tbody",{children:s.map((n,r)=>e.jsxs("tr",{className:"border-b border-gray-50",children:[e.jsx("td",{className:"py-1 text-gray-400",children:r+1}),e.jsxs("td",{className:"py-1",children:[n.woodType,n.thickness?` (${n.thickness})`:""]}),e.jsx("td",{className:"py-1 text-right font-medium",children:n.orderCount.toLocaleString()}),e.jsx("td",{className:"py-1 text-right text-gray-500",children:n.totalQuantity.toLocaleString()}),e.jsxs("td",{className:"py-1 text-right text-gray-500",children:[n.percentage.toFixed(1),"%"]})]},r))})]})})]})]})}const me=["#3b82f6","#e5e7eb"],W=["#6366f1","#8b5cf6","#a855f7","#d946ef","#ec4899","#f43f5e","#ef4444","#f97316","#eab308","#22c55e"];function he({ratio:s}){const t=[{name:"가공 포함",value:s.withProcessing},{name:"가공 미포함",value:s.withoutProcessing}];return e.jsxs("div",{className:"bg-white rounded-lg border p-4",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-700 mb-3",children:"가공 포함 비율"}),s.totalOrders===0?e.jsx("p",{className:"text-sm text-gray-400 text-center py-8",children:"데이터를 업로드해주세요"}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("div",{className:"h-[140px] w-[140px] flex-shrink-0",children:e.jsx(q,{width:"100%",height:"100%",children:e.jsxs(te,{children:[e.jsx(se,{data:t,cx:"50%",cy:"50%",innerRadius:35,outerRadius:60,dataKey:"value",strokeWidth:0,children:t.map((a,n)=>e.jsx(B,{fill:me[n]},n))}),e.jsx(z,{formatter:a=>[`${a.toLocaleString()}건`]})]})})}),e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-3 h-3 rounded-full bg-blue-500 inline-block"}),e.jsx("span",{className:"text-gray-600",children:"가공 포함:"}),e.jsxs("span",{className:"font-semibold",children:[s.withProcessing.toLocaleStr
1ing(),"건"]}),e.jsxs("span",{className:"text-blue-600 font-medium",children:["(",s.withProcessingPercent.toFixed(1),"%)"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-3 h-3 rounded-full bg-gray-200 inline-block"}),e.jsx("span",{className:"text-gray-600",children:"가공 미포함:"}),e.jsxs("span",{className:"font-semibold",children:[s.withoutProcessing.toLocaleString(),"건"]}),e.jsxs("span",{className:"text-gray-500",children:["(",(100-s.withProcessingPercent).toFixed(1),"%)"]})]}),e.jsxs("div",{className:"text-xs text-gray-400 mt-1",children:["전체 ",s.totalOrders.toLocaleString(),"건"]})]})]}),e.jsxs("div",{className:"mt-4 border-t pt-3",children:[e.jsx("h4",{className:"text-xs font-semibold text-gray-500 mb-2",children:"가공 옵션별 건수"}),e.jsxs("div",{className:"space-y-1.5 max-h-[1000px] overflow-y-auto",children:[s.perOptionBreakdown.map((a,n)=>e.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full flex-shrink-0",style:{backgroundColor:W[n%W.length]}}),e.jsx("span",{className:"flex-1 text-gray-700 truncate",children:a.name}),e.jsxs("span",{className:"font-medium tabular-nums",children:[a.count.toLocaleString(),"건"]}),e.jsxs("span",{className:"text-gray-400 tabular-nums w-14 text-right",children:[a.percentage.toFixed(1),"%"]})]},a.name)),s.perOptionBreakdown.length===0&&e.jsx("p",{className:"text-gray-400",children:"가공 데이터 없음"})]})]})]})]})}function ue({ranges:s}){return e.jsxs("div",{className:"bg-white rounded-lg border p-4",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-700 mb-3",children:"가공별 입력 치수 범위"}),s.length===0?e.jsx("p",{className:"text-sm text-gray-400 text-center py-8",children:"데이터를 업로드해주세요"}):e.jsx("div",{className:"overflow-x-auto max-h-[1000px] overflow-y-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"text-gray-500 border-b sticky top-0 bg-white",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left py-1.5 font-medium",children:"가공명"}),e.jsx("th",{className:"text-right py-1.5 font-medium",children:"목재 가로"}),e.jsx("th",{className:"text-right py-1.5 font-medium",children:"목재 세로"}),e.jsx("th",{className:"text-left py-1.5 font-medium pl-4",children:"옵션 치수 범위"}),e.jsx("th",{className:"text-right py-1.5 font-medium",children:"건수"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{className:"border-b border-gray-50 hover:bg-gray-50 align-top",children:[e.jsx("td",{className:"py-1.5 font-medium text-gray-700",children:t.processingName}),e.jsxs("td",{className:"py-1.5 text-right tabular-nums text-gray-500",children:[t.minWidth.toLocaleString(),"~",t.maxWidth.toLocaleString(),"mm"]}),e.jsxs("td",{className:"py-1.5 text-right tabular-nums text-gray-500",children:[t.minLength.toLocaleString(),"~",t.maxLength.toLocaleString(),"mm"]}),e.jsx("td",{className:"py-1.5 pl-4",children:t.paramRanges.length>0?e.jsx("div",{className:"space-y-0.5",children:t.paramRanges.map(a=>e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("span",{className:"text-gray-500",children:[a.label,":"]}),e.jsx("span",{className:"tabular-nums font-medium",children:a.min===a.max?`${a.min}mm`:`${a.min}~${a.max}mm`})]},a.label))}):e.jsx("span",{className:"text-gray-300",children:"-"})}),e.jsx("td",{className:"py-1.5 text-right font-medium text-blue-600",children:t.sampleCount.toLocaleString()})]},t.processingName))})]})})]})}function xe({rankings:s,ratio:t,ranges:a}){return e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-4",children:[e.jsx(de,{rankings:s}),e.jsx(he,{ratio:t}),e.jsx(ue,{ranges:a})]})}const L=30;function pe({data:s}){const[t,a]=f.useState(0),[n,r]=f.useState("date"),[o,i]=f.useState("desc"),c=f.useMemo(()=>[...s].sort((m,y)=>{const w=m[n],N=y[n];if(typeof w=="number"&&typeof N=="number")return o==="asc"?w-N:N-w;const j=String(w??""),k=String(N??"");return o==="asc"?j.localeCompare(k):k.localeCompare(j)}
1),[s,n,o]),d=Math.ceil(c.length/L),l=c.slice(t*L,(t+1)*L),h=m=>{n===m?i(y=>y==="asc"?"desc":"asc"):(r(m),i("desc")),a(0)},x=({label:m,field:y})=>e.jsxs("th",{className:"py-2 px-2 font-medium text-left cursor-pointer hover:text-blue-600 select-none whitespace-nowrap",onClick:()=>h(y),children:[m,n===y&&e.jsx("span",{className:"ml-0.5 text-blue-500",children:o==="asc"?"↑":"↓"})]}),p=m=>{if(!m)return"-";const y=new Date(m);return isNaN(y.getTime())?m.slice(0,10):y.toLocaleDateString("ko-KR",{year:"numeric",month:"2-digit",day:"2-digit"})};return e.jsxs("div",{className:"bg-white rounded-lg border",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b",children:[e.jsxs("h3",{className:"text-sm font-semibold text-gray-700",children:["상세 데이터 ",e.jsxs("span",{className:"text-gray-400 font-normal",children:["(",s.length.toLocaleString(),"건)"]})]}),e.jsxs("div",{className:"flex items-center gap-2 text-xs text-gray-500",children:[e.jsxs("span",{children:[t+1," / ",Math.max(d,1)," 페이지"]}),e.jsx(S,{variant:"outline",size:"sm",disabled:t===0,onClick:()=>a(m=>m-1),className:"h-7 w-7 p-0",children:e.jsx(ae,{className:"w-4 h-4"})}),e.jsx(S,{variant:"outline",size:"sm",disabled:t>=d-1,onClick:()=>a(m=>m+1),className:"h-7 w-7 p-0",children:e.jsx(ne,{className:"w-4 h-4"})})]})]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"text-gray-500 bg-gray-50 border-b",children:e.jsxs("tr",{children:[e.jsx(x,{label:"소스",field:"sourceType"}),e.jsx(x,{label:"주문코드",field:"orderCode"}),e.jsx(x,{label:"날짜",field:"date"}),e.jsx(x,{label:"고객명",field:"customerName"}),e.jsx(x,{label:"목재종류",field:"woodType"}),e.jsx(x,{label:"두께",field:"thickness"}),e.jsx(x,{label:"가로(mm)",field:"width"}),e.jsx(x,{label:"세로(mm)",field:"length"}),e.jsx(x,{label:"수량",field:"quantity"}),e.jsx("th",{className:"py-2 px-2 font-medium text-left whitespace-nowrap",children:"가공"}),e.jsx("th",{className:"py-2 px-2 font-medium text-left whitespace-nowrap",children:"가공내용"}),e.jsx(x,{label:"금액",field:"price"})]})}),e.jsx("tbody",{children:l.length===0?e.jsx("tr",{children:e.jsx("td",{colSpan:12,className:"text-center py-12 text-gray-400",children:"데이터를 업로드해주세요"})}):l.map((m,y)=>e.jsxs("tr",{className:"border-b border-gray-50 hover:bg-gray-50",children:[e.jsx("td",{className:"py-1.5 px-2",children:e.jsx("span",{className:`inline-block px-1.5 py-0.5 rounded text-[10px] font-medium ${m.sourceType==="ln_order_requests"?"bg-blue-50 text-blue-600":"bg-orange-50 text-orange-600"}`,children:m.sourceType==="ln_order_requests"?"LN":"OD"})}),e.jsx("td",{className:"py-1.5 px-2 font-mono text-gray-500 truncate max-w-[120px]",children:m.orderCode}),e.jsx("td",{className:"py-1.5 px-2 whitespace-nowrap",children:p(m.date)}),e.jsx("td",{className:"py-1.5 px-2",children:m.customerName}),e.jsx("td",{className:"py-1.5 px-2 font-medium",children:m.woodType}),e.jsx("td",{className:"py-1.5 px-2 tabular-nums",children:m.thickness}),e.jsx("td",{className:"py-1.5 px-2 tabular-nums text-right",children:m.width.toLocaleString()}),e.jsx("td",{className:"py-1.5 px-2 tabular-nums text-right",children:m.length.toLocaleString()}),e.jsx("td",{className:"py-1.5 px-2 tabular-nums text-right",children:m.quantity.toLocaleString()}),e.jsx("td",{className:"py-1.5 px-2",children:m.hasProcessing?e.jsx("span",{className:"text-blue-600 font-medium",children:"O"}):e.jsx("span",{className:"text-gray-300",children:"-"})}),e.jsx("td",{className:"py-1.5 px-2 text-gray-500 truncate max-w-[200px]",children:m.processingList.map(w=>w.name).join(", ")||"-"}),e.jsx("td",{className:"py-1.5 px-2 tabular-nums text-right",children:m.price.toLocaleString()})]},`${m.sourceType}-${m.sourceId}-${y}`))})]})})]})}const fe={모서리라운딩:"코너 라운딩",절단면라운딩:"엣지 라운드/사선",사각타공:"기본 사각형",원형타공:"기본 원형",피스타공:"피스 타공",두께홈따기:"반턱 가공",밑단홈파기:"윗면 홈파기",두께홈파기:"옆면 홈파기",원형컷팅:"원형 컷팅",원형커팅:"원형 컷팅","모양 컷팅":"원형 컷팅",모양컷팅:"원형 컷팅",모서리사선컷팅:"액자 컷팅",액자컷팅:"액자 컷팅",액자커팅:"액자 컷팅",씽크대보링:"싱크 경첩 가공","씽크 경첩 가공":"싱크 경첩 가공","씽크 경첩 패널":"싱크 경첩 가공","싱크 경첩 패널":"싱크 경첩 가공"};function F(s){return fe[s]||s}const ge={미송집성목:"미송 집성목",멀바우집성목:"멀바우 집성목",삼나무집성목:"삼나무 집성목",아카시아집성목:"아카시아 집성목",고무나무집성목:"고무나무 집성목","히노끼집성목 무절":"히노끼 집성목",레드파인집성목:"레드파인 집성목",스프러스집성목:"스프러스 집성목",애쉬집성목:"애쉬 집성목",엘더집성목:"엘더 집성목",라왕집성목:"라왕 집성목","프리미엄 자작나무 합판":"자작나무 합판","무취무절 프리미엄 미송합판":"미송 합판","인코아 합판":"코아 합판","낙엽송합판 라취엠보":"낙엽송 합판","OSB 합판":"OSB 보드"},ye=["피스","꺽쇠","경첩","받침대","사포","본드","컨디셔너","스테인","바니쉬"];function je(s){return ye.some(t=>s.includes(t))}function Ne(s){return ge[s]||s}function be(s){const t=s.match(/^([\d.]+)T$/);return t?`${t[1]}mm`:s}function we(s){return s.filter(t=>!je(t.woodType)).map(t=>({...t,woodType:Ne(t.woodType),thickness:be(t.thickness)}))}function ve(s){const t=new Map;for(const r of s){const o=`${r.woodType}||${r.thickness}`,i=t.get(o);i?(i.orderCount+=1,i.totalQuantity+=r.quantity):t.set(o,{orderCount:1,totalQuantity:r.quantity})}const a=s.length,n=[];for(const[r,o]of t.entries()){const[i,c]=r.split("||");n.push({woodType:i,thickness:c,orderCount:o.orderCount,totalQuantity:o.totalQuantity,percentage:a>0?o.orderCount/a*100:0})}return n.sort((r,o)=>o.orderCount-r.orderCount)}function Se(s){const t=s.length,a=s.filter(i=>
1i.hasProcessing).length,n=t-a,r=new Map;for(const i of s)if(i.hasProcessing)for(const c of i.processingList){if(!c.name)continue;const d=F(c.name);r.set(d,(r.get(d)||0)+1)}const o=[];for(const[i,c]of r.entries())o.push({name:i,count:c,percentage:a>0?c/a*100:0});return o.sort((i,c)=>c.count-i.count),{totalOrders:t,withProcessing:a,withoutProcessing:n,withProcessingPercent:t>0?a/t*100:0,perOptionBreakdown:o}}const _={radius:"반지름",batchRadius:"반지름",radiusA:"반지름",radiusB:"반지름",radiusC:"반지름",radiusD:"반지름",diameter:"지름",sizeC:"가로 크기",sizeD:"세로 크기",depth:"깊이",depthA:"깊이",depthB:"깊이",depthC:"깊이",depthD:"깊이",widthA:"폭",widthB:"폭",widthC:"폭",widthD:"폭",shapeWidth:"가로 크기",shapeLength:"세로 크기",batchLength:"길이",batchWidth:"폭",lengthA:"길이",lengthB:"길이",lengthC:"길이",lengthD:"길이",size:"크기",spacing:"간격",width:"폭"},T=new Set(["notes","enableA","enableB","enableC","enableD","enableAll","positions","surface","position","processingType","direction","faceSanding","faceEdgeSanding","sideSanding","cuttingType","shapeType","drillingInfo","kind","edge","positionA","positionB"]);function ke(s){if(!s)return[];const t=[];if("details"in s&&typeof s.details=="string"){const n=s.details.matchAll(/([가-힣A-Za-z\s]+):\s*([\d.]+)(?:mm)?/g);for(const r of n){const o=r[1].trim(),i=parseFloat(r[2]);!isNaN(i)&&i>0&&!o.includes("위치")&&!o.includes("방향")&&t.push({label:o,value:i})}return t}const a=s;for(const[n,r]of Object.entries(a)){if(T.has(n))continue;if(n==="processingItems"){const c=Array.isArray(r)?r:$(r);if(c){for(const d of c)if(!(typeof d!="object"||!d))for(const[l,h]of Object.entries(d)){if(T.has(l))continue;const x=_[l];if(!x)continue;const p=Number(h);!isNaN(p)&&p>0&&t.push({label:x,value:p})}}continue}if(n==="edgeItems"){const c=Array.isArray(r)?r:$(r);if(c){for(const d of c)if(!(typeof d!="object"||!d))for(const[l,h]of Object.entries(d)){if(T.has(l))continue;const x=_[l];if(!x)continue;const p=Number(h);!isNaN(p)&&p>0&&t.push({label:x,value:p})}}continue}if(n==="grooves"){const c=typeof r=="object"&&r?r:Ce(r);if(c){for(const d of Object.values(c))if(Array.isArray(d))for(const l of d){if(typeof l!="object"||!l)continue;const h=l,x=Number(h.width),p=Number(h.depth);!isNaN(x)&&x>0&&t.push({label:"폭",value:x}),!isNaN(p)&&p>0&&t.push({label:"깊이",value:p})}}continue}if(n==="hingePositions")continue;const o=_[n];if(!o)continue;const i=Number(r);!isNaN(i)&&i>0&&t.push({label:o,value:i})}return t}function $(s){if(typeof s!="string")return null;try{const t=JSON.parse(s);return Array.isArray(t)?t:null}catch{return null}}function Ce(s){if(typeof s!="string")return null;try{const t=JSON.parse(s);return typeof t=="object"&&t?t:null}catch{return null}}const Le={"코너 라운딩":new Set(["반지름"]),"윗면 홈파기":new Set(["폭","깊이"]),"반턱 가공":new Set(["폭","깊이"]),"옆면 홈파기":new Set(["폭","깊이"])};function _e(s){const t=new Map;for(const n of s)if(n.hasProcessing)for(const r of n.processingList){if(!r.name)continue;const o=F(r.name);let i=t.get(o);i||(i={minW:n.width,maxW:n.width,minL:n.length,maxL:n.length,count:0,paramMap:new Map},t.set(o,i)),i.minW=Math.min(i.minW,n.width),i.maxW=Math.max(i.maxW,n.width),i.minL=Math.min(i.minL,n.length),i.maxL=Math.max(i.maxL,n.length),i.count+=1;const c=Le[o];if(!c)continue;const d=ke(r.params);for(const l of d){if(!c.has(l.label))continue;const h=i.paramMap.get(l.label);h?(h.min=Math.min(h.min,l.value),h.max=Math.max(h.max,l.value),h.count+=1):i.paramMap.set(l.label,{min:l.value,max:l.value,count:1})}}const a=[];for(const[n,r]of t.entries()){const o=[];for(const[i,c]of r.paramMap.entries())o.push({label:i,min:c.min,max:c.max,count:c.count});o.sort((i,c)=>c.count-i.count),a.push({processingName:n,minWidth:r.minW,maxWidth:r.maxW,minLength:r.minL,maxLength:r.maxL,sampleCount:r.count,paramRanges:o})}return a.sort((n,r)=>r.sampleCount-n.sampleCount)}const Te=["솔리드 무광","솔리드 유광","세라믹","우드"];function E(s){return s?Te.some(t=>s.includes(t)):!1}function Pe(s){if(!s)return{woodType:"",thickness:""};let t=s.replace(/^\d+\)\s*/,"");t=t.replace(/\[.*?\]\s*/g,"");const a=t.match(/^(.+?)\s*\(([\d.]+T)\)\s*(.*)$/);if(a)return{woodType:(a[1].trim()+" "+(a[3]||"").trim()).trim(),thickness:a[2]};const n=t.match(/^(.+?)\s+([\d.]+T)(?:\s|$)/);return n?{woodType:n[1].trim(),thickness:n[2]}:{woodType:t.trim(),thickness:""}}function De(s){return typeof s=="object"&&s!==null&&"woodType"in s}function Oe(s){const t=[];for(const a of s){const n=a.request_data;if(!n)continue;let r;if(typeof n=="string")try{r=JSON.parse(n)}catch{continue}else r=n;if(!(!r.wood_items||!Array.isArray(r.wood_items)))for(const o of r.wood_items)if(De(o)){if(E(o.woodType))continue;t.push({sourceType:"ln_order_requests",sourceId:Number(a.id)||0,orderCode:a.request_number||"",date:a.created_at||"",customerName:a.customer_name||"",woodType:o.woodType||"",thickness:o.thickness||"",width:o.width||0,length:o.length||0,quantity:o.quantity||1,hasProcessing:Array.isArray(o.processing)&&o.processing.some(i=>!!i.name),processingList:(o.processing||[]).filter(i=>!!i.name).map(i=>({name:i.name,price:i.price||0,params:i.params})),price:o.totalPrice||0})}else{const i=o,c=i.wood_name||"",{woodType:d,thickness:l}=Pe(c);if(E(d)||!d)continue;const h=i.dimensions||{},x=l||(h.thickness?`${h.thickness}T`:"");t.push({sourceType:"ln_order_requests",sourceId:Number(a.id)||0,orderCode:a.request_number||"",date:a.created_at||"",customerName:a.customer_name||"",woodType:d,thickness:x,width:h.width||0,length:h.height||h.length||0,quantity:i.quantity||1,hasProcessing:Array.isArray(i.processing)&&(i.processing||[]).some(p=>!!p.name),processingList:(i.processing||[]).filter(p=>!!p.name).map(p=>({name:p.name||"",price:p.price||0,params:p.params})),price:i.total_price||0})}}return t}function Me(s){if(!s||/^[a-zA-Z0-9\s\-_.]+$/.test(s.trim()))return null;let t=s.replace(/^\d+\)\s*/,"");t=t.replace(/\[.*?\]\s*/g,"");const a=t.match(/^(.+?)\s*\(([\d.]+T)\)\s*(.*)$/);if(a)return{woodType:(a[1].trim()+" "+(a[3]||"").trim()).trim(),thickness:a[2]};const n=t.match(/^(.+?)\s+([\d.]+T)(?:\s|$)/);if(n)return{woodType:n[1].trim(),thickness:n[2]};const r=t.match(/^(.+?)\s*\((\d+mm\s*x\s*\d+mm)\)\s*$/);return r?{woodType:r[1].trim(),thickness:r[2].replace(/\s/g,"")}:/[가-힣]/.test(t)?{woodType:t.trim(),thickness:""}:null}const Ae=new Set(["샌딩","모서리라운딩","절단면라운딩","사각타공","원형타공","피스타공","밑단홈파기","씽크대보링","두께홈따기","원형컷팅","원형커팅","모서리사선컷팅","액자컷팅","액자커팅","두께홈파기","코너 라운딩","엣지 라운드/사선","기본 사각형","기본 원형","피스 타공","반턱 가공","윗면 홈파기","옆면 홈파기","원형 컷팅","모양 컷팅","모양컷팅","액자 컷팅","싱크 경첩 가공","싱크 경첩 패널","씽크 경첩 가공","씽크 경첩 패널"]);function Re(s){if(!s)return[];const t=s.split("@@@").filter(n=>n.trim()),a=[];for(const n of t){const r=n.split("$$$"),o=r.length>=7?r[6]:r[0];if(!o)continue;const i=o.split("^^^"),c=(i[0]||"").trim();if(!c||c==="가공서비스안함")continue;const d=Number(i[1])||0,l=(i[2]||"").replace(/<br\s*\/?>/gi,"").trim();a.push({name:c,price:d,details:l})}return a}function We(s){const t=[];for(const a of s){const n=(a.proc_data||"").trim();if(!n)continue;const r=a.item_name||"";if(r.includes("[부자재]"))continue;const o=Me(r);if(!o)continue;const c=Re(n).filter(l=>Ae.has(l.name)),d=c.length>0;t.push({sourceType:"order_detail",sourceId:Number(a.id)||0,orderCode:a.order_code||"",date:a.regdate||a.created_at||"",customerName:a.order_name||"",woodType:o.woodType,thickness:o.thickness,width:Number(a.width)||0,length:Number(a.height)||0,quantity:Number(a.qty)||1,hasProcessing:d,processingList:c.map(l=>({name:l.name,price:l.price,params:l.details?{details:l.details}:void 0})),price:Number(a.price)||0})}return t}const P=1e3;async function I(s,t,a,n,r){const o=[];let i=0;for(;;){let c=V.from(s).select(t).order(a,{ascending:!1}).range(i,i+P-1);n&&(c=c.gte(a,n)),r&&(c=c.lte(a,r));const{data:d,error:l}=await c;if(l){console.error(`Fetch ${s} error:`,l);break}if(!d||d.length===0||(o.push(...d),d.length<P))break;i+=P}return o}function Je(){const[s,t]=f.useState([]),[a,n]=f.useState(!1),[r,o]=f.useState(""),[i,c]=f.useState(void 0),[d,l]=f.useState(void 0),[h,x]=f.useState(null),[p,m]=f.useState("all"),y=f.useCallback(async()=>{n(!0);try{const u=i?v(i,"yyyy-MM-dd"):void 0,g=d?v(d,"yyyy-MM-dd")+"T23:59:59":void 0,[b,G]=await Promise.all([I("ln_order_requests","id, request_number, 
1customer_name, request_data, created_at","created_at",u,g),I("order_detail","id, order_code, order_name, item_name, width, height, qty, price, proc_data, regdate, created_at","created_at",u,g)]),D=Oe(b),O=We(G);t(we([...D,...O])),x({lnCount:D.length,odCount:O.length})}catch(u){console.error("Data fetch failed:",u)}finally{n(!1)}},[i,d]);f.useEffect(()=>{y()},[]);const w=f.useCallback(u=>{m(u);const g=new Date;switch(u){case"all":c(void 0),l(void 0);break;case"30d":c(M(g,30)),l(g);break;case"90d":c(M(g,90)),l(g);break;case"1y":c(re(g)),l(g);break}},[]),N=f.useMemo(()=>{if(s.length===0)return null;let u=s[0].date,g=s[0].date;for(const b of s)b.date&&(b.date<u&&(u=b.date),b.date>g&&(g=b.date));return{min:new Date(u),max:new Date(g)}},[s]),j=f.useMemo(()=>{if(!r)return s;const u=r.toLowerCase();return s.filter(g=>g.woodType.toLowerCase().includes(u)||g.customerName.toLowerCase().includes(u)||g.orderCode.toLowerCase().includes(u)||g.processingList.some(b=>b.name.toLowerCase().includes(u)))},[s,r]),k=f.useMemo(()=>ve(j),[j]),K=f.useMemo(()=>Se(j),[j]),Y=f.useMemo(()=>_e(j),[j]);return e.jsxs("div",{className:"p-4 md:p-6 space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-amber-50 rounded-lg",children:e.jsx(ie,{className:"w-5 h-5 text-amber-600"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-lg font-bold text-gray-900",children:"온라인목공소 주문 분석"}),e.jsx("p",{className:"text-xs text-gray-500",children:"주문 데이터를 분석하여 목재/가공 트렌드를 파악합니다"})]})]}),e.jsxs("div",{className:"bg-white rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("span",{className:"text-xs text-gray-500",children:"기간:"}),e.jsx("div",{className:"flex gap-1",children:["all","30d","90d","1y"].map(u=>e.jsx(S,{variant:p===u?"default":"outline",size:"sm",className:"h-7 text-xs",onClick:()=>w(u),children:u==="all"?"전체":u==="30d"?"30일":u==="90d"?"90일":"1년"},u))}),e.jsx(S,{variant:"outline",size:"sm",className:"h-7 text-xs",disabled:!0,children:i?v(i,"yyyy.MM.dd",{locale:C}):N?v(N.min,"yyyy.MM.dd",{locale:C}):"시작일"}),e.jsx("span",{className:"text-gray-400 text-xs",children:"~"}),e.jsx(S,{variant:"outline",size:"sm",className:"h-7 text-xs",disabled:!0,children:d?v(d,"yyyy.MM.dd",{locale:C}):N?v(N.max,"yyyy.MM.dd",{locale:C}):"종료일"}),e.jsxs(S,{variant:"default",size:"sm",className:"h-7 text-xs",onClick:y,disabled:a,children:[a?e.jsx(A,{className:"w-3.5 h-3.5 mr-1 animate-spin"}):e.jsx(oe,{className:"w-3.5 h-3.5 mr-1"}),"조회"]}),e.jsxs("div",{className:"relative ml-auto",children:[e.jsx(ce,{className:"absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-gray-400"}),e.jsx(Z,{placeholder:"목재명/고객명/가공명 검색...",value:r,onChange:u=>o(u.target.value),className:"h-7 text-xs pl-8 pr-8 w-[220px]"}),r&&e.jsx("button",{type:"button",onClick:()=>o(""),className:"absolute right-2 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-gray-100 text-gray-400 hover:text-gray-600",title:"검색어 지우기",children:e.jsx(Q,{className:"h-4 w-4"})})]})]}),h&&e.jsxs("div",{className:"flex items-center gap-3 text-xs text-gray-500",children:[e.jsx(le,{className:"w-3.5 h-3.5"}),e.jsxs("span",{children:["신버전 계산기(ln_order_requests): ",e.jsxs("strong",{className:"text-blue-600",children:[h.lnCount.toLocaleString(),"건"]})]}),e.jsx("span",{children:"|"}),e.jsxs("span",{children:["구버전 계산기(컷 포함)(order_detail): ",e.jsxs("strong",{className:"text-orange-600",children:[h.odCount.toLocaleString(),"건"]})]}),e.jsx("span",{children:"|"}),e.jsxs("span",{children:["합계: ",e.jsxs("strong",{className:"text-gray-700",children:[(h.lnCount+h.odCount).toLocaleString(),"건"]})]})]})]}),a&&e.jsxs("div",{className:"flex items-center justify-center py-12 text-gray-400",children:[e.jsx(A,{className:"w-5 h-5 mr-2 animate-spin"}),e.jsx("span",{className:"text-sm",children:"데이터 조회 중..."})]}),!a&&e.jsx(xe,{rankings:k,ratio:K,ranges:Y}),!a&&e.jsx(pe,{data:j})]})}export{Je as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.