feature/template #5
@@ -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');
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>아파트단지 DB구축 현황</h1>
|
||||
@@ -325,6 +334,10 @@
|
||||
</div>
|
||||
|
||||
<div class="ml-auto">
|
||||
<button class="btn btn-sm btn-outline-secondary" id="excel-upload">
|
||||
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i> 엑셀업로드
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm btn-outline-success" id="excel-download">
|
||||
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i> 엑셀다운로드
|
||||
</button>
|
||||
@@ -375,6 +388,72 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="excelModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">엑셀 업로드</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- 업로드 영역 -->
|
||||
<div class="d-flex align-items-center gap-3 mb-3">
|
||||
<input type="file" id="excel" class="form-control" accept=".xlsx,.xls,.csv"
|
||||
style="max-width: 320px;">
|
||||
|
||||
<a href="/plugin/sample/sample.xlsx" download="아파트단지_샘플양식" class="btn btn-outline-secondary btn-sm">
|
||||
샘플양식 다운로드
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 안내 문구 -->
|
||||
<div class="alert alert-light py-2 mb-3">
|
||||
<ul class="mb-0 small">
|
||||
<li>엑셀 첫 행은 헤더로 인식됩니다.</li>
|
||||
<li>컬럼 순서 및 개수는 샘플양식과 동일해야 합니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 테이블 영역 -->
|
||||
<div class="table-responsive">
|
||||
<table id="excelList"
|
||||
class="table table-sm table-hover table-striped table-bordered align-middle text-center mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>줄번호</th>
|
||||
<th>단지코드</th>
|
||||
<th>통합단지코드</th>
|
||||
<th>법정동코드</th>
|
||||
<th>주소</th>
|
||||
<th>상세주소</th>
|
||||
<th>단지유형</th>
|
||||
<th>단지명</th>
|
||||
<th>입주년월</th>
|
||||
<th>총세대수</th>
|
||||
<th>총동수</th>
|
||||
<th>평형수</th>
|
||||
<th>동호수</th>
|
||||
<th>사용여부</th>
|
||||
<th>경도</th>
|
||||
<th>위도</th>
|
||||
<th>사진촬영제외</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||
<button type="button" class="btn btn-primary" id="btnUpload">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
|
||||
@@ -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)
|
||||
|
||||
BIN
public/plugin/sample/sample.xlsx
Normal file
BIN
public/plugin/sample/sample.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user