From fa4daa958f25d1737f7f8bf86d287213c3803356 Mon Sep 17 00:00:00 2001 From: SoonWooLee1 Date: Thu, 1 Jan 2026 21:42:19 +0900 Subject: [PATCH 01/53] =?UTF-8?q?=EA=B3=A0=EA=B0=9D=20=EB=8C=80=EC=9D=91?= =?UTF-8?q?=20=ED=9E=88=EC=8A=A4=ED=86=A0=EB=A6=AC=20=EA=B2=80=EC=83=89,?= =?UTF-8?q?=20=ED=95=84=ED=84=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 13 +- src/views/customer/CustomerDetailView.vue | 165 +++++++++++++++++----- 2 files changed, 128 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index d94e6a1..3a34560 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -315,7 +314,6 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.28.5" }, @@ -1379,7 +1377,6 @@ "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/lodash": "*" } @@ -1802,7 +1799,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -2043,7 +2039,6 @@ "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", "integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "2.3.0", "zrender": "6.0.0" @@ -2533,15 +2528,13 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash-unified": { "version": "1.0.3", @@ -3280,7 +3273,6 @@ "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -3459,7 +3451,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.24.tgz", "integrity": "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/compiler-sfc": "3.5.24", diff --git a/src/views/customer/CustomerDetailView.vue b/src/views/customer/CustomerDetailView.vue index 8d50459..7149a9d 100644 --- a/src/views/customer/CustomerDetailView.vue +++ b/src/views/customer/CustomerDetailView.vue @@ -57,7 +57,6 @@
- @@ -69,6 +68,9 @@ {{ customer.email }} {{ customer.firstContractDate || '-' }} {{ customer.addr || '-' }} + + {{ formatMoneyMan(customer.totalTransactionAmount) }} + @@ -98,12 +100,47 @@
* '저장' 클릭 시 반영됩니다.
+ - - - + + + + [{{ item.type }}] {{ item.performer }} -
{{ item.content }}
+
{{ item.status === '완료' ? '완료' : '진행 중' }} @@ -123,7 +160,8 @@ - + + @@ -135,7 +173,6 @@ - - \ No newline at end of file diff --git a/src/views/customer/overdue/ItemOverdueDetailView.vue b/src/views/customer/overdue/ItemOverdueDetailView.vue index 17bdc4f..812688a 100644 --- a/src/views/customer/overdue/ItemOverdueDetailView.vue +++ b/src/views/customer/overdue/ItemOverdueDetailView.vue @@ -4,15 +4,22 @@ import { useRoute, useRouter } from 'vue-router' import axios from '@/api/axios' import StatusBadge from '@/components/overdue/StatusBadge.vue' import { ElMessage, ElMessageBox } from 'element-plus' +import { useAuthStore } from '@/store/auth.store' const route = useRoute() const router = useRouter() +const authStore = useAuthStore(); const overdueId = route.params.overdueId const loading = ref(false) const detail = ref(null) const items = ref([]) +/** 제품 연체 처리 권한 */ +const canProcessItemOverdue = computed(() => + authStore.hasAuth('OVERDUE_PROCESS') +) + /* 수정용 */ const editCount = ref(0) @@ -49,8 +56,8 @@ const saveCount = async () => { await ElMessageBox.confirm( isResolve - ? '수량이 0입니다. 제품 연체를 해결 처리하시겠습니까?' - : '연체 수량을 수정하시겠습니까?', + ? '수량이 0입니다. 제품 연체를 해결 처리하시겠습니까?' + : '연체 수량을 수정하시겠습니까?', '제품 연체 수정', { type: 'warning' } ) @@ -69,20 +76,20 @@ const saveCount = async () => { /* 연락처 포맷: 02-6100-0060 / 010-1234-5678 */ const formatPhone = (value) => { - if (!value) return '-' - const d = String(value).replace(/\D/g, '') + if (!value) return '-' + const d = String(value).replace(/\D/g, '') - // 02 지역번호 - if (d.startsWith('02')) { - if (d.length === 9) return d.replace(/^(\d{2})(\d{3})(\d{4})$/, '$1-$2-$3') // 02-123-4567 - if (d.length === 10) return d.replace(/^(\d{2})(\d{4})(\d{4})$/, '$1-$2-$3') // 02-1234-5678 - } + // 02 지역번호 + if (d.startsWith('02')) { + if (d.length === 9) return d.replace(/^(\d{2})(\d{3})(\d{4})$/, '$1-$2-$3') // 02-123-4567 + if (d.length === 10) return d.replace(/^(\d{2})(\d{4})(\d{4})$/, '$1-$2-$3') // 02-1234-5678 + } - // 휴대폰/기타 지역번호(3자리) - if (d.length === 10) return d.replace(/^(\d{3})(\d{3})(\d{4})$/, '$1-$2-$3') // 031-123-4567 - if (d.length === 11) return d.replace(/^(\d{3})(\d{4})(\d{4})$/, '$1-$2-$3') // 010-1234-5678 + // 휴대폰/기타 지역번호(3자리) + if (d.length === 10) return d.replace(/^(\d{3})(\d{3})(\d{4})$/, '$1-$2-$3') // 031-123-4567 + if (d.length === 11) return d.replace(/^(\d{3})(\d{4})(\d{4})$/, '$1-$2-$3') // 010-1234-5678 - return value + return value } onMounted(fetchDetail) @@ -92,79 +99,86 @@ onMounted(fetchDetail)
-

제품 연체 상세

- 목록으로 -
- - -
-
-

{{ detail?.itemOverdueCode }}

- +

제품 연체 상세

+ 목록으로
- - 수정 저장 - -
+ +
+
+

{{ detail?.itemOverdueCode }}

+ +
+ + + + + + 수정 저장 + + + + + + + 수정 저장 + +
- - - - {{ detail?.customerName }} - - - - {{ detail?.inCharge }} - - - - {{ formatPhone(detail?.callNum) }} - - - - {{ detail?.contractCode }} - - - - {{ formatDate(detail?.dueDate) }} - - - - {{ detail?.overduePeriod }}일 - - - - - - {{ detail?.count }}개 - - - - - - - - -

연체된 제품 목록

- - - - - - + + + + {{ detail?.customerName }} + + + + {{ detail?.inCharge }} + + + + {{ formatPhone(detail?.callNum) }} + + + + {{ detail?.contractCode }} + + + + {{ formatDate(detail?.dueDate) }} + + + + {{ detail?.overduePeriod }}일 + + + + + + {{ detail?.count }}개 + + + + + + + + +

연체된 제품 목록

+ + + + + +
- \ No newline at end of file +const openEditModal = () => { + editModalVisible.value = true +} + +const handleDelete = () => { + ElMessageBox.confirm( + '정말로 이 상담 내역을 삭제하시겠습니까?\n삭제된 데이터는 복구할 수 없습니다.', + '삭제 확인', + { type: 'warning' } + ).then(async () => { + try { + await deleteQuote(quote.value.quoteId) + ElMessage.success('삭제되었습니다.') + router.push('/quote') + } catch (e) { + ElMessage.error('삭제 중 오류가 발생했습니다.') + } + }) +} + +/* ========================= + Utils +========================= */ +const formatDateTime = (v) => { + if (!v) return '-' + return v.replace('T', ' ') +} + +const formatPhone = (v) => + v + ? v.replace( + /(^02|^0505|^1[0-9]{3}|^0[0-9]{2})([0-9]+)?([0-9]{4})$/, + '$1-$2-$3' + ) + : '-' + +/* ========================= + Lifecycle +========================= */ +onMounted(fetchData) + + + \ No newline at end of file From 35fc66c7d6a5e95d96f4fe69fb382433cce9818c Mon Sep 17 00:00:00 2001 From: huni2 Date: Fri, 2 Jan 2026 12:18:07 +0900 Subject: [PATCH 11/53] =?UTF-8?q?feat:=20#75=20=EC=82=AC=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=EB=B0=94=20UX=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AppLayout.vue | 97 ++++++++++++++++++ src/components/Sidebar.vue | 186 +++++++++++++++++++++++++++++++---- 2 files changed, 263 insertions(+), 20 deletions(-) create mode 100644 src/components/AppLayout.vue diff --git a/src/components/AppLayout.vue b/src/components/AppLayout.vue new file mode 100644 index 0000000..e72429e --- /dev/null +++ b/src/components/AppLayout.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 0e77831..0e66a31 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -1,17 +1,24 @@ \ No newline at end of file +/* 공통 카드 */ +.kpi-box { + background: #fff; + padding: 24px; + border: 1px solid #eee; + border-radius: 8px; + cursor: pointer; + transition: all 0.15s ease; +} + +.kpi-box:hover { + box-shadow: 0 4px 10px rgba(0,0,0,0.06); + transform: translateY(-2px); +} + +/* 텍스트 */ +.kpi-title { + font-size: 14px; + color: #666; + margin-bottom: 10px; + display: block; + font-weight: 500; +} + +.kpi-count { + font-size: 28px; + font-weight: 800; + color: #333; +} + +.kpi-sub { + display: block; + margin-top: 6px; + font-size: 13px; + color: #888; +} + +/* 숫자 색상 */ +.warning { color: #ef4444; } +.success { color: #22c55e; } +.info { color: #3b82f6; } + +/* 배경 강조 */ +.warning-box { + background-color: #fef2f2; + border-color: #fee2e2; +} + +.success-box { + background-color: #ecfdf5; + border-color: #d1fae5; +} + +.info-box { + background-color: #eff6ff; + border-color: #dbeafe; +} + +/* 선택 상태 */ +.kpi-box.active { + outline: 2px solid #2563eb; + outline-offset: -2px; +} + diff --git a/src/views/product/AsListView.vue b/src/views/product/AsListView.vue index c9362f5..3c801b4 100644 --- a/src/views/product/AsListView.vue +++ b/src/views/product/AsListView.vue @@ -1,186 +1,196 @@ + From a889198aac0cd4c0caa8c87367794826536d39ca Mon Sep 17 00:00:00 2001 From: Kjandgo Date: Fri, 2 Jan 2026 16:23:00 +0900 Subject: [PATCH 13/53] =?UTF-8?q?feat:=20#90=20=EA=B6=8C=ED=95=9C=EB=B3=84?= =?UTF-8?q?=20=EC=A0=91=EA=B7=BC=20=EC=84=A4=EC=A0=95=EC=A4=91(=EA=B2=AC?= =?UTF-8?q?=EC=A0=81=EA=B9=8C=EC=A7=80=20=EC=99=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Sidebar.vue | 9 +++++++++ src/views/business/QuoteDetailView.vue | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 0e66a31..337340b 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -395,6 +395,15 @@ const toggleSidebar = () => { isCollapsed.value = !isCollapsed.value; }; +const hasAdminPermission = computed(() => { + const list = authStore.auth || []; + + return list.some(p => + typeof p === "string" + ? p === "ADMIN_READ" || p === "ADMIN_MANAGE" + : p.auth === "ADMIN_READ" || p.auth === "ADMIN_MANAGE" + ); +}); \ No newline at end of file + From 72d1cdb19a72dce494edc6d92630059c0df23bf7 Mon Sep 17 00:00:00 2001 From: Kjandgo Date: Fri, 2 Jan 2026 17:26:41 +0900 Subject: [PATCH 14/53] =?UTF-8?q?feat:=20#90=20=EA=B6=8C=ED=95=9C=EB=B3=84?= =?UTF-8?q?=20=EC=A0=91=EA=B7=BC=20=EC=84=A4=EC=A0=95=EC=A4=91(=EC=BA=A0?= =?UTF-8?q?=ED=8E=98=EC=9D=B8=EA=B9=8C=EC=A7=80=20=EC=99=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Sidebar.vue | 12 - src/router/index.js | 6 +- src/views/approval/ApprovalPending.vue | 168 ++++------- src/views/campaign/CouponDetailModal.vue | 62 ++++- src/views/campaign/CouponListView.vue | 292 ++++++++++---------- src/views/campaign/PromotionDetailModal.vue | 47 ++-- src/views/campaign/PromotionListView.vue | 34 ++- src/views/contract/ContractDetailView.vue | 47 +++- src/views/contract/ContractListView.vue | 33 ++- 9 files changed, 370 insertions(+), 331 deletions(-) diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 337340b..cd80990 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -389,21 +389,9 @@ const hasAdminPermission = computed(() => { }); const isCollapsed = ref(false); - - const toggleSidebar = () => { isCollapsed.value = !isCollapsed.value; }; - -const hasAdminPermission = computed(() => { - const list = authStore.auth || []; - - return list.some(p => - typeof p === "string" - ? p === "ADMIN_READ" || p === "ADMIN_MANAGE" - : p.auth === "ADMIN_READ" || p.auth === "ADMIN_MANAGE" - ); -}); \ No newline at end of file diff --git a/src/views/campaign/PromotionDetailModal.vue b/src/views/campaign/PromotionDetailModal.vue index 49d1490..a39b9c6 100644 --- a/src/views/campaign/PromotionDetailModal.vue +++ b/src/views/campaign/PromotionDetailModal.vue @@ -1,10 +1,5 @@ \ No newline at end of file From 2cecad6bb97d1fdecb9a7d4e97569c0f00fee4e7 Mon Sep 17 00:00:00 2001 From: Kjandgo Date: Sat, 3 Jan 2026 16:18:35 +0900 Subject: [PATCH 20/53] =?UTF-8?q?feat:=20#90=20=EC=9E=90=EC=82=B0=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B6=8C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/product/ProductDetailModal.vue | 75 ++++-- src/views/product/ProductListView.vue | 315 +++++++++++------------ 2 files changed, 215 insertions(+), 175 deletions(-) diff --git a/src/views/product/ProductDetailModal.vue b/src/views/product/ProductDetailModal.vue index db7811f..e01e7f0 100644 --- a/src/views/product/ProductDetailModal.vue +++ b/src/views/product/ProductDetailModal.vue @@ -7,12 +7,19 @@

{{ itemName }}

{{ categoryName }}

+ + class="edit-btn" + :disabled="!canUpdateItem" + @click="canUpdateItem && openNameEditModal(itemName, monthlyPrice, categoryName)" +> + 수정 + + @@ -69,18 +76,32 @@ {{ formatDate(unit.startDate) }} {{ formatDate(unit.lastInspectDate) }} + + class="text-btn" + :disabled="!canUpdateItem" + @click="canUpdateItem && openEditModal(unit)" +> + 수정 + + + + class="text-btn danger" + :disabled="!canDeleteItem" + @click="canDeleteItem && deleteUnit(unit)" +> + 삭제 + + @@ -120,10 +141,21 @@ \ No newline at end of file diff --git a/src/views/dashboard/DashboardView.vue b/src/views/dashboard/DashboardView.vue index 76b7dfe..05450bb 100644 --- a/src/views/dashboard/DashboardView.vue +++ b/src/views/dashboard/DashboardView.vue @@ -1,6 +1,15 @@ From 3590993c08698fd1480a036b626f00797b749fd1 Mon Sep 17 00:00:00 2001 From: Seojin Yun Date: Sat, 3 Jan 2026 20:04:27 +0900 Subject: [PATCH 30/53] =?UTF-8?q?=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/CampaignWorkbenchMock.vue | 54 +---- .../dashboard/CouponWorkbenchMock.vue | 227 ++++++++++++++++++ src/components/dashboard/ProductStatus.vue | 4 - src/views/dashboard/DashboardView.vue | 2 + 4 files changed, 233 insertions(+), 54 deletions(-) create mode 100644 src/components/dashboard/CouponWorkbenchMock.vue diff --git a/src/components/dashboard/CampaignWorkbenchMock.vue b/src/components/dashboard/CampaignWorkbenchMock.vue index aec2cb0..9537028 100644 --- a/src/components/dashboard/CampaignWorkbenchMock.vue +++ b/src/components/dashboard/CampaignWorkbenchMock.vue @@ -2,8 +2,7 @@
-
캠페인 워크벤치
-
승격 2건
+
프로모션 워크벤치
@@ -29,26 +28,6 @@
- - -
-
- - -
-
{{ coupon.name }}
-
대상: {{ coupon.segmentName }}
-
-
- - -
@@ -62,7 +41,6 @@ import api from '@/api/axios'; const router = useRouter(); const loading = ref(false); const promotion = ref([]); -const coupon = ref([]); const fetchPromotionList = async () => { loading.value = true; @@ -77,22 +55,9 @@ const fetchPromotionList = async () => { } }; -const fetchCouponList = async () => { - loading.value = true; - try { - const res = await api.get('/recommend/coupon/read-one'); - coupon.value = res.data; - } catch (e) { - ElMessage.error('추천 쿠폰 목록을 불러오지 못했습니다.'); - console.error(e); - } finally { - loading.value = false; - } -}; onMounted(() => { - fetchPromotionList(), - fetchCouponList(); + fetchPromotionList() }); /** @@ -101,8 +66,6 @@ onMounted(() => { */ const routeMap = { PROMOTION_CREATE: { name: "promotion-list" }, // 프로모션 생성 - COUPON_CREATE: { name: "coupon-list" }, // 쿠폰 발급 - CAMPAIGN_SETTING: { name: "campaign-setting" }, // 캠페인 설정 -> 이부분 고민하기 }; const go = (key) => { @@ -117,9 +80,10 @@ const go = (key) => { background: #fff; border: 1px solid #eee; border-radius: 12px; - height: 100%; + height: 48%; width: 100%; padding: 16px 16px 14px; + margin-bottom: 12px; } /* Header */ @@ -138,16 +102,6 @@ const go = (key) => { letter-spacing: -0.2px; } -.wb-pill { - font-size: 12px; - color: #6b7280; - border: 1px solid #e5e7eb; - background: #f9fafb; - padding: 6px 10px; - border-radius: 999px; - white-space: nowrap; -} - /* List */ .wb-list { border-radius: 10px; diff --git a/src/components/dashboard/CouponWorkbenchMock.vue b/src/components/dashboard/CouponWorkbenchMock.vue new file mode 100644 index 0000000..ec4452e --- /dev/null +++ b/src/components/dashboard/CouponWorkbenchMock.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/src/components/dashboard/ProductStatus.vue b/src/components/dashboard/ProductStatus.vue index addf35f..0359154 100644 --- a/src/components/dashboard/ProductStatus.vue +++ b/src/components/dashboard/ProductStatus.vue @@ -54,10 +54,6 @@ - -
- -
diff --git a/src/views/dashboard/DashboardView.vue b/src/views/dashboard/DashboardView.vue index 76b7dfe..a5ecade 100644 --- a/src/views/dashboard/DashboardView.vue +++ b/src/views/dashboard/DashboardView.vue @@ -58,6 +58,7 @@
+
@@ -74,6 +75,7 @@ import SegmentAnalysisChart from "@/components/analysis/SegmentAnalysisChart.vue import QuarterCustomerChart from "@/components/dashboard/QuarterCustomerChart.vue"; import SegmentDistribution from "@/components/analysis/SegmentDistribution.vue"; import CampaignWorkbenchMock from "@/components/dashboard/CampaignWorkbenchMock.vue"; +import CouponWorkbenchMock from "@/components/dashboard/CouponWorkbenchMock.vue"; const router = useRouter(); From f2de7230a9a2b0598b6ac728eb5e5a3dac3a361d Mon Sep 17 00:00:00 2001 From: SoonWooLee1 Date: Sun, 4 Jan 2026 01:28:12 +0900 Subject: [PATCH 31/53] =?UTF-8?q?=EA=B3=A0=EA=B0=9D=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0=20=EB=9D=BC=EC=9A=B0=ED=8C=85=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/campaign/CouponListView.vue | 19 +++++- src/views/campaign/PromotionListView.vue | 17 ++++- src/views/customer/CustomerDetailView.vue | 77 +++++++++-------------- src/views/product/AsListView.vue | 15 +++++ 4 files changed, 76 insertions(+), 52 deletions(-) diff --git a/src/views/campaign/CouponListView.vue b/src/views/campaign/CouponListView.vue index 96ad654..beb255f 100644 --- a/src/views/campaign/CouponListView.vue +++ b/src/views/campaign/CouponListView.vue @@ -162,13 +162,19 @@ diff --git a/src/views/campaign/PromotionListView.vue b/src/views/campaign/PromotionListView.vue index 129ae28..3f4c90d 100644 --- a/src/views/campaign/PromotionListView.vue +++ b/src/views/campaign/PromotionListView.vue @@ -134,12 +134,17 @@ diff --git a/src/views/customer/CustomerDetailView.vue b/src/views/customer/CustomerDetailView.vue index 8bdd81d..18c48a1 100644 --- a/src/views/customer/CustomerDetailView.vue +++ b/src/views/customer/CustomerDetailView.vue @@ -278,7 +278,7 @@ @@ -300,7 +300,7 @@ @@ -318,7 +318,7 @@ @@ -371,11 +371,6 @@
- - - - - @@ -386,11 +381,6 @@ import { getCustomerDetail, updateCustomer, deleteCustomer, restoreCustomer } fr import { ElMessage, ElMessageBox } from 'element-plus'; import { ArrowLeft, Edit, Delete, RefreshLeft, Right, Search } from '@element-plus/icons-vue'; -// [수정] 모달 Import 경로 수정 (components 폴더 확인) -import AsDetailModal from '@/components/product/AsDetailModal.vue'; -import CouponDetailModal from '@/views/campaign/CouponDetailModal.vue'; -import PromotionDetailModal from '@/views/campaign/PromotionDetailModal.vue'; - const route = useRoute(); const router = useRouter(); const customerId = route.params.id; @@ -398,16 +388,6 @@ const customerId = route.params.id; const loading = ref(false); const activeTab = ref(route.query.tab || 'general'); -// [수정] 모달 상태 변수 (견적 모달은 제거됨) -const showAsModal = ref(false); -const selectedAsId = ref(null); - -const showCouponModal = ref(false); -const selectedCouponId = ref(null); - -const showPromotionModal = ref(false); -const selectedPromotionId = ref(null); - const isEditMode = ref(false); const customer = ref({ historyList: [], segmentHistoryList: [], supportList: [], quoteList: [], @@ -455,35 +435,36 @@ const activeBizTab = computed({ set: (val) => updateUrlTab(val) }); -// [수정] 상세 이동 핸들러 (라우터 경로 및 파라미터 수정) -// * 주의: row.id (숫자)를 넘겨받아 해당 ID 경로로 이동합니다. -const goContractDetail = (id) => { - router.push(`/contracts/${id}`); -}; -const goSupportDetail = (id) => { - router.push(`/cs/supports/${id}`); -}; -const goFeedbackDetail = (id) => { - router.push(`/cs/feedbacks/${id}`); -}; -const goQuoteDetail = (id) => { - router.push(`/quote/${id}`); +// 페이지 이동 핸들러 +const goContractDetail = (id) => { router.push(`/contracts/${id}`); }; +const goSupportDetail = (id) => { router.push(`/cs/supports/${id}`); }; +const goFeedbackDetail = (id) => { router.push(`/cs/feedbacks/${id}`); }; +const goQuoteDetail = (id) => { router.push(`/quote/${id}`); }; + +// [수정] 목록 페이지로 이동하며 키워드 전달 +// 경로는 src/router/index.js 기준이며, keyword 쿼리를 넘깁니다. +const goCouponList = (code) => { + router.push({ + path: '/campaign/coupons', + query: { keyword: code } + }); }; -// [수정] 모달 오픈 핸들러 (ID 사용) -const openAsDetail = (id) => { - selectedAsId.value = id; - showAsModal.value = true; -}; -const openCouponDetail = (id) => { - selectedCouponId.value = id; - showCouponModal.value = true; -}; -const openPromotionDetail = (id) => { - selectedPromotionId.value = id; - showPromotionModal.value = true; +const goPromotionList = (code) => { + router.push({ + path: '/campaign/promotions', + query: { keyword: code } + }); }; +const goAsList = () => { + // AS는 코드 대신 '고객사 이름'으로 검색한다고 가정 + const companyName = customer.value.name; + router.push({ + path: '/as', + query: { keyword: companyName } + }); +}; const fetchData = async () => { loading.value = true; diff --git a/src/views/product/AsListView.vue b/src/views/product/AsListView.vue index c9362f5..0d020e8 100644 --- a/src/views/product/AsListView.vue +++ b/src/views/product/AsListView.vue @@ -187,6 +187,12 @@ import SummaryCard from '@/components/product/SummaryCard.vue' import AsDetailModal from '@/components/product/AsDetailModal.vue' import AsCreateModal from '@/components/product/AsCreateModal.vue' +// [추가 1] +import { useRoute } from 'vue-router'; + +// [추가 2] +const route = useRoute(); + // 상태 const summary = ref({}) const list = ref([]) // 화면에 보여줄 목록 @@ -306,6 +312,15 @@ const changePage = (p) => { // 생명주기 onMounted(() => { fetchSummary() + + // [추가] URL 쿼리 파라미터(keyword)가 있다면 검색창에 자동으로 입력 + if (route.query.keyword) { + // 1. 검색 객체에 값 주입 + search.value.keyword = route.query.keyword; + // 2. 페이지 초기화 + page.value.current = 1; + } + fetchList() fetchNextWeek() }) From b080043939153ae57acb8b7cefd30edb909da071 Mon Sep 17 00:00:00 2001 From: Seojin Yun Date: Sun, 4 Jan 2026 09:57:23 +0900 Subject: [PATCH 32/53] =?UTF-8?q?reform=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/campaign/CouponCreateModal.vue | 17 +++++++++-------- src/views/campaign/PromotionCreateModal.vue | 18 +++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/views/campaign/CouponCreateModal.vue b/src/views/campaign/CouponCreateModal.vue index ed77a3b..f82e3e6 100644 --- a/src/views/campaign/CouponCreateModal.vue +++ b/src/views/campaign/CouponCreateModal.vue @@ -265,14 +265,6 @@ const rules = { ], }; -// props.recommendId 변화 감지 -watch(() => props.recommendId, async (newId) => { - if (newId) { - await fetchRecommendCoupon(newId) - } else { - resetForm() - } -}, { immediate: true }) const resetForm = () => { form.name = ''; @@ -290,6 +282,15 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; +// props.recommendId 변화 감지 +watch(() => props.recommendId, async (newId) => { + if (newId) { + await fetchRecommendCoupon(newId) + } else { + resetForm() + } +}, { immediate: true }) + const handleClose = () => { emit('update:visible', false); }; diff --git a/src/views/campaign/PromotionCreateModal.vue b/src/views/campaign/PromotionCreateModal.vue index b2e32a4..076e9a9 100644 --- a/src/views/campaign/PromotionCreateModal.vue +++ b/src/views/campaign/PromotionCreateModal.vue @@ -200,15 +200,6 @@ const rules = { ], }; -watch(() => props.recommendId, async (newId) => { - if (newId) { - await fetchRecommendPromotion(newId) - } else { - // 모달 닫힐 때 폼 초기화 - resetForm() - } -}, { immediate: true }) - const resetForm = () => { form.name = ''; form.startDate = null; @@ -221,6 +212,15 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; +watch(() => props.recommendId, async (newId) => { + if (newId) { + await fetchRecommendPromotion(newId) + } else { + // 모달 닫힐 때 폼 초기화 + resetForm() + } +}, { immediate: true }) + const handleClose = () => { emit('update:visible', false); }; From 57cebc14961a2229822e2b096bf096d1a393f4b4 Mon Sep 17 00:00:00 2001 From: thdgudtjr0415 Date: Sun, 4 Jan 2026 10:24:25 +0900 Subject: [PATCH 33/53] =?UTF-8?q?=EA=B3=A0=EA=B0=9D=20=EB=B6=84=EC=84=9D?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=EB=90=98=EB=8A=94=20=EC=88=AB=EC=9E=90=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0#27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/analysis/SegmentCustomersModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/analysis/SegmentCustomersModal.vue b/src/components/analysis/SegmentCustomersModal.vue index a398554..06fd56d 100644 --- a/src/components/analysis/SegmentCustomersModal.vue +++ b/src/components/analysis/SegmentCustomersModal.vue @@ -33,7 +33,7 @@ {{ c.segmentName }} - {{ fmt(c.customerCount) }}개사 + From db02e1c5e2b290731d2dea1ed32c4b0fd0e78ee6 Mon Sep 17 00:00:00 2001 From: Seojin Yun Date: Sun, 4 Jan 2026 12:07:30 +0900 Subject: [PATCH 34/53] =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/campaign/CouponCreateModal.vue | 11 ++++++----- src/views/campaign/PromotionCreateModal.vue | 12 ++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/views/campaign/CouponCreateModal.vue b/src/views/campaign/CouponCreateModal.vue index f82e3e6..90a00c5 100644 --- a/src/views/campaign/CouponCreateModal.vue +++ b/src/views/campaign/CouponCreateModal.vue @@ -282,11 +282,10 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; -// props.recommendId 변화 감지 -watch(() => props.recommendId, async (newId) => { - if (newId) { +watch([() => props.recommendId, () => props.visible], async ([newId, isVisible]) => { + if (newId && isVisible) { await fetchRecommendCoupon(newId) - } else { + } else if (!isVisible) { resetForm() } }, { immediate: true }) @@ -338,7 +337,9 @@ const handleSubmit = () => { maxNum: form.maxNum, segmentName: form.segmentName, }); - await api.put(`/recommend/coupon/update/${props.recommendId}`); + if (props.recommendId) { + await api.put(`/recommend/coupon/update/${props.recommendId}`); + } ElMessage.success('쿠폰이 등록되었습니다.'); emit('created'); emit('update:visible', false); diff --git a/src/views/campaign/PromotionCreateModal.vue b/src/views/campaign/PromotionCreateModal.vue index 076e9a9..aa4a022 100644 --- a/src/views/campaign/PromotionCreateModal.vue +++ b/src/views/campaign/PromotionCreateModal.vue @@ -212,11 +212,10 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; -watch(() => props.recommendId, async (newId) => { - if (newId) { +watch([() => props.recommendId, () => props.visible], async ([newId, isVisible]) => { + if (newId && isVisible) { await fetchRecommendPromotion(newId) - } else { - // 모달 닫힐 때 폼 초기화 + } else if (!isVisible) { resetForm() } }, { immediate: true }) @@ -276,8 +275,9 @@ const handleSubmit = () => { content: form.content, segmentName: form.segmentName, }); - await api.put(`/recommend/promotion/update/${props.recommendId}`); - + if (props.recommendId) { + await api.put(`/recommend/promotion/update/${props.recommendId}`); + } ElMessage.success('프로모션이 등록되었습니다.'); emit('created'); // 부모에서 목록 재조회 emit('update:visible', false); From 63812aa3ce82afb3fcc393b77676ce2f20543276 Mon Sep 17 00:00:00 2001 From: Kjandgo Date: Sun, 4 Jan 2026 13:50:30 +0900 Subject: [PATCH 35/53] =?UTF-8?q?refact:=20#16=20=EA=B2=B0=EC=9E=AC=20?= =?UTF-8?q?=EC=8A=B9=EC=9D=B8/=EB=B0=98=EB=A0=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Sidebar.vue | 2 ++ src/views/notification/NotificationCenterView.vue | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 3c886ac..b0a8c8d 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -373,6 +373,8 @@ const getIcon = (type) => { return Calendar; case "QUOTE_INSERT": return DocumentCopy; + case "REJECT": + return Close; default: return Bell; } diff --git a/src/views/notification/NotificationCenterView.vue b/src/views/notification/NotificationCenterView.vue index fe9c14d..64abc59 100644 --- a/src/views/notification/NotificationCenterView.vue +++ b/src/views/notification/NotificationCenterView.vue @@ -104,7 +104,7 @@ From eb4f6531c6b9b31bd4cfcfcab4c6a0a202f48dba Mon Sep 17 00:00:00 2001 From: Seojin Yun Date: Sat, 3 Jan 2026 20:04:27 +0900 Subject: [PATCH 43/53] =?UTF-8?q?=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/CampaignWorkbenchMock.vue | 54 +---- .../dashboard/CouponWorkbenchMock.vue | 227 ++++++++++++++++++ src/components/dashboard/ProductStatus.vue | 4 - src/views/dashboard/DashboardView.vue | 2 + 4 files changed, 233 insertions(+), 54 deletions(-) create mode 100644 src/components/dashboard/CouponWorkbenchMock.vue diff --git a/src/components/dashboard/CampaignWorkbenchMock.vue b/src/components/dashboard/CampaignWorkbenchMock.vue index aec2cb0..9537028 100644 --- a/src/components/dashboard/CampaignWorkbenchMock.vue +++ b/src/components/dashboard/CampaignWorkbenchMock.vue @@ -2,8 +2,7 @@
-
캠페인 워크벤치
-
승격 2건
+
프로모션 워크벤치
@@ -29,26 +28,6 @@
- - -
-
- - -
-
{{ coupon.name }}
-
대상: {{ coupon.segmentName }}
-
-
- - -
@@ -62,7 +41,6 @@ import api from '@/api/axios'; const router = useRouter(); const loading = ref(false); const promotion = ref([]); -const coupon = ref([]); const fetchPromotionList = async () => { loading.value = true; @@ -77,22 +55,9 @@ const fetchPromotionList = async () => { } }; -const fetchCouponList = async () => { - loading.value = true; - try { - const res = await api.get('/recommend/coupon/read-one'); - coupon.value = res.data; - } catch (e) { - ElMessage.error('추천 쿠폰 목록을 불러오지 못했습니다.'); - console.error(e); - } finally { - loading.value = false; - } -}; onMounted(() => { - fetchPromotionList(), - fetchCouponList(); + fetchPromotionList() }); /** @@ -101,8 +66,6 @@ onMounted(() => { */ const routeMap = { PROMOTION_CREATE: { name: "promotion-list" }, // 프로모션 생성 - COUPON_CREATE: { name: "coupon-list" }, // 쿠폰 발급 - CAMPAIGN_SETTING: { name: "campaign-setting" }, // 캠페인 설정 -> 이부분 고민하기 }; const go = (key) => { @@ -117,9 +80,10 @@ const go = (key) => { background: #fff; border: 1px solid #eee; border-radius: 12px; - height: 100%; + height: 48%; width: 100%; padding: 16px 16px 14px; + margin-bottom: 12px; } /* Header */ @@ -138,16 +102,6 @@ const go = (key) => { letter-spacing: -0.2px; } -.wb-pill { - font-size: 12px; - color: #6b7280; - border: 1px solid #e5e7eb; - background: #f9fafb; - padding: 6px 10px; - border-radius: 999px; - white-space: nowrap; -} - /* List */ .wb-list { border-radius: 10px; diff --git a/src/components/dashboard/CouponWorkbenchMock.vue b/src/components/dashboard/CouponWorkbenchMock.vue new file mode 100644 index 0000000..ec4452e --- /dev/null +++ b/src/components/dashboard/CouponWorkbenchMock.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/src/components/dashboard/ProductStatus.vue b/src/components/dashboard/ProductStatus.vue index addf35f..0359154 100644 --- a/src/components/dashboard/ProductStatus.vue +++ b/src/components/dashboard/ProductStatus.vue @@ -54,10 +54,6 @@ - -
- -
diff --git a/src/views/dashboard/DashboardView.vue b/src/views/dashboard/DashboardView.vue index 05450bb..ddc9121 100644 --- a/src/views/dashboard/DashboardView.vue +++ b/src/views/dashboard/DashboardView.vue @@ -67,6 +67,7 @@
+
@@ -87,6 +88,7 @@ import SegmentAnalysisChart from "@/components/analysis/SegmentAnalysisChart.vue import QuarterCustomerChart from "@/components/dashboard/QuarterCustomerChart.vue"; import SegmentDistribution from "@/components/analysis/SegmentDistribution.vue"; import CampaignWorkbenchMock from "@/components/dashboard/CampaignWorkbenchMock.vue"; +import CouponWorkbenchMock from "@/components/dashboard/CouponWorkbenchMock.vue"; const authStore = useAuthStore(); const router = useRouter(); From 75c37d770dd7e3b21f4e41fb8294a47dad2c6ace Mon Sep 17 00:00:00 2001 From: Seojin Yun Date: Sun, 4 Jan 2026 09:57:23 +0900 Subject: [PATCH 44/53] =?UTF-8?q?reform=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/campaign/CouponCreateModal.vue | 17 +++++++++-------- src/views/campaign/PromotionCreateModal.vue | 18 +++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/views/campaign/CouponCreateModal.vue b/src/views/campaign/CouponCreateModal.vue index ed77a3b..f82e3e6 100644 --- a/src/views/campaign/CouponCreateModal.vue +++ b/src/views/campaign/CouponCreateModal.vue @@ -265,14 +265,6 @@ const rules = { ], }; -// props.recommendId 변화 감지 -watch(() => props.recommendId, async (newId) => { - if (newId) { - await fetchRecommendCoupon(newId) - } else { - resetForm() - } -}, { immediate: true }) const resetForm = () => { form.name = ''; @@ -290,6 +282,15 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; +// props.recommendId 변화 감지 +watch(() => props.recommendId, async (newId) => { + if (newId) { + await fetchRecommendCoupon(newId) + } else { + resetForm() + } +}, { immediate: true }) + const handleClose = () => { emit('update:visible', false); }; diff --git a/src/views/campaign/PromotionCreateModal.vue b/src/views/campaign/PromotionCreateModal.vue index b2e32a4..076e9a9 100644 --- a/src/views/campaign/PromotionCreateModal.vue +++ b/src/views/campaign/PromotionCreateModal.vue @@ -200,15 +200,6 @@ const rules = { ], }; -watch(() => props.recommendId, async (newId) => { - if (newId) { - await fetchRecommendPromotion(newId) - } else { - // 모달 닫힐 때 폼 초기화 - resetForm() - } -}, { immediate: true }) - const resetForm = () => { form.name = ''; form.startDate = null; @@ -221,6 +212,15 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; +watch(() => props.recommendId, async (newId) => { + if (newId) { + await fetchRecommendPromotion(newId) + } else { + // 모달 닫힐 때 폼 초기화 + resetForm() + } +}, { immediate: true }) + const handleClose = () => { emit('update:visible', false); }; From 29ece01ac02be984b6b2d8dae7225ba9a6dd442a Mon Sep 17 00:00:00 2001 From: thdgudtjr0415 Date: Sun, 4 Jan 2026 10:24:25 +0900 Subject: [PATCH 45/53] =?UTF-8?q?=EA=B3=A0=EA=B0=9D=20=EB=B6=84=EC=84=9D?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=EB=90=98=EB=8A=94=20=EC=88=AB=EC=9E=90=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0#27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/analysis/SegmentCustomersModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/analysis/SegmentCustomersModal.vue b/src/components/analysis/SegmentCustomersModal.vue index a398554..06fd56d 100644 --- a/src/components/analysis/SegmentCustomersModal.vue +++ b/src/components/analysis/SegmentCustomersModal.vue @@ -33,7 +33,7 @@ {{ c.segmentName }} - {{ fmt(c.customerCount) }}개사 + From 402ca3e398df62f72ba04693e0fc51608d7abe84 Mon Sep 17 00:00:00 2001 From: Seojin Yun Date: Sun, 4 Jan 2026 12:07:30 +0900 Subject: [PATCH 46/53] =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/campaign/CouponCreateModal.vue | 11 ++++++----- src/views/campaign/PromotionCreateModal.vue | 12 ++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/views/campaign/CouponCreateModal.vue b/src/views/campaign/CouponCreateModal.vue index f82e3e6..90a00c5 100644 --- a/src/views/campaign/CouponCreateModal.vue +++ b/src/views/campaign/CouponCreateModal.vue @@ -282,11 +282,10 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; -// props.recommendId 변화 감지 -watch(() => props.recommendId, async (newId) => { - if (newId) { +watch([() => props.recommendId, () => props.visible], async ([newId, isVisible]) => { + if (newId && isVisible) { await fetchRecommendCoupon(newId) - } else { + } else if (!isVisible) { resetForm() } }, { immediate: true }) @@ -338,7 +337,9 @@ const handleSubmit = () => { maxNum: form.maxNum, segmentName: form.segmentName, }); - await api.put(`/recommend/coupon/update/${props.recommendId}`); + if (props.recommendId) { + await api.put(`/recommend/coupon/update/${props.recommendId}`); + } ElMessage.success('쿠폰이 등록되었습니다.'); emit('created'); emit('update:visible', false); diff --git a/src/views/campaign/PromotionCreateModal.vue b/src/views/campaign/PromotionCreateModal.vue index 076e9a9..aa4a022 100644 --- a/src/views/campaign/PromotionCreateModal.vue +++ b/src/views/campaign/PromotionCreateModal.vue @@ -212,11 +212,10 @@ const resetForm = () => { formRef.value && formRef.value.clearValidate(); }; -watch(() => props.recommendId, async (newId) => { - if (newId) { +watch([() => props.recommendId, () => props.visible], async ([newId, isVisible]) => { + if (newId && isVisible) { await fetchRecommendPromotion(newId) - } else { - // 모달 닫힐 때 폼 초기화 + } else if (!isVisible) { resetForm() } }, { immediate: true }) @@ -276,8 +275,9 @@ const handleSubmit = () => { content: form.content, segmentName: form.segmentName, }); - await api.put(`/recommend/promotion/update/${props.recommendId}`); - + if (props.recommendId) { + await api.put(`/recommend/promotion/update/${props.recommendId}`); + } ElMessage.success('프로모션이 등록되었습니다.'); emit('created'); // 부모에서 목록 재조회 emit('update:visible', false); From 44e1045d4c4cdd4e2871fdebcb26db24c1e3d0c6 Mon Sep 17 00:00:00 2001 From: Kjandgo Date: Sun, 4 Jan 2026 16:56:01 +0900 Subject: [PATCH 47/53] =?UTF-8?q?feat:=20#16=20=EA=B3=A0=EA=B0=9D=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D,=20=EC=A0=9C=ED=92=88=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=20=EC=95=8C=EB=A6=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Sidebar.vue | 38 ++- src/views/campaign/CouponListView.vue | 7 +- src/views/cs/SurveyCreateView.vue | 4 +- src/views/customer/CustomerDetailView.vue | 226 +++--------------- .../notification/NotificationCenterView.vue | 199 +++++++++++---- 5 files changed, 225 insertions(+), 249 deletions(-) diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index b0a8c8d..72401ea 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -4,7 +4,7 @@