diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 2c672c8..bc16274 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -61,6 +61,7 @@ $routes->group('article', ['namespace' => 'App\Controllers\Article'], function (
$routes->post('apt/chgAptVideoTarget', 'Apt::chgAptVideoTarget');
$routes->post('apt/chkTakeAptPhotoCnt', 'Apt::chkTakeAptPhotoCnt');
$routes->get('apt/excel', 'Apt::excel');
+ $routes->post('apt/uploadExcel', 'Apt::uploadExcel');
/** API - 아파트단지 상세 */
$routes->post('apt/saveKeeper', 'Apt::saveKeeper');
diff --git a/app/Controllers/Article/Apt.php b/app/Controllers/Article/Apt.php
index 1d6b958..311a6d9 100644
--- a/app/Controllers/Article/Apt.php
+++ b/app/Controllers/Article/Apt.php
@@ -267,6 +267,63 @@ class Apt extends BaseController
}
}
+ // 엑셀 업로드
+ public function uploadExcel()
+ {
+ try {
+
+ $payload = $this->request->getJSON(true);
+ $datas = $payload['datas'] ?? null;
+
+ if (count($datas) === 0) {
+ return $this->response->setJSON([
+ 'code' => '9',
+ 'msg' => "데이터 없음",
+ ]);
+ }
+
+
+ foreach ($datas as $data) {
+ $rdate = date("Y-m-d H:i:s");
+
+ $params = [
+ 'row_no' => $data[0],
+ 'hscp_no' => $data[1],
+ 'uni_hscp_no' => $data[2],
+ 'region_cd' => $data[3],
+ 'addr' => $data[4],
+ 'addr2' => $data[5],
+ 'apt_cate_nm' => $data[6],
+ 'rcpt_hscp_nm' => $data[7],
+ 'move_ym' => $data[8],
+ 'households_cnt' => $data[9],
+ 'dong_cnt' => $data[10],
+ 'pyeong_cnt' => $data[11],
+ 'dongho' => $data[12],
+ 'use_yn' => $data[13],
+ 'rcpt_x' => $data[14],
+ 'rcpt_y' => $data[15],
+ 'pho_exept_yn' => $data[16],
+ 'rdate' => $rdate,
+ ];
+
+ // INSERT apt_receipt, apt_result
+ $this->aptModel->saveExcelUploadData($params);
+
+ }
+
+ return $this->response->setJSON([
+ 'code' => '0',
+ 'msg' => 'success'
+ ]);
+
+ } catch (\Exception $e) {
+ return $this->response->setJSON([
+ 'code' => '9',
+ 'msg' => $e->getMessage(),
+ ]);
+ }
+ }
// 엑셀 다운로드
public function excel()
diff --git a/app/Models/article/AptModel.php b/app/Models/article/AptModel.php
index 4704df6..071e356 100644
--- a/app/Models/article/AptModel.php
+++ b/app/Models/article/AptModel.php
@@ -683,6 +683,77 @@ class AptModel extends Model
];
}
+ // 엑셀업로드 저장
+ public function saveExcelUploadData($params)
+ {
+
+ $this->db->transStart();
+
+ $builder = $this->db->table('apt_receipt');
+ $res = $builder->insert($params);
+
+ if ($res === false) {
+ return [
+ 'success' => false,
+ 'msg' => "단지코드 : {$params['hscp_no']} 저장실패",
+ ];
+ }
+
+ $rcpt_no = $this->db->insertID();
+
+ $params2 = [
+ 'rcpt_no' => $rcpt_no,
+ 'hscp_no' => $params['hscp_no'],
+ 'region_cd' => $params['region_cd'],
+ 'charger' => '',
+ 'dept_sq' => '',
+ 'addr' => $params['addr'],
+ 'addr2' => $params['addr2'],
+ 'rcpt_hscp_nm' => $params['rcpt_hscp_nm'],
+ 'rcpt_x' => $params['rcpt_x'],
+ 'rcpt_y' => $params['rcpt_y'],
+ 'move_ym' => $params['move_ym'],
+ 'households_cnt' => $params['households_cnt'],
+ 'dong_cnt' => $params['dong_cnt'],
+ 'apt_cate_nm' => $params['apt_cate_nm'],
+ 'apt_step' => 'S01',
+ 'check_yn' => 'N',
+ 'resend_yn' => 'N',
+ 'memo' => '',
+ 'pho_up_yn' => 'N',
+ 'vdo_up_ynx' => 'N',
+ 'vdo_up_tm' => NULL,
+ 'video_target' => 'N',
+ 'not_vdo_reson' => '',
+ 'note' => '',
+ 'not_vdo_tm' => NULL,
+ 'check_tm' => NULL,
+ 'write_complete_yn' => 'N',
+ 'write_complete_tm' => NULL,
+ 'all_no_pho' => NULL,
+ 'syncid' => '',
+ 'sync_comp' => NULL,
+ 'sync_wait_cnt' => '0'
+ ];
+
+ $builder = $this->db->table('apt_result');
+ $res = $builder->insert($params2);
+
+ if ($res === false) {
+ return [
+ 'success' => false,
+ 'msg' => "단지코드 : {$params['hscp_no']} 저장실패",
+ ];
+ }
+
+ $this->db->transComplete();
+
+ // 성공
+ return [
+ 'success' => true,
+ ];
+ }
+
// 엑셀 다운로드
public function getExcelList($data)
{
diff --git a/app/Views/pages/article/lists.php b/app/Views/pages/article/lists.php
index 7dee47d..6cacb11 100644
--- a/app/Views/pages/article/lists.php
+++ b/app/Views/pages/article/lists.php
@@ -44,6 +44,15 @@
background-color: #ff0000 !important;
color: #fff !important;
}
+
+ #excelList.dataTable {
+ width: max-content !important;
+ }
+
+ table.dataTable td,
+ table.dataTable th {
+ white-space: nowrap;
+ }
아파트단지 DB구축 현황
@@ -325,6 +334,10 @@
+
+
@@ -375,6 +388,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 엑셀 첫 행은 헤더로 인식됩니다.
+ - 컬럼 순서 및 개수는 샘플양식과 동일해야 합니다.
+
+
+
+
+
+
+
+
+ | 줄번호 |
+ 단지코드 |
+ 통합단지코드 |
+ 법정동코드 |
+ 주소 |
+ 상세주소 |
+ 단지유형 |
+ 단지명 |
+ 입주년월 |
+ 총세대수 |
+ 총동수 |
+ 평형수 |
+ 동호수 |
+ 사용여부 |
+ 경도 |
+ 위도 |
+ 사진촬영제외 |
+
+
+
+
+
+
+
+
+
+
+
= $this->endSection() ?>
@@ -389,7 +468,7 @@
const teamArr = = json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = = json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
- var table;
+ var table, excelTbl;
$(function () {
@@ -677,6 +756,136 @@
table.ajax.reload()
});
+ // 엑셀업로드 click
+ $("#excel-upload").on("click", function () {
+ $("#excel").val("");
+ $("#excelList").DataTable().clear().destroy();
+
+ $("#excelModal").modal("show");
+
+ });
+
+ // 엑셀 업로드
+ $("#excel").on("change", async function () {
+ const file = this.files[0];
+ if (!file) return;
+
+ const bodyRows = await readExcelBodyOnly(file);
+ renderExcelDataTable(bodyRows);
+
+ });
+
+ // 엑셀 업로드 저장
+ $("#btnUpload").on("click", function () {
+
+ const dt = $("#excelList").DataTable();
+
+ // 전체 row 데이터 (모든 페이지)
+ const excelData = dt.rows().data().toArray();
+
+ if (excelData.length === 0) {
+ Swal.fire({
+ title: "업로드할 데이터가 없습니다.",
+ icon: "warning"
+ });
+ return;
+ }
+
+ const headers = [
+ "줄번호", "단지코드", "통합단지코드", "법정동코드", "주소"
+ , "상세주소", "단지유형", "단지명"
+ , "입주년월", "총세대수", "총동수", "평형수", "동호수"
+ , "사용여부", "경도", "위도", "사진촬영제외"
+ ];
+
+ const errors = [];
+ let hasError = false;
+ for (let rowIdx = 0; rowIdx < excelData.length; rowIdx++) {
+ const row = excelData[rowIdx];
+
+ for (let colIdx = 0; colIdx < headers.length; colIdx++) {
+ const colName = headers[colIdx];
+ const val = row[colIdx];
+
+
+ if (val === undefined || val === null || String(val).trim() === "") {
+ Swal.fire({
+ title: `${rowIdx + 1}행 ${colName} 데이터 누락`,
+ icon: "warning"
+ });
+
+ hasError = true;
+ break;
+ }
+ }
+
+ if (hasError) break;
+ }
+
+ if (hasError) return;
+
+ swal.fire({
+ text: "저장 하시겠습니까?",
+ type: "warning",
+ showCancelButton: true,
+ confirmButtonText: "예",
+ cancelButtonText: "아니오",
+ closeOnConfirm: false,
+ closeOnCancel: true,
+ confirmButtonColor: "#3085d6",
+ cancelButtonColor: "#d33",
+ }).then((result) => {
+ if (result.isConfirmed) {
+ $.ajax({
+ url: '/article/apt/uploadExcel',
+ contentType: 'application/json;charset=UTF-8',
+ method: 'POST',
+ data: JSON.stringify({ datas: excelData }),
+ beforeSend: function () {
+ blockUI.blockPage({
+ message: tpl
+ })
+ },
+ complete: function () {
+ blockUI.unblockPage()
+ },
+ error: function (xhr, error, thrown) {
+ blockUI.unblockPage()
+ var msg = "";
+ if (xhr.responseText != null) {
+ msg = xhr.responseText
+ } else {
+ msg = "잠시후 다시 시도해 주세요."
+ }
+
+ Swal.fire({
+ title: msg,
+ icon: "error"
+ })
+ },
+ success: function (result) {
+
+ if (result.code == '0') {
+ $("#btnSearch").trigger('click')
+ $("#excelModal").modal("hide")
+ Swal.fire({
+ title: '정상 처리되었습니다.',
+ icon: "success"
+
+ })
+ } else {
+ Swal.fire({
+ title: result.msg,
+ icon: "error"
+ })
+ }
+ }
+ });
+ }
+ });
+
+
+ });
// 엑셀 다운로드 click
$("#excel-download").on("click", function () {
@@ -817,7 +1026,7 @@
Swal.fire({
title: msg,
icon: "error"
- })
+ });
},
success: function (result) {
@@ -940,6 +1149,48 @@
});
+ async function readExcelBodyOnly(file) {
+ const data = await file.arrayBuffer();
+ const wb = XLSX.read(data, { type: "array" });
+ const ws = wb.Sheets[wb.SheetNames[0]];
+
+ const rows2d = XLSX.utils.sheet_to_json(ws, {
+ header: 1,
+ defval: "",
+ raw: false
+ });
+
+ // 첫 줄(엑셀 헤더) 제거 + 빈 행 제거
+ return rows2d
+ .slice(1)
+ .filter(r => r.some(v => String(v).trim() !== ""));
+ }
+
+ function renderExcelDataTable(data2d) {
+ // 이미 DataTable이 있으면 파괴 후 재생성(컬럼 구조가 바뀔 수 있으니)
+ if ($.fn.DataTable.isDataTable("#excelList")) {
+ $("#excelList").DataTable().clear().destroy();
+ }
+
+ excelTbl = $("#excelList").DataTable({
+ language: lang_kor,
+ columnDefs: [
+ { className: 'text-center dt-nowrap', targets: '_all' },
+ ],
+ data: data2d,
+ searching: false,
+ ordering: false,
+ destroy: true,
+ deferRender: true,
+ pageLength: 10,
+ lengthMenu: [10, 25, 50, 100],
+ scrollX: true,
+ autoWidth: true,
+ });
+ }
+
+
+
function hscp_no_enter(event) {
if (event.keyCode == 13) {
table.ajax.reload()
@@ -1055,10 +1306,6 @@
// 단지정보저장
function fn_save_info(row, idx) {
- console.log('+++')
- console.log(row)
- console.log('idx ?? ' + idx)
- console.log('+++')
const target = $("#video_target_" + idx).val();
console.log(target)
diff --git a/public/plugin/sample/sample.xlsx b/public/plugin/sample/sample.xlsx
new file mode 100644
index 0000000..5152b00
Binary files /dev/null and b/public/plugin/sample/sample.xlsx differ