PageSourceSearch

https://homecheck.kr/_nuxt/DhoqAXRe.js

js homecheck.kr collected 2026-10-04 07:47:37 UTC 12,052 bytes, 28 lines download raw bytes

1import{_ as N}from"./BgYlC6kX.js";import{e as O,d as m,f as F,c as T,j as E}from"./C_MIU5t0.js";import{_ as B,c as a,a as e,y as c,b as _,d as g,w,t as i,F as v,E as k,G as I,Z as x,q as L,v as y,C as V,B as H,o as u}from"./B3DH6OY8.js";function f(s,t){return s&&s.data&&(s.data.statusMessage||s.data.message)||s&&(s.statusMessage||s.message)||t}function C(s){const t=s.schedule&&s.schedule.start;return E(t)?t:"9999-99-99"}function S(s){for(const t of[s.completedAt,s.updatedAt,s.publishedAt])if(typeof t=="string"&&t)return t;return""}function A(s){return s.slice().sort((t,r)=>{const h=t.status==="closed",n=r.status==="closed";if(h!==n)return h?1:-1;if(h){const o=S(t),d=S(r);if(o!==d)return o<d?1:-1}else{const o=C(t),d=C(r);if(o!==d)return o<d?-1:1;const l=String(t.apartmentName||"").localeCompare(String(r.apartmentName||""),"ko");if(l!==0)return l}return String(t.slug||"").localeCompare(String(r.slug||""))})}function M(s){const t=String(s||"").replace(/[,\s]/g,"").replace(/세대$/,"");if(!/^\d+$/.test(t))return null;const r=Number(t);return r>=1&&r<=999999?r:null}const P={data(){return{loading:!0,loadError:"",missing:!1,readError:!1,items:[],search:"",progressFilter:"",statusFilter:"",message:"",messageOk:!0,savedNotice:"",busySlug:""}},computed:{filteredItems(){const s=this.search.trim().toLowerCase();return this.items.filter(t=>{if(s){const r=t.region||{};if(![t.apartmentName,r.sido,r.sigungu,r.gu].filter(Boolean).join(" ").toLowerCase().includes(s))return!1}return!(this.progressFilter==="open"&&this.isClosed(t)||this.progressFilter==="closed"&&!this.isClosed(t)||this.statusFilter==="published"&&!t.published||this.statusFilter==="draft"&&t.published)})},savedItem(){return this.savedNotice&&this.items.find(s=>s.slug===this.savedNotice)||null},savedLabel(){const s=this.savedItem;return s&&s.apartmentName?`${s.apartmentName} (${s.slug})`:this.savedNotice}},async mounted(){const s=V();s.query.saved&&(this.savedNotice=String(s.query.saved),H().replace({path:"/__admin__/groupbuy"})),await this.load()},methods:{async load(){this.loading=!0,this.loadError="";try{const s=await $fetch("/api/admin/groupbuy");this.items=A(s.file&&s.file.items||[]),this.missing=!!s.missing,this.readError=!!s.readError}catch(s){this.loadError=f(s,"불러오기 실패")}finally{this.loading=!1}},resetFilters(){this.search="",this.progressFilter="",this.statusFilter=""},isClosed(s){return s.status==="closed"},hasBody(s){return!!String(s.bodyHtml||"").trim()},regionText(s){return T(s.region||{})||"-"},householdsText(s){return m(s)||"-"},scheduleText(s){const t=s.schedule;return t&&t.start&&F(t)||"-"},progressLabel(s){if(!this.isClosed(s))return"진행중";const t=m(s.completedHouseholds);return t?`완료 · ${t}`:"완료"},nameOf(s){return s.apartmentName||s.slug},async remove(s){const t=this.isClosed(s)?`
2완료 처리된 항목이라 실적 페이지(/portfolio)의 카드도 함께 사라집니다.`:"";if(window.confirm(`이 공동구매를 삭제하시겠습니까?
3
4아파트: ${this.nameOf(s)}
5슬러그: ${s.slug}
6
7삭제하면 되돌릴 수 없습니다.${t}`)){this.message="",this.busySlug=s.slug;try{await $fetch(`/api/admin/groupbuy/items/${encodeURIComponent(s.slug)}`,{method:"DELETE"}),this.message=`삭제 완료: ${this.nameOf(s)}`,this.messageOk=!0,await this.load()}catch(r){this.message=f(r,"삭제 실패"),this.messageOk=!1}finally{this.busySlug=""}}},async togglePublish(s){const t=!s.published,r=t?"발행":"비공개 전환",h=t&&!this.hasBody(s)?`
8
9※ 단지 소개 본문이 비어 있습니다.`:"";if(window.confirm(`이 공동구매를 ${r} 하시겠습니까?
10
11아파트: ${this.nameOf(s)}
12슬러그: ${s.slug}${h}`)){this.message="",this.busySlug=s.slug;try{await $fetch("/api/admin/groupbuy/items",{method:"POST",body:{mode:"update",item:{...s,published:t}}}),this.message=`${r} 완료: ${this.nameOf(s)}`,this.messageOk=!0,await this.load()}catch(n){this.message=f(n,"상태 변경 실패"),this.messageOk=!1}finally{this.busySlug=""}}},async complete(s){const t=this.nameOf(s),r=`
13
14아파트: ${t}
15단지 세대수: ${this.householdsText(s.households)}`;let h=`공동구매 참여 세대수를 숫자로 입력하세요.${r}`,n="",o=null;for(;;){const b=window.prompt(h,n);if(b===null)return;if(o=M(b),o!==null)break;h=`1 이상의 숫자(정수)만 입력할 수 있습니다. 다시 입력하세요.
16
17공동구매 참여 세대수를 숫자로 입력하세요.${r}`,n=b}const d=typeof s.households=="number"&&o>s.households?`
18
19※ 입력한 참여 세대수가 단지 세대수보다 많습니다. 숫자를 다시 확인하세요.`:"",l=O({completedHouseholds:o}),p=s.published?"":`
20
21※ 아직 초안(비공개)이라 사이트에는 발행한 뒤에 표시됩니다.`;if(window.confirm(`이 공동구매를 완료 처리하시겠습니까?
22
23아파트: ${t}
24참여 세대수: ${m(o)}
25
26완료 처리하면 사이트 상세 페이지에 '${l}' 문구가 표시되고, 실적 페이지(/portfolio) 사전점검 칸에도 카드로 표시됩니다.${p}${d}`)){this.message="",this.busySlug=s.slug;try{await $fetch("/api/admin/groupbuy/complete",{method:"POST",body:{slug:s.slug,completedHouseholds:o}}),this.message=`완료 처리: ${t} · ${m(o)}`,this.messageOk=!0,await this.load()}catch(b){this.message=f(b,"완료 처리 실패"),this.messageOk=!1}finally{this.busySlug=""}}},async reopen(s){if(window.confirm(`완료 처리를 취소하고 다시 '진행중' 으로 되돌립니다. 계속할까요?
27
28아파트: ${this.nameOf(s)}`)){this.message="",this.busySlug=s.slug;try{await $fetch("/api/admin/groupbuy/reopen",{method:"POST",body:{slug:s.slug}}),this.message=`완료 취소: ${this.nameOf(s)} — 다시 '진행중' 으로 표시됩니다.`,this.messageOk=!0,await this.load()}catch(t){this.message=f(t,"완료 취소 실패"),this.messageOk=!1}finally{this.busySlug=""}}}},head(){return{title:"공동구매 관리 · Admin",meta:[{name:"robots",content:"noindex,nofollow"}]}}},D={class:"groupbuy-list"},G={class:"gl-head"},R={key:0,class:"gl-status gl-status--top gl-status--success"},U={key:1,class:"gl-status gl-status--top gl-status--error"},$={class:"gl-filters"},j={class:"gl-filter"},q={class:"gl-filter"},K={class:"gl-filter"},z={key:2,class:"gl-status"},Z={key:3,class:"gl-status gl-status--error"},J={class:"gl-count"}
28,Q={key:0,class:"gl-count__missing"},W={class:"gl-table-wrap"},X={class:"gl-table"},Y={key:0},ss={class:"gl-thumb"},ts=["src","alt"],es={key:1,class:"gl-thumb__empty"},ls={class:"gl-slug"},os={key:0,class:"gl-subtitle"},ns={class:"gl-nowrap"},rs={class:"gl-nowrap"},as={class:"gl-stack"},us={key:0,class:"gl-warn-badge",title:"단지 소개 본문이 비어 있습니다"},is={class:"gl-nowrap"},ds={class:"gl-actions"},gs=["disabled","onClick"],hs=["disabled","onClick"],cs=["disabled","onClick"],ps=["disabled","onClick"];function bs(s,t,r,h,n,o){const d=N;return u(),a("div",D,[e("div",G,[t[5]||(t[5]=e("div",null,[e("h1",{class:"admin-page-title"},"공동구매 관리"),e("p",{class:"admin-page-desc"},[g(" 아파트 사전점검 공동구매 진행 현황을 등록·수정·완료 처리합니다. 저장한 내용은 "),e("code",null,"data/groupbuy.json"),g(" 에 반영됩니다. "),e("br"),g("발행된 항목만 사이트(/groupbuy)에 노출되며, 완료 처리한 항목은 실적 페이지(/portfolio) 사전점검 칸에도 카드로 표시됩니다. ")])],-1)),_(d,{to:"/__admin__/groupbuy/new",class:"gl-btn gl-btn--primary"},{default:w(()=>[...t[4]||(t[4]=[g("+ 새 공동구매 등록",-1)])]),_:1})]),n.savedNotice?(u(),a("div",R,[t[6]||(t[6]=g(" 공동구매가 저장되었습니다: ",-1)),e("strong",null,i(o.savedLabel),1),o.savedItem&&!o.savedItem.published?(u(),a(v,{key:0},[g(" · 아직 초안입니다. 목록의 '발행' 버튼을 눌러야 사이트에 공개됩니다. ")],64)):c("",!0)])):c("",!0),n.readError?(u(),a("div",U," 공동구매 데이터를 읽지 못했습니다(일시적 오류일 수 있음). 새로고침 후 다시 시도하세요. 이 상태에서는 저장·삭제·완료 처리가 서버에서 제한됩니다. ")):c("",!0),e("div",$,[e("label",j,[t[7]||(t[7]=e("span",null,"검색(아파트 이름·지역)",-1)),k(e("input",{type:"text",class:"gl-input","onUpdate:modelValue":t[0]||(t[0]=l=>n.search=l),placeholder:"아파트 이름 또는 지역으로 검색"},null,512),[[I,n.search]])]),e("label",q,[t[9]||(t[9]=e("span",null,"진행 상태",-1)),k(e("select",{class:"gl-input","onUpdate:modelValue":t[1]||(t[1]=l=>n.progressFilter=l)},[...t[8]||(t[8]=[e("option",{value:""},"전체",-1),e("option",{value:"open"},"진행중",-1),e("option",{value:"closed"},"완료",-1)])],512),[[x,n.progressFilter]])]),e("label",K,[t[11]||(t[11]=e("span",null,"발행 상태",-1)),k(e("select",{class:"gl-input","onUpdate:modelValue":t[2]||(t[2]=l=>n.statusFilter=l)},[...t[10]||(t[10]=[e("option",{value:""},"전체",-1),e("option",{value:"published"},"발행",-1),e("option",{value:"draft"},"초안",-1)])],512),[[x,n.statusFilter]])]),e("button",{type:"button",class:"gl-btn gl-filter-reset",onClick:t[3]||(t[3]=(...l)=>o.resetFilters&&o.resetFilters(...l))},"필터 초기화")]),n.loading?(u(),a("div",z,"불러오는 중…")):n.loadError?(u(),a("div",Z,i(n.loadError),1)):(u(),a(v,{key:4},[e("div",J,[t[12]||(t[12]=g(" 총 ",-1)),e("strong",null,i(n.items.length),1),t[13]||(t[13]=g("건 · 필터 후 ",-1)),e("strong",null,i(o.filteredItems.length),1),t[14]||(t[14]=g("건 ",-1)),n.missing?(u(),a("span",Q,"· 아직 저장된 공동구매 파일이 없습니다")):c("",!0)]),e("div",W,[e("table",X,[t[17]||(t[17]=e("thead",null,[e("tr",null,[e("th",{style:{width:"56px"}}),e("th",null,"아파트"),e("th",{style:{width:"150px"}},"지역"),e("th",{style:{width:"90px"}},"세대수"),e("th",{style:{width:"150px"}},"사전점검 일정"),e("th",{style:{width:"120px"}},"상태"),e("th",{style:{width:"90px"}},"발행"),e("th",{style:{width:"110px"}},"게시일"),e("th",{style:{width:"280px"}},"작업")])],-1)),e("tbody",null,[o.filteredItems.length?c("",!0):(u(),a("tr",Y,[...t[15]||(t[15]=[e("td",{colspan:"9",class:"gl-empty"},"표시할 공동구매가 없습니다.",-1)])])),(u(!0),a(v,null,L(o.filteredItems,l=>(u(),a("tr",{key:l.slug},[e("td",null,[e("div",ss,[l.thumbnail?(u(),a("img",{key:0,src:l.thumbnail,alt:l.alt||l.apartmentName},null,8,ts)):(u(),a("span",es,"-"))])]),e("td",null,[_(d,{to:`/__admin__/groupbuy/${l.slug}`,class:"gl-title"},{default:w(()=>[g(i(l.apartmentName||"(아파트 이름 없음)"),1)]),_:2},1032,["to"]),e("div",ls,i(l.slug),1),l.title?(u(),a("div",os,i(l.title),
281)):c("",!0)]),e("td",null,i(o.regionText(l)),1),e("td",ns,i(o.householdsText(l.households)),1),e("td",rs,i(o.scheduleText(l)),1),e("td",null,[e("span",{class:y(["gl-badge",o.isClosed(l)?"gl-badge--done":"gl-badge--open"])},i(o.progressLabel(l)),3)]),e("td",null,[e("div",as,[e("span",{class:y(["gl-badge",l.published?"gl-badge--pub":"gl-badge--draft"])},i(l.published?"발행":"초안"),3),o.hasBody(l)?c("",!0):(u(),a("span",us,"본문 없음"))])]),e("td",is,i(l.publishedAt||"-"),1),e("td",ds,[e("button",{type:"button",class:y(["gl-row-btn",l.published?"":"gl-row-btn--pub"]),disabled:n.busySlug===l.slug,onClick:p=>o.togglePublish(l)},i(l.published?"비공개":"발행"),11,gs),o.isClosed(l)?(u(),a("button",{key:1,type:"button",class:"gl-row-btn",disabled:n.busySlug===l.slug,onClick:p=>o.reopen(l)}," 완료 취소 ",8,cs)):(u(),a("button",{key:0,type:"button",class:"gl-row-btn gl-row-btn--done",disabled:n.busySlug===l.slug,onClick:p=>o.complete(l)}," 완료 ",8,hs)),_(d,{to:`/__admin__/groupbuy/${l.slug}`,class:"gl-row-btn"},{default:w(()=>[...t[16]||(t[16]=[g("수정",-1)])]),_:1},8,["to"]),e("button",{type:"button",class:"gl-row-btn gl-row-btn--danger",disabled:n.busySlug===l.slug,onClick:p=>o.remove(l)}," 삭제 ",8,ps)])]))),128))])])]),n.message?(u(),a("p",{key:0,class:y(["gl-status",{"gl-status--success":n.messageOk,"gl-status--error":!n.messageOk}])},i(n.message),3)):c("",!0)],64))])}const _s=B(P,[["render",bs],["__scopeId","data-v-7617ebbe"]]);export{_s 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.