Jelajahi Sumber

[선상관리] 완료 / [공통] 타이틀 수정, 프로젝트 개발내역 추가

DESKTOP-T61HUSC\user 3 minggu lalu
induk
melakukan
bf104c843d

+ 41 - 359
app/assets/scss/admin.scss

@@ -444,7 +444,6 @@ html {
     border: none;
     color: #fcfcfd;
     font-size: 24px;
-    font-family: 'FORDKOREAType';
     font-weight: 400;
     transition: all 0.3s;
 
@@ -490,7 +489,6 @@ html {
     transition: all 0.3s;
     background: transparent;
     border: none;
-    font-family: 'FORDKOREAType';
     font-weight: 400;
     padding: 0;
     cursor: pointer;
@@ -664,7 +662,6 @@ html {
   .dealer--name {
     margin: 0px;
     color: #1a1a1a;
-    font-family: FORDKOREAType, sans-serif;
     letter-spacing: 0px;
     font-weight: 400;
     text-decoration: none;
@@ -715,7 +712,6 @@ html {
   .info--label {
     margin: 0px;
     color: #666666;
-    font-family: FORDKOREAType, sans-serif;
     letter-spacing: 0px;
     font-weight: 400;
     text-decoration: none;
@@ -1126,15 +1122,6 @@ footer {
           flex-flow: wrap;
           width: 100%;
         }
-
-        &.lincoln {
-          >li {
-            @media (min-width: 1440px) {
-              //width: calc(100% / 5);
-            }
-          }
-        }
-
         >li {
           margin-bottom: -1px;
 
@@ -1489,7 +1476,6 @@ footer {
       color: var(--admin-text-primary);
       font-size: 14px;
       transition: all 0.3s ease;
-      font-family: 'FORDKOREAType', sans-serif;
 
       &:focus {
         outline: none;
@@ -1550,7 +1536,6 @@ footer {
       font-weight: 600;
       cursor: pointer;
       transition: all 0.3s ease;
-      font-family: 'FORDKOREAType', sans-serif;
 
       &:hover:not(:disabled) {
         background: var(--admin-accent-hover);
@@ -1584,7 +1569,6 @@ footer {
 // Admin Layout
 .admin--layout {
   background: var(--admin-bg-primary);
-  font-family: 'FORDKOREAType', sans-serif;
 }
 
 // Admin Header
@@ -1628,7 +1612,6 @@ footer {
     font-weight: 500;
     cursor: pointer;
     transition: all 0.3s ease;
-    font-family: 'FORDKOREAType', sans-serif;
 
     &:hover {
       background: var(--admin-bg-primary);
@@ -2017,7 +2000,6 @@ footer {
     border-radius: 6px;
     color: var(--admin-text-primary);
     font-size: 13px;
-    font-family: 'FORDKOREAType', sans-serif;
     transition: all 0.3s ease;
 
     &:focus {
@@ -2082,7 +2064,6 @@ footer {
         cursor: pointer;
         transition: all 0.3s ease;
         white-space: nowrap;
-        font-family: 'FORDKOREAType', sans-serif;
 
         &:hover {
           background: #dc2626;
@@ -2100,7 +2081,6 @@ footer {
       font-weight: 500;
       cursor: pointer;
       transition: all 0.3s ease;
-      font-family: 'FORDKOREAType', sans-serif;
 
       &:hover {
         background: var(--admin-bg-primary);
@@ -2260,10 +2240,37 @@ footer {
   align-items: center;
   gap: 20px;
 
+  &.type2{
+    flex-direction: column;
+    align-items: start;
+    gap: 8px;
+  }
+
+  .admin--search--inner--box{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    gap: 20px;
+  }
+
   .admin--search-form {
     display: flex;
     gap: 12px;
+    align-items: center;
     flex: 1;
+    .admin--quick-range{
+      display: flex;
+      gap: 8px;
+      .range--btn{
+        width: 60px;
+        font-weight: 400;
+        min-width: 60px;
+        padding: 12px 0;
+        color: #1a2b4a;
+        
+      }
+    }
   }
 
   // 검색 박스 내 모든 select, input 통일된 스타일
@@ -2282,6 +2289,17 @@ footer {
     }
   }
 
+  .admin--form-select{
+    cursor: pointer;
+    appearance: none;
+    -webkit-appearance: none;
+    -moz-appearance: none;
+    padding-right: 36px;
+    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23666B75' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
+    background-repeat: no-repeat;
+    background-position: right 12px center;
+  }
+
   .admin--search-select,
   .admin--form-select {
     width: 140px;
@@ -2472,15 +2490,16 @@ footer {
 
 // 작은 버튼
 .admin--btn-small {
-  padding: 6px 14px;
+  padding: 12px 24px;
   border: none;
   border-radius: 4px;
   font-size: 13px;
   font-weight: 500;
   cursor: pointer;
   transition: all 0.3s ease;
-  font-family: 'FORDKOREAType', sans-serif;
   white-space: nowrap;
+  line-height: normal;
+  min-width: 100px;
 
   &.admin--btn-small-primary {
     background: var(--admin-accent-primary);
@@ -2630,7 +2649,6 @@ footer {
   border-radius: 6px;
   color: #fff;
   font-size: 14px;
-  font-family: 'FORDKOREAType', sans-serif;
   cursor: pointer;
 
   &::-webkit-file-upload-button {
@@ -2643,7 +2661,6 @@ footer {
     font-weight: 500;
     cursor: pointer;
     margin-right: 12px;
-    font-family: 'FORDKOREAType', sans-serif;
   }
 }
 
@@ -2674,7 +2691,6 @@ footer {
     font-weight: 500;
     cursor: pointer;
     transition: all 0.3s ease;
-    font-family: 'FORDKOREAType', sans-serif;
 
     &:hover {
       background: #dc2626;
@@ -3363,7 +3379,6 @@ footer {
   font-weight: 500;
   cursor: pointer;
   transition: all 0.3s ease;
-  font-family: 'FORDKOREAType', sans-serif;
 
   &:hover:not(:disabled) {
     background: #1d4ed8 !important;
@@ -3439,21 +3454,6 @@ footer {
         bottom: 330px;
         pointer-events: none;
 
-        &.lincoln {
-          border: 1px solid rgba(219, 120, 77, 0.50);
-          background: #FFF8F5;
-
-          .inner--wrap {
-            li {
-              a {
-                &:hover {
-                  color: #DB784D;
-                }
-              }
-            }
-          }
-        }
-
         &.active {
           pointer-events: all;
           opacity: 1;
@@ -3516,10 +3516,6 @@ footer {
           }
         }
 
-        &.lincoln {
-          background-color: #DB784D;
-        }
-
         .ico {
           width: 24px;
           height: 24px;
@@ -4021,10 +4017,6 @@ footer {
         gap: 10px;
         display: flex;
         align-items: center;
-
-        &.lincoln {
-          background: #DB784D;
-        }
       }
 
       &.interior {
@@ -4042,9 +4034,6 @@ footer {
         display: flex;
         align-items: center;
 
-        &.lincoln {
-          background: #22292B;
-        }
       }
     }
 
@@ -4535,20 +4524,6 @@ footer {
       }
     }
   }
-
-  &.lincoln {
-    ul {
-      li {
-        >div {
-          em {
-            i {
-              color: #DB784D;
-            }
-          }
-        }
-      }
-    }
-  }
 }
 
 .title--visual {
@@ -4805,10 +4780,6 @@ footer {
                   line-height: 100%;
                   /* 12px */
                   text-transform: uppercase;
-
-                  &.lincoln {
-                    color: #FF6524;
-                  }
                 }
               }
             }
@@ -5228,14 +5199,6 @@ footer {
     margin-top: 80px;
     margin-bottom: 240px;
 
-    &.lincoln {
-      p {
-        b {
-          color: #DB784D;
-        }
-      }
-    }
-
     @media(max-width: 1024px) {
       margin-bottom: 120px;
     }
@@ -6135,10 +6098,6 @@ footer {
         display: inline-flex;
         align-items: center;
         justify-content: center;
-
-        &.lincoln {
-          background-color: #DB784D;
-        }
       }
 
       .desc {
@@ -6161,10 +6120,6 @@ footer {
           //line-height: 100%; /* 20px */
           letter-spacing: -0.4px;
           text-transform: uppercase;
-
-          &.lincoln {
-            color: #e0571c;
-          }
         }
       }
     }
@@ -6807,7 +6762,6 @@ footer {
 
     h2 {
       color: #111;
-      font-family: "Lincoln Proxima Nova";
       font-size: 30px;
       font-style: normal;
       font-weight: 700;
@@ -6819,7 +6773,6 @@ footer {
 
     >div {
       color: #444;
-      font-family: "Lincoln Proxima Nova";
       font-size: 17px;
       font-style: normal;
       font-weight: 400;
@@ -7024,259 +6977,6 @@ footer {
   }
 }
 
-.lincoln {
-  .link {
-    color: #DB784D;
-    font-size: 20px;
-    font-style: normal;
-    font-weight: 400;
-    line-height: 100%;
-    letter-spacing: -0.4px;
-    text-decoration-line: underline;
-    text-decoration-style: solid;
-    text-decoration-skip-ink: auto;
-    text-decoration-thickness: auto;
-    text-underline-offset: auto;
-  }
-
-  .lincoln--prm--service {
-    background: #FAFAFA;
-  }
-
-  .btn--sky {
-    background: #DB784D;
-
-    &.reverse {
-      background: #fff;
-      border: 1px solid #DB784D;
-      color: #DB784D;
-    }
-  }
-
-  .title--visual {
-    h2 {
-      font-weight: 700;
-    }
-  }
-
-  .ovwner--wrapper {
-    .title--visual {
-      .desc {
-        font-weight: 400;
-      }
-    }
-  }
-
-  .tfs--drop--menus {
-    >ul {
-      >li {
-        .drop--contents {
-          p {
-            color: #333;
-            font-size: 17px;
-            font-style: normal;
-            font-weight: 400;
-            //line-height: 100%; /* 17px */
-            letter-spacing: -0.34px;
-            text-transform: uppercase;
-            padding-left: 10px;
-
-            &::before {
-              display: none;
-            }
-          }
-
-          ul {
-            >li {
-              color: #444;
-              font-size: 17px;
-              font-style: normal;
-              font-weight: 400;
-              //line-height: 100%; /* 17px */
-              letter-spacing: -0.34px;
-              text-transform: uppercase;
-            }
-          }
-
-          h4 {
-            color: #333;
-            font-size: 17px;
-            font-style: normal;
-            font-weight: 400;
-            line-height: 100%;
-            /* 17px */
-            letter-spacing: -0.34px;
-            text-transform: uppercase;
-            position: relative;
-            padding-left: 20px;
-            margin-bottom: 10px;
-
-            &:before {
-              content: '';
-              display: block;
-              width: 3px;
-              height: 3px;
-              background: #313131;
-              position: absolute;
-              top: 5px;
-              left: 5px;
-            }
-          }
-
-          h2 {
-            color: #333;
-            font-size: 17px;
-            font-style: normal;
-            font-weight: 400;
-            line-height: 100%;
-            /* 17px */
-            letter-spacing: -0.34px;
-            text-transform: uppercase;
-
-            &:before {
-              display: none;
-            }
-
-            padding-left:0px;
-          }
-
-          div {
-            color: #444;
-            font-size: 17px;
-            font-style: normal;
-            font-weight: 400;
-            line-height: 1.6;
-            letter-spacing: -0.34px;
-
-            &.phone {
-              color: #E0571C;
-              font-size: 25px;
-              font-style: normal;
-              font-weight: 700;
-              line-height: 100%;
-              /* 25px */
-              letter-spacing: -0.5px;
-              padding-left: 0px;
-              text-transform: uppercase;
-              margin-bottom: 0px;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  .nav--dis--wrap {
-    p {
-      color: #333;
-      font-size: 16px;
-      font-style: normal;
-      font-weight: 400;
-      //line-height: 100%; /* 16px */
-      text-transform: uppercase;
-    }
-
-    .dis--btn {
-      color: #222;
-      font-size: 17px;
-      font-style: normal;
-      font-weight: 700;
-      line-height: 100%;
-      /* 17px */
-      text-transform: uppercase;
-    }
-  }
-
-  .breadcrumbs--wrap {
-    background: #111;
-
-    .menu--wrap {
-      .sub--menu--wrap {
-        .nav--wrap {
-          .sub--menu2 {
-            &.active {
-              color: #DB784D !important;
-            }
-
-            &:hover {
-              color: #DB784D !important;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  .swiper--banner--wrapper3 {
-    .top--text--wrap {
-      >div {
-        font-weight: 400;
-      }
-    }
-  }
-
-  .car--price--small--pic--wrap {
-    >div {
-      .car--list--wrap {
-        ul {
-          li {
-            .desc--wrap {
-              .price--wrap {
-                font-weight: 400;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  .models--visual--grid {
-    ul {
-      li {
-        .desc--wrap {
-          h2 {
-            font-size: 26px;
-            font-weight: 700;
-          }
-
-          .captions {
-            font-weight: 400;
-          }
-        }
-      }
-    }
-  }
-
-  .caution--text--foot {
-    .caution--text {
-      font-weight: 400;
-    }
-  }
-
-  .grid--banner--wrapper {
-    .grid--items {
-      .grid--desc {
-        max-width: 710px;
-        width: 100%;
-
-        h2 {
-          color: #000;
-          font-size: 30px;
-          font-style: normal;
-          font-weight: 700;
-          line-height: 1.4;
-          text-transform: capitalize;
-        }
-
-        .captions {
-          font-weight: 400;
-        }
-      }
-    }
-  }
-}
-
 // 전체 메뉴 (사이트맵)
 .all--menu--wrapper {
   position: fixed;
@@ -7530,24 +7230,6 @@ footer {
               }
             }
 
-            .lincoln--link {
-              padding-left: 20px;
-              position: relative;
-              font-size: 16px;
-              font-weight: 500;
-              color: #000;
-
-              &::before {
-                content: '';
-                position: absolute;
-                width: 5px;
-                top: 8px;
-                left: 0;
-                height: 5px;
-                background-color: #333;
-              }
-            }
-
             h4 {
               padding-left: 20px;
               position: relative;

+ 1 - 23
app/components/admin/AccountLockedModal.vue

@@ -49,7 +49,7 @@
   };
 </script>
 
-<style>
+<style scope>
   .admin--modal-overlay {
     position: fixed;
     top: 0;
@@ -144,26 +144,4 @@
     justify-content: center;
     flex-shrink: 0;
   }
-
-  .admin--btn-small {
-    padding: 10px 24px;
-    border: none;
-    border-radius: 4px;
-    font-size: 14px;
-    font-weight: 500;
-    cursor: pointer;
-    transition: all 0.3s ease;
-    font-family: "FORDKOREAType", sans-serif;
-    white-space: nowrap;
-    min-width: 100px;
-  }
-
-  .admin--btn-small-primary {
-    background: var(--admin-accent-primary, #217346);
-    color: #ffffff;
-  }
-
-  .admin--btn-small-primary:hover:not(:disabled) {
-    background: var(--admin-accent-hover, #1a5c37);
-  }
 </style>

+ 2 - 6
app/components/admin/DatePicker.vue

@@ -17,7 +17,6 @@ import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
 import flatpickr from 'flatpickr'
 import { Korean } from 'flatpickr/dist/l10n/ko'
 import 'flatpickr/dist/flatpickr.min.css'
-import 'flatpickr/dist/themes/dark.css'
 
 const props = defineProps({
   modelValue: {
@@ -63,8 +62,6 @@ onMounted(() => {
     onChange: (_selectedDates, dateStr) => {
       emit('update:modelValue', dateStr)
     },
-    // 다크 테마 설정
-    theme: 'dark',
     // 월/년 선택 드롭다운 활성화
     monthSelectorType: 'dropdown',
     // 시간 선택 비활성화
@@ -116,7 +113,7 @@ onBeforeUnmount(() => {
 }
 
 .admin--datepicker .admin--form-input:read-only {
-  background: var(--admin-bg-tertiary, #252525);
+  background-color: #fff;
   color: var(--admin-text-primary, #ffffff) !important;
 }
 
@@ -126,8 +123,7 @@ onBeforeUnmount(() => {
 
 .admin--datepicker .admin--form-input:focus {
   outline: none;
-  border-color: var(--admin-accent-primary, #bb0a30);
-  box-shadow: 0 0 0 3px rgba(187, 10, 48, 0.1);
+  /* box-shadow: 0 0 0 3px rgba(187, 10, 48, 0.1); */
 }
 
 /* 다크 테마 커스터마이징 */

+ 0 - 38
app/components/admin/PasswordChangeRecommendModal.vue

@@ -296,42 +296,4 @@ const changePassword = async () => {
   justify-content: flex-end;
   flex-shrink: 0;
 }
-
-.admin--btn-small {
-  padding: 8px 16px;
-  border: none;
-  border-radius: 4px;
-  font-size: 13px;
-  font-weight: 500;
-  cursor: pointer;
-  transition: all 0.3s ease;
-  font-family: 'FORDKOREAType', sans-serif;
-  white-space: nowrap;
-}
-
-.admin--btn-small:disabled {
-  opacity: 0.5;
-  cursor: not-allowed;
-}
-
-.admin--btn-small-secondary {
-  background: #f5f5f5;
-  color: #333333;
-  border: 1px solid #e0e0e0;
-}
-
-.admin--btn-small-secondary:hover:not(:disabled) {
-  background: #eeeeee;
-  border-color: var(--admin-accent-primary, #217346);
-  color: #333333;
-}
-
-.admin--btn-small-primary {
-  background: var(--admin-accent-primary, #217346);
-  color: #ffffff;
-}
-
-.admin--btn-small-primary:hover:not(:disabled) {
-  background: var(--admin-accent-hover, #1a5c37);
-}
 </style>

+ 91 - 30
app/pages/site-manager/onboard/list.vue

@@ -1,36 +1,53 @@
 <template>
   <div class="admin--field-list">
     <!-- 상단 검색/액션 영역 -->
-    <div class="admin--search-box">
-      <div class="admin--search-form">
-        <select v-model="searchField" class="admin--form-select admin--search-select">
-          <option value="">전체</option>
-          <option value="field">분야</option>
-          <option value="area">지역명</option>
-          <option value="name">선상명</option>
-        </select>
-        <input
-          v-model="searchQuery"
-          type="text"
-          placeholder="검색어 입력"
-          @keyup.enter="onSearch"
-          class="admin--form-input admin--search-input"
-        />
-        <select v-model="filterPartnership" @change="onSearch" class="admin--form-select admin--search-select">
-          <option value="">전체</option>
-          <option value="Y">제휴</option>
-          <option value="N">비제휴</option>
-        </select>
-        <select v-model="filterStatus" @change="onSearch" class="admin--form-select admin--search-select">
-          <option value="">전체</option>
-          <option value="Y">사용중</option>
-          <option value="N">미사용</option>
-        </select>
-        <button @click="onSearch" class="admin--btn-small admin--btn-small-primary">검색</button>
-        <button @click="resetSearch" class="admin--btn-small admin--btn-small-secondary">초기화</button>
+    <div class="admin--search-box type2">
+      <div class="admin--search--inner--box">
+        <div class="admin--search-form">
+          <select v-model="searchField" class="admin--form-select admin--search-select">
+            <option value="">전체</option>
+            <option value="field">분야</option>
+            <option value="area">지역명</option>
+            <option value="name">선상명</option>
+          </select>
+          <input
+            v-model="searchQuery"
+            type="text"
+            placeholder="검색어 입력"
+            @keyup.enter="onSearch"
+            class="admin--form-input admin--search-input"
+          />
+          <select v-model="filterPartnership" @change="onSearch" class="admin--form-select admin--search-select">
+            <option value="">전체</option>
+            <option value="Y">제휴</option>
+            <option value="N">비제휴</option>
+          </select>
+          <select v-model="filterStatus" @change="onSearch" class="admin--form-select admin--search-select">
+            <option value="">전체</option>
+            <option value="Y">사용중</option>
+            <option value="N">미사용</option>
+          </select>
+          <button @click="onSearch" class="admin--btn-small admin--btn-small-primary">검색</button>
+          <button @click="resetSearch" class="admin--btn-small admin--btn-small-secondary">초기화</button>
+        </div>
+        <div class="admin--search-actions">
+          <button class="admin--btn-add" @click="goToCreate">+ 새 선상 추가</button>
+        </div>
       </div>
-      <div class="admin--search-actions">
-        <button class="admin--btn-add" @click="goToCreate">+ 새 선상 추가</button>
+      <div class="admin--search--inner--box">
+        <div class="admin--search-form">
+          <DatePicker v-model="startDate" placeholder="📅 YYYY-MM-DD" />
+          <span class="admin--date-separator">-</span>
+          <DatePicker v-model="endDate" placeholder="📅 YYYY-MM-DD" />
+          <div class="admin--quick-range">
+            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('today')">오늘</button>
+            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('7d')">7일</button>
+            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('15d')">15일</button>
+            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('1m')">1개월</button>
+            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('3m')">3개월</button>
+            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('1y')">1년</button>
+          </div>
+        </div>
       </div>
     </div>
 
@@ -142,6 +159,7 @@
 <script setup>
   import { ref, computed, onMounted } from "vue";
   import { useRouter } from "vue-router";
+  import DatePicker from "~/components/admin/DatePicker.vue";
 
   definePageMeta({
     layout: "admin",
@@ -162,6 +180,45 @@
   const searchQuery = ref("");
   const filterPartnership = ref(""); // '', Y, N
   const filterStatus = ref("");      // '', Y, N
+  const startDate = ref("");         // YYYY-MM-DD
+  const endDate = ref("");           // YYYY-MM-DD
+
+  // YYYY-MM-DD 포맷터
+  const toYMD = (d) => {
+    const y = d.getFullYear();
+    const m = String(d.getMonth() + 1).padStart(2, "0");
+    const day = String(d.getDate()).padStart(2, "0");
+    return `${y}-${m}-${day}`;
+  };
+
+  // 빠른 기간 선택 (오늘 기준)
+  const setRange = (kind) => {
+    const today = new Date();
+    const end = toYMD(today);
+    const startDt = new Date();
+    switch (kind) {
+      case "today":
+        break;
+      case "7d":
+        startDt.setDate(startDt.getDate() - 7);
+        break;
+      case "15d":
+        startDt.setDate(startDt.getDate() - 15);
+        break;
+      case "1m":
+        startDt.setMonth(startDt.getMonth() - 1);
+        break;
+      case "3m":
+        startDt.setMonth(startDt.getMonth() - 3);
+        break;
+      case "1y":
+        startDt.setFullYear(startDt.getFullYear() - 1);
+        break;
+    }
+    startDate.value = toYMD(startDt);
+    endDate.value = end;
+    onSearch();
+  };
 
   // 보이는 페이지 번호 계산
   const visiblePages = computed(() => {
@@ -193,6 +250,8 @@
     }
     if (filterPartnership.value) params.partnership = filterPartnership.value;
     if (filterStatus.value) params.status = filterStatus.value;
+    if (startDate.value) params.start_date = startDate.value;
+    if (endDate.value) params.end_date = endDate.value;
 
     const { data, error } = await get("/onboard/list", { params });
 
@@ -222,6 +281,8 @@
     searchQuery.value = "";
     filterPartnership.value = "";
     filterStatus.value = "";
+    startDate.value = "";
+    endDate.value = "";
     currentPage.value = 1;
     loadOnboards();
   };
@@ -259,4 +320,4 @@
   onMounted(() => {
     loadOnboards();
   });
-</script>
+</script>

+ 10 - 0
backend/app/Controllers/Api/OnboardController.php

@@ -31,6 +31,8 @@ class OnboardController extends BaseApiController
             $search      = trim((string) $this->request->getGet('search'));
             $partnership = trim((string) $this->request->getGet('partnership'));
             $status      = trim((string) $this->request->getGet('status'));
+            $startDate   = trim((string) $this->request->getGet('start_date')); // YYYY-MM-DD
+            $endDate     = trim((string) $this->request->getGet('end_date'));   // YYYY-MM-DD
 
             $db = $this->getDB();
             $builder = $db->table($this->table . ' o');
@@ -61,6 +63,14 @@ class OnboardController extends BaseApiController
                 $builder->where('o.status_YN', $status);
             }
 
+            // 등록일 기간 필터 (YYYY-MM-DD)
+            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate)) {
+                $builder->where('o.created_at >=', $startDate . ' 00:00:00');
+            }
+            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $endDate)) {
+                $builder->where('o.created_at <=', $endDate . ' 23:59:59');
+            }
+
             $total = $builder->countAllResults(false);
 
             // 계좌번호는 목록에서 제외 (민감정보)

+ 115 - 0
info.md

@@ -0,0 +1,115 @@
+# Piratezone — 프로젝트 정보
+
+선상 낚시 예약 서비스의 **사이트 관리자(Admin)** 와 사용자 사이트.
+
+---
+
+## 🏗️ 기술 스택
+
+| | |
+|---|---|
+| 프론트엔드 | Nuxt 3 (Vue 3), SCSS, flatpickr (DatePicker) |
+| 백엔드 | CodeIgniter 4 (PHP) |
+| DB | MySQL / MariaDB |
+| 폰트 | Pretendard (로컬, woff2 + woff) |
+| 외부 API | Daum 우편번호, Google Geocoding |
+| 암호화 | CI4 Encryption (AES-256-CTR + HMAC-SHA512) |
+
+---
+
+## ✅ 완료된 기능 (메뉴별)
+
+### 🔐 인증 / 로그인
+- **페이지**: `/site-manager` (로그인 폼, 좌우 50/50 레이아웃)
+- **API**: `POST /api/auth/login`, `POST /api/auth/logout`, `GET /api/auth/check`
+- 토큰 기반 인증, 비밀번호 변경 권장 모달, 계정 잠금 모달
+- 로그인 후 `/site-manager/dashboard` 로 이동
+
+### 👤 관리자 관리
+- **페이지**: `/site-manager/admins`
+- **API**: `GET /api/admin`, `POST/PUT/DELETE /api/admin/:id`, 비밀번호 변경, 잠금 해제, 아이디 중복 확인
+- 검색(아이디/이름) + 역할·상태 필터 + 페이지네이션
+- 본인 계정 삭제 방지, 5회 실패 시 잠금 표시
+
+### 🎣 낚시분야 관리 (Field)
+- **테이블**: `fishing_field` (id, name, weight, status_YN, deleted_YN, created_at, updated_at)
+- **페이지**: list / create / detail / edit
+- **API**: `GET /api/field/list`, `GET/POST/PUT/DELETE /api/field/:id`
+- 분야명 1~30자, 중복 불가
+- 가중치 0.0~1.0 (소수점 1자리 검증)
+- 상태(사용중/미사용) 토글, soft delete
+
+### 🗺️ 낚시지역 관리 (Area)
+- **테이블**: `fishing_area` (id, name, deleted_YN, created_at, updated_at)
+- **페이지**: list / create / detail / edit
+- **API**: `GET /api/area/list`, `GET/POST/PUT/DELETE /api/area/:id`
+- 지역명 1~20자, 중복 불가, soft delete
+
+### ⚓ 선상 관리 (Onboard)
+- **테이블**: `onboard` (id, field_id, area_id, name, area_detail, tonnage, capacity, zip_code, address, address_detail, address_refer, lat, lng, bank_code, account_number(암호화), account_holder, partnership_YN, status_YN, deleted_YN, created_at, updated_at)
+- **테이블**: `onboard_photos` (FK → onboard, ON DELETE CASCADE, hard delete)
+- **페이지**: list / create / detail / edit
+- **API**:
+  - `GET /api/onboard/list` (분야·지역 JOIN, 검색·필터·페이지네이션)
+  - `GET /api/onboard/:id` (사진 목록 포함, 계좌번호 복호화)
+  - `POST /api/onboard` (계좌번호 암호화)
+  - `PUT /api/onboard/:id` (계좌번호 재암호화)
+  - `DELETE /api/onboard/:id` (soft delete)
+  - `POST /api/onboard/:id/photos` (다중 사진 업로드, MIME 검증)
+  - `DELETE /api/onboard/photo/:photoId` (파일 + DB hard delete)
+- **주요 기능**:
+  - 분야/지역 select (옵션 역순 정렬 — 수도권 등 초기 등록이 위로)
+  - **Daum 우편번호 검색** + 선택 시 **Google Geocoding 좌표 자동 입력**
+  - **계좌번호 양방향 암호화**: 저장 시 암호화, 상세/수정에서 복호화된 평문 표시
+  - 비제휴 선택 시 계좌 행 자동 숨김 + 값 초기화
+  - **다중 사진 업로드**: 미리보기, 개별 삭제, 첫 장 "대표" 뱃지, 10MB 제한
+  - **수정에서 기존 사진 삭제** (즉시 서버 반영, 파일 + DB)
+  - 검색 4종 (검색대상 select + 검색어 + 제휴 필터 + 상태 필터)
+  - **기간 검색** (등록일, DatePicker + 빠른 버튼: 오늘/7일/15일/1개월/3개월/1년)
+  - 행 클릭 → 상세, "수정" 버튼 → edit
+
+---
+
+## 🟡 작업 예정 (메뉴)
+
+- ⛵ 낚시터 관리 (Fishing Spot)
+- 📊 대시보드 (현재 빈 페이지)
+
+---
+
+## ⚙️ 환경 설정 메모
+
+### 프론트 `.env` (Nuxt 루트)
+```
+NUXT_PUBLIC_API_BASE=...           # 백엔드 base URL
+NUXT_PUBLIC_IMAGE_BASE=...         # 이미지 호스트 (운영 도메인)
+NUXT_PUBLIC_MEDIA_BASE=...
+NUXT_PUBLIC_GOOGLE_MAP_KEY=...     # Google Geocoding 키 (위도, 경도 가져오는 데에 사용[타 API 이용시 별도 키 필요하여 구 피싱포엠 형식 따름])
+```
+
+### 백엔드 `.env` (backend/)
+```
+encryption.key = hex2bin:...       # 계좌번호 암호화 키 (분실 시 복호화 불가)
+```
+
+### 백엔드 타임존
+[backend/app/Config/App.php](backend/app/Config/App.php) — `appTimezone = 'Asia/Seoul'`
+
+### 업로드 위치
+`backend/public/uploads/onboard/` (기존 패턴과 통일, 웹 직접 서빙)
+
+---
+
+## 🗑️ 정리한 컨트롤러 / 라우트
+
+ERD 새로 짜면서 기존 비즈니스 컨트롤러(Branch, Showroom, Service, Brochure, Event, News, Notice, IR, Advisor, Popup, Basic, SalesStaff, BranchManager, Test) 전부 삭제. 남긴 것: Auth / Admin / BaseApi / Ping / Dashboard / Upload / Home.
+
+---
+
+## 📌 디자인 정책
+
+- **soft delete vs hard delete**
+  - 마스터성 데이터(분야/지역/선상): **soft delete** (`deleted_YN`)
+  - 종속 데이터(선상 사진): **hard delete** + 파일 직접 삭제
+- **TIMESTAMP 사용 시 주의** — MySQL이 첫 TIMESTAMP에 자동으로 `ON UPDATE CURRENT_TIMESTAMP` 부여하므로 `created_at`은 `DEFAULT CURRENT_TIMESTAMP`만, `updated_at`은 `NULL DEFAULT NULL`로 정의
+- **계좌번호 컬럼 길이** — 암호화하면 base64로 ~135자 → `VARCHAR(255)` 권장

+ 3 - 7
nuxt.config.ts

@@ -10,12 +10,12 @@ export default defineNuxtConfig({
   app: {
     head: {
       titleTemplate: '',
-      title: '포드 SUV, 픽업 트럭 & Ford 스포츠카 라인업',
+      title: '파이럿존',
       htmlAttrs: {
         lang: 'ko'
       },
       link: [
-        { rel: 'icon', type: 'image/x-icon', href: '/favicon-ford.ico' },
+        { rel: 'icon', type: 'image/x-icon', href: '' },
       ],
       script: [
         {
@@ -24,11 +24,7 @@ export default defineNuxtConfig({
         },
         {
           type: 'text/javascript',
-          innerHTML: `if(!wcs_add) var wcs_add = {};
-wcs_add["wa"] = "23841615685b68";
-if(window.wcs) {
-  wcs_do();
-}`
+          innerHTML: ``
         }
       ]
     },