commit
This commit is contained in:
798
kngil/js/adm_comp.js
Normal file
798
kngil/js/adm_comp.js
Normal file
@@ -0,0 +1,798 @@
|
||||
import { w2grid, w2ui, w2popup, w2alert, w2confirm } from 'https://cdn.jsdelivr.net/gh/vitmalina/w2ui@master/dist/w2ui.es6.min.js'
|
||||
let AUTH_ITEMS = []
|
||||
let CURRENT_MEMBER_ID = null;
|
||||
|
||||
const USE_ITEMS = [
|
||||
{ id: 'Y', text: '사용' },
|
||||
{ id: 'N', text: '미사용' }
|
||||
]
|
||||
/* -------------------------------------------------
|
||||
공통 유틸
|
||||
------------------------------------------------- */
|
||||
|
||||
function getTargetMemberId() {
|
||||
return document.getElementById('targetMemberId')?.value?.trim()
|
||||
}
|
||||
|
||||
function destroyGrid(name) {
|
||||
if (w2ui[name]) {
|
||||
w2ui[name].destroy()
|
||||
}
|
||||
}
|
||||
|
||||
function loadBaseCode(mainCd) {
|
||||
return fetch(`/kngil/bbs/adm_comp.php?action=base_code&main_cd=${mainCd}`)
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
if (json.status !== 'success') {
|
||||
throw new Error(json.message || '공통코드 로딩 실패')
|
||||
}
|
||||
return json.items
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeAuth(records) {
|
||||
return records.map(r => {
|
||||
const item = AUTH_ITEMS.find(a => a.id === r.auth_bc)
|
||||
return {
|
||||
...r,
|
||||
auth_bc: item || null //객체 복사
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeUseYn(records) {
|
||||
return records.map(r => {
|
||||
const item = USE_ITEMS.find(u => u.id === r.use_yn)
|
||||
return {
|
||||
...r,
|
||||
use_yn: item || null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------
|
||||
기업 관리자 페이지 Grid
|
||||
------------------------------------------------- */
|
||||
export async function createUserGrid(boxId, options = {}) {
|
||||
console.log('🔥 createUserGrid 호출됨:', boxId)
|
||||
// 🔥 DB에서 권한 코드 로딩
|
||||
AUTH_ITEMS = (await loadBaseCode('BS100')).map(r => ({
|
||||
id: r.id,
|
||||
text: r.text
|
||||
}))
|
||||
const { loadSummary = true, memberId = null } = options
|
||||
|
||||
destroyGrid('userGrid')
|
||||
|
||||
const grid = new w2grid({
|
||||
name: boxId === '#detailGrid' ? 'detailGrid' : 'userGrid',
|
||||
box: boxId,
|
||||
|
||||
show: {
|
||||
footer: true,
|
||||
lineNumbers: true,
|
||||
selectColumn: true,
|
||||
},
|
||||
|
||||
columns: [
|
||||
// {
|
||||
// field: 'recid',
|
||||
// text: '#',
|
||||
// size: '50px',
|
||||
// attr: 'align=center',
|
||||
// sortable: true,
|
||||
// },
|
||||
{ field: 'user_id', text: 'ID', size: '90px', editable: {type : 'text'}, resizable: true, sortable: true },
|
||||
{
|
||||
field: 'user_pw',
|
||||
text: 'PW',
|
||||
size: '90px',
|
||||
resizable: true,
|
||||
sortable: false,
|
||||
|
||||
editable: {
|
||||
type: 'password' // ✅ 입력 시 ●●●●
|
||||
},
|
||||
|
||||
render() {
|
||||
return '********' // ✅ 항상 마스킹
|
||||
}
|
||||
},
|
||||
{ field: 'user_nm', text: '이름', size: '90px', editable: {type : 'text'}, resizable: true, sortable: true },
|
||||
{
|
||||
field: 'tel_no',
|
||||
text: '연락처',
|
||||
size: '120px',
|
||||
editable: { type: 'text' },
|
||||
resizable: true,
|
||||
sortable: true
|
||||
},
|
||||
{ field: 'email', text: 'E-mail', size: '180px', editable: {type : 'text'}, resizable: true, sortable: true },
|
||||
{ field: 'dept_nm', text: '부서', size: '120px', editable: {type : 'text'}, resizable: true, sortable: true },
|
||||
{
|
||||
field: 'use_area',
|
||||
text: '사용량(㎡)',
|
||||
size: '120px',
|
||||
attr: 'align=right',
|
||||
editable: false,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
|
||||
render(record) {
|
||||
const v = Number(record.use_area) || 0
|
||||
return v.toLocaleString() // ✅ 1,000단위 콤마
|
||||
}
|
||||
},
|
||||
{ field: 'cdt', text: '등록일', size: '100px', editable: false, resizable: true, sortable: true },
|
||||
{
|
||||
field: 'use_yn',
|
||||
text: '사용',
|
||||
size: '90px',
|
||||
attr: 'align=center',
|
||||
sortable: true,
|
||||
editable: {
|
||||
type: 'list',
|
||||
items: USE_ITEMS,
|
||||
showAll: true,
|
||||
openOnFocus: true
|
||||
},
|
||||
|
||||
render(record, extra) {
|
||||
return extra?.value?.text || ''
|
||||
}
|
||||
},
|
||||
/* ✅ 권한 콤보 (DB 연동) */
|
||||
{
|
||||
field: 'auth_bc',
|
||||
text: '권한',
|
||||
size: '120px',
|
||||
sortable: true,
|
||||
editable: {
|
||||
type: 'list',
|
||||
items: AUTH_ITEMS,
|
||||
showAll: true,
|
||||
openOnFocus: true
|
||||
},
|
||||
render(record, extra) {
|
||||
return extra?.value?.text || ''
|
||||
}
|
||||
},
|
||||
{ field: 'rmks', text: '비고', size: '120px', editable: { type: 'text' }, resizable: true, sortable: true }
|
||||
],
|
||||
onEditField(event) {
|
||||
|
||||
const pwColIndex = this.getColumn('user_pw').index
|
||||
|
||||
// 🔥 PW 컬럼일 때만 처리
|
||||
if (event.column !== pwColIndex) return
|
||||
|
||||
event.onComplete = function () {
|
||||
|
||||
// 🔥 현재 편집 세션의 input만 정확히 집기
|
||||
const box = event.box
|
||||
if (!box) return
|
||||
|
||||
const input = box.querySelector('input[type="password"]')
|
||||
if (!input) return
|
||||
|
||||
// PW만 초기화
|
||||
input.value = ''
|
||||
input.placeholder = '변경 시에만 입력'
|
||||
}
|
||||
},
|
||||
onChange(event) {
|
||||
event.onComplete = function (ev) {
|
||||
|
||||
const rec = grid.get(ev.recid);
|
||||
if (!rec) return;
|
||||
|
||||
const field = grid.columns[ev.column].field;
|
||||
let val = ev.value_new;
|
||||
|
||||
/* ===============================
|
||||
📞 전화번호(tel_no) 자동 하이픈
|
||||
=============================== */
|
||||
if (field === 'tel_no') {
|
||||
|
||||
let digits = String(val || '').replace(/\D/g, '');
|
||||
|
||||
// 입력 중이면 건드리지 않음
|
||||
if (digits.length < 9) return;
|
||||
|
||||
let formatted = digits;
|
||||
|
||||
if (digits.length === 11) {
|
||||
formatted =
|
||||
`${digits.slice(0,3)}-${digits.slice(3,7)}-${digits.slice(7)}`;
|
||||
} else if (digits.length === 10) {
|
||||
formatted =
|
||||
`${digits.slice(0,3)}-${digits.slice(3,6)}-${digits.slice(6)}`;
|
||||
}
|
||||
|
||||
// ✅ 화면 값
|
||||
grid.set(ev.recid, { tel_no: formatted });
|
||||
|
||||
// ✅ 변경사항으로 "확정" (이게 핵심)
|
||||
grid.mergeChanges(ev.recid, { tel_no: formatted });
|
||||
|
||||
grid.refreshRow(ev.recid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ===============================
|
||||
공통 처리
|
||||
=============================== */
|
||||
if (typeof val === 'object' && val !== null) {
|
||||
val = val.text;
|
||||
}
|
||||
|
||||
grid.set(ev.recid, { [field]: val });
|
||||
grid.mergeChanges(ev.recid, { [field]: val });
|
||||
};
|
||||
},
|
||||
records: [],
|
||||
})
|
||||
|
||||
loadData({
|
||||
loadSummary,
|
||||
memberId
|
||||
})
|
||||
}
|
||||
|
||||
export function loadUsersByMember(memberId) {
|
||||
|
||||
if (!memberId) return
|
||||
|
||||
const g = w2ui.detailGrid
|
||||
if (!g) {
|
||||
console.error('detailGrid 없음')
|
||||
return
|
||||
}
|
||||
|
||||
fetch(`/kngil/bbs/adm_comp.php?action=list&member_id=${memberId}`)
|
||||
.then(res => res.json())
|
||||
.then(d => {
|
||||
|
||||
if (d.status !== 'success') {
|
||||
w2alert('사용자 조회 실패')
|
||||
return
|
||||
}
|
||||
const records = normalizeAuth(d.records || [])
|
||||
records = normalizeUseYn(records)
|
||||
g.clear()
|
||||
g.add(d.records)
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
}
|
||||
|
||||
export function setUserGridMode(mode = 'view') {
|
||||
const g = w2ui.userGrid
|
||||
if (!g) return
|
||||
|
||||
if (mode === 'view') {
|
||||
g.show.toolbar = false
|
||||
g.show.selectColumn = false
|
||||
g.show.toolbarSave = false
|
||||
} else {
|
||||
g.show.toolbar = true
|
||||
g.show.selectColumn = true
|
||||
g.show.toolbarSave = true
|
||||
}
|
||||
|
||||
g.refresh()
|
||||
}
|
||||
|
||||
export function loadData({ loadSummary = true } = {}) {
|
||||
fetch('/kngil/bbs/adm_comp.php?action=list')
|
||||
.then(res => res.json())
|
||||
.then(async d => {
|
||||
|
||||
if (d.status !== 'success') return
|
||||
|
||||
let records = normalizeAuth(d.records || [])
|
||||
records = normalizeUseYn(records)
|
||||
const gridName = w2ui.detailGrid ? 'detailGrid' : 'userGrid'
|
||||
|
||||
w2ui[gridName].clear()
|
||||
w2ui[gridName].add(records)
|
||||
|
||||
if (loadSummary && d.member_id) {
|
||||
const totalArea = await loadTotalArea()
|
||||
renderSummaryFromRecords({
|
||||
memberId: d.member_id,
|
||||
records,
|
||||
totalArea
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function renderSummaryFromRecords({ memberId, records, totalArea }) {
|
||||
|
||||
if (!records.length) return
|
||||
|
||||
const first = records[0]
|
||||
|
||||
const issuedCnt = Number(first.users_tot) || 0
|
||||
const usedCnt = Number(first.users_y) || 0
|
||||
const term = first.term || ''
|
||||
|
||||
// 사용 중 면적 합계
|
||||
let usedArea = 0
|
||||
records.forEach(r => {
|
||||
if (r.use_yn?.id === 'Y') {
|
||||
usedArea += Number(r.use_area || 0)
|
||||
}
|
||||
})
|
||||
|
||||
const percent = totalArea > 0
|
||||
? Math.floor((usedArea / totalArea) * 100)
|
||||
: 0
|
||||
|
||||
/* -------- 화면 바인딩 -------- */
|
||||
document.getElementById('memberId').textContent = memberId
|
||||
document.getElementById('planName').textContent = first.itm_nm || '-'
|
||||
document.getElementById('dateRange').textContent = term
|
||||
|
||||
document.getElementById('issuedCnt').textContent = issuedCnt
|
||||
document.getElementById('usedCnt').textContent = usedCnt
|
||||
|
||||
document.getElementById('usedArea').textContent =
|
||||
usedArea.toLocaleString() + '㎡'
|
||||
|
||||
document.getElementById('totalArea').textContent =
|
||||
totalArea.toLocaleString() + '㎡'
|
||||
|
||||
/* -------- 사용량 바 -------- */
|
||||
const bar = document.getElementById('usedBar')
|
||||
bar.style.width = percent + '%'
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===============================
|
||||
// 저장 버튼
|
||||
// ===============================
|
||||
document.getElementById('btnSave_comp')?.addEventListener('click', () => {
|
||||
|
||||
// 현재 사용 중인 grid
|
||||
const g = w2ui.detailGrid || w2ui.userGrid
|
||||
if (!g) return
|
||||
|
||||
const changes = g.getChanges()
|
||||
|
||||
if (!changes.length) {
|
||||
w2alert('변경된 내용이 없습니다.')
|
||||
return
|
||||
}
|
||||
|
||||
const inserts = []
|
||||
const updates = []
|
||||
|
||||
changes.forEach(c => {
|
||||
const rec = g.get(c.recid)
|
||||
if (!rec) return
|
||||
|
||||
// 🔥 핵심: 원본 rec + 변경값 c 병합
|
||||
const merged = { ...rec, ...c }
|
||||
|
||||
if (rec.__isNew) {
|
||||
// INSERT → 전체 row 필요
|
||||
inserts.push(merged)
|
||||
} else {
|
||||
// UPDATE → PK + 변경 컬럼
|
||||
updates.push({
|
||||
member_id : merged.member_id,
|
||||
user_id : merged.user_id,
|
||||
|
||||
user_nm : merged.user_nm,
|
||||
dept_nm : merged.dept_nm,
|
||||
tel_no : merged.tel_no,
|
||||
email : merged.email,
|
||||
use_yn : merged.use_yn?.id || merged.use_yn,
|
||||
auth_bc : merged.auth_bc?.id || merged.auth_bc,
|
||||
rmks : (merged.memo !== undefined ? merged.memo : '')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
console.log('INSERTS', inserts)
|
||||
console.log('UPDATES', updates)
|
||||
|
||||
fetch('/kngil/bbs/adm_comp.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'save',
|
||||
// member_id: g.records[0]?.member_id,
|
||||
inserts,
|
||||
updates
|
||||
})
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(text => {
|
||||
try {
|
||||
const json = JSON.parse(text)
|
||||
if (json.status === 'success') {
|
||||
w2alert('저장 완료')
|
||||
loadData()
|
||||
} else {
|
||||
w2alert(json.message || '저장 실패')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(text)
|
||||
w2alert('서버 응답 오류 (JSON 아님)')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
//추가(insert)
|
||||
document.getElementById('btnAdd')?.addEventListener('click', () => {
|
||||
|
||||
const g = w2ui.userGrid || w2ui.detailGrid
|
||||
if (!g) return
|
||||
const defaultAuth = AUTH_ITEMS.find(a => a.id === 'BS100500') // 일반
|
||||
// 신규 row용 recid (음수로 충돌 방지)
|
||||
const newRecid = -Date.now()
|
||||
|
||||
g.add({
|
||||
recid: newRecid,
|
||||
__isNew: true,
|
||||
user_id: '',
|
||||
user_pw: '',
|
||||
user_nm: '',
|
||||
tel_no: '',
|
||||
email: '',
|
||||
dept_nm: '',
|
||||
use_area: 0,
|
||||
use_yn: USE_ITEMS[0],
|
||||
auth_bc: defaultAuth || null,
|
||||
memo: ''
|
||||
}, true)
|
||||
|
||||
g.select(newRecid)
|
||||
g.scrollIntoView(newRecid)
|
||||
})
|
||||
|
||||
//삭제
|
||||
document.getElementById('btnDelete')?.addEventListener('click', () => {
|
||||
|
||||
const g = w2ui.detailGrid || w2ui.userGrid
|
||||
if (!g) return
|
||||
|
||||
const sel = g.getSelection()
|
||||
|
||||
if (!sel.length) {
|
||||
w2alert('삭제할 사용자를 선택하세요.')
|
||||
return
|
||||
}
|
||||
|
||||
// 선택된 user_id 수집
|
||||
const ids = sel
|
||||
.map(recid => {
|
||||
const r = g.get(recid)
|
||||
return r?.user_id
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
if (!ids.length) {
|
||||
w2alert('삭제 가능한 항목이 없습니다.')
|
||||
return
|
||||
}
|
||||
|
||||
w2confirm(`선택한 ${ids.length}명의 사용자를 삭제하시겠습니까?`)
|
||||
.yes(() => {
|
||||
|
||||
fetch('/kngil/bbs/adm_comp.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'delete',
|
||||
// member_id: g.records[0]?.member_id,
|
||||
ids
|
||||
})
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(text => {
|
||||
try {
|
||||
const json = JSON.parse(text)
|
||||
if (json.status === 'success') {
|
||||
w2alert('삭제 완료')
|
||||
loadData()
|
||||
} else {
|
||||
w2alert(json.message || '삭제 실패')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(text)
|
||||
w2alert('서버 응답 오류 (JSON 아님)')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function loadTotalArea(memberId) {
|
||||
return fetch(`/kngil/bbs/adm_comp.php?action=total_area`)
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
if (json.status !== 'success') {
|
||||
throw new Error('총 구매면적 로딩 실패')
|
||||
}
|
||||
return Number(json.total_area || 0)
|
||||
})
|
||||
}
|
||||
|
||||
function doSearch() {
|
||||
|
||||
const keyword = document.getElementById('schKeyword').value.trim()
|
||||
const type = document.getElementById('schType').value
|
||||
const useYn = document.getElementById('schUseYn').value
|
||||
|
||||
let p_user_nm = ''
|
||||
let p_dept_nm = ''
|
||||
|
||||
// DB로 보낼 검색 조건
|
||||
if (type === 'name') {
|
||||
p_user_nm = keyword
|
||||
} else if (type === 'dept') {
|
||||
p_dept_nm = keyword
|
||||
} else if (type === '') {
|
||||
// 전체 검색 → 이름 OR 부서
|
||||
p_user_nm = keyword
|
||||
p_dept_nm = keyword
|
||||
}
|
||||
// ⚠️ type === 'id' 는 DB로 안 보냄
|
||||
|
||||
fetch(`/kngil/bbs/adm_comp.php?action=list`
|
||||
+ `&user_nm=${encodeURIComponent(p_user_nm)}`
|
||||
+ `&dept_nm=${encodeURIComponent(p_dept_nm)}`
|
||||
+ `&use_yn=${useYn}`
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(d => {
|
||||
|
||||
if (d.status !== 'success') {
|
||||
w2alert('검색 실패')
|
||||
return
|
||||
}
|
||||
|
||||
let records = d.records || []
|
||||
|
||||
// ID 검색은 프론트 필터
|
||||
if (type === 'id' && keyword) {
|
||||
records = records.filter(r =>
|
||||
(r.user_id || '').toLowerCase()
|
||||
.includes(keyword.toLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
const g = w2ui.detailGrid || w2ui.userGrid
|
||||
records = normalizeAuth(records)
|
||||
records = normalizeUseYn(records)
|
||||
g.clear()
|
||||
g.add(records)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
document.getElementById('btnSearch')
|
||||
?.addEventListener('click', () => {
|
||||
|
||||
const memberInput = document.getElementById('targetMemberId');
|
||||
const memberId = memberInput ? memberInput.value.trim() : '';
|
||||
|
||||
if (memberInput && memberInput.style.display !== 'none') {
|
||||
CURRENT_MEMBER_ID = memberId; // ⭐ 저장
|
||||
loadDataByMemberId(memberId);
|
||||
return;
|
||||
}
|
||||
|
||||
doSearch();
|
||||
});
|
||||
|
||||
document.getElementById('schKeyword')
|
||||
?.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') doSearch()
|
||||
})
|
||||
|
||||
document.getElementById('btnBulkCreate')
|
||||
?.addEventListener('click', () => {
|
||||
|
||||
const memberId = getTargetMemberId()
|
||||
|
||||
if (!memberId) {
|
||||
w2alert('회원ID를 입력하세요.')
|
||||
return
|
||||
}
|
||||
|
||||
// 🔥 여기서 CSV URL 팝업 띄움
|
||||
openBulkCreatePopup(memberId)
|
||||
})
|
||||
|
||||
function openBulkCreatePopup(memberId) {
|
||||
|
||||
// ⭐ 방어: 객체면 member_id만 사용
|
||||
if (typeof memberId === 'object' && memberId !== null) {
|
||||
memberId = memberId.member_id || '';
|
||||
}
|
||||
|
||||
if (!memberId) {
|
||||
w2alert('회원ID가 올바르지 않습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
w2popup.open({
|
||||
title: '사용자 일괄 생성 (CSV)',
|
||||
width: 520,
|
||||
height: 220,
|
||||
modal: true,
|
||||
body: `
|
||||
<div style="padding:20px">
|
||||
<p style="margin-bottom:8px">
|
||||
대상 회원ID: <b>${memberId}</b>
|
||||
</p>
|
||||
|
||||
<input type="text"
|
||||
id="csvUrl"
|
||||
placeholder="CSV URL 입력"
|
||||
style="width:100%; padding:6px" />
|
||||
|
||||
<div style="margin-top:15px; text-align:right">
|
||||
<button class="w2ui-btn" id="btnCsvRun">실행</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
onOpen(event) {
|
||||
event.onComplete = () => {
|
||||
document
|
||||
.getElementById('btnCsvRun')
|
||||
.addEventListener('click', () => {
|
||||
|
||||
const url =
|
||||
document.getElementById('csvUrl').value.trim()
|
||||
|
||||
if (!url) {
|
||||
w2alert('CSV URL을 입력하세요.')
|
||||
return
|
||||
}
|
||||
|
||||
runBulkCreate(memberId, url)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function runBulkCreate(memberId, csvUrl) {
|
||||
|
||||
fetch('/kngil/bbs/adm_comp.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'bulk_create',
|
||||
member_id: memberId,
|
||||
csv_url: csvUrl
|
||||
})
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(text => {
|
||||
|
||||
let d;
|
||||
try {
|
||||
d = JSON.parse(text);
|
||||
} catch (e) {
|
||||
w2alert({
|
||||
title: '서버 오류',
|
||||
text: `<pre style="white-space:pre-wrap; text-align:left;">${text}</pre>`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const successCnt = Number(d.success_cnt || 0);
|
||||
const failCnt = Number(d.fail_cnt || 0);
|
||||
|
||||
let errors = d.errors || [];
|
||||
// 배열이지만 요소가 객체일 수 있음 → 문자열로 강제
|
||||
errors = errors.map(e => {
|
||||
if (typeof e === 'string') return e;
|
||||
try {
|
||||
return JSON.stringify(e);
|
||||
} catch {
|
||||
return String(e);
|
||||
}
|
||||
});
|
||||
|
||||
// // ⭐ 핵심: object → array 변환
|
||||
// if (!Array.isArray(errors) && typeof errors === 'object') {
|
||||
// errors = Object.values(errors);
|
||||
// }
|
||||
console.log('errors raw =', d.errors);
|
||||
// ❌ 전부 실패
|
||||
if (successCnt === 0) {
|
||||
w2popup.close(); // ⭐ 먼저 CSV 팝업 닫기
|
||||
|
||||
w2alert(`
|
||||
<div style="
|
||||
text-align:center;
|
||||
line-height:1.6;
|
||||
padding:10px;
|
||||
font-size:16px;
|
||||
">
|
||||
<b>일괄 생성 실패</b><br><br>
|
||||
${errors.map(e => `• ${e}`).join('<br>')}
|
||||
</div>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ 성공 or 부분 성공
|
||||
let msg = '';
|
||||
msg += `✔ 성공: ${successCnt}명<br>`;
|
||||
msg += `❌ 실패: ${failCnt}명`;
|
||||
|
||||
if (errors.length > 0) {
|
||||
msg += '<hr style="margin:8px 0">';
|
||||
msg += '<div style="text-align:left; max-height:200px; overflow:auto;">';
|
||||
errors.forEach(err => {
|
||||
msg += `• ${err}<br>`;
|
||||
});
|
||||
msg += '</div>';
|
||||
}
|
||||
|
||||
w2alert({
|
||||
title: '일괄 생성 결과',
|
||||
msg: msg
|
||||
});
|
||||
|
||||
if (CURRENT_MEMBER_ID) {
|
||||
loadDataByMemberId(CURRENT_MEMBER_ID);
|
||||
} else {
|
||||
loadData();
|
||||
}
|
||||
w2popup.close();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
w2alert('서버 통신 중 오류가 발생했습니다.');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function loadDataByMemberId(memberId) {
|
||||
|
||||
if (!memberId) {
|
||||
w2alert('회원ID를 입력하세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/kngil/bbs/adm_comp.php?action=list&member_id=${encodeURIComponent(memberId)}`)
|
||||
.then(res => res.json())
|
||||
.then(async d => {
|
||||
|
||||
if (d.status !== 'success') {
|
||||
w2alert(d.message || '조회 실패');
|
||||
return;
|
||||
}
|
||||
|
||||
let records = normalizeAuth(d.records || []);
|
||||
records = normalizeUseYn(records);
|
||||
|
||||
const gridName = w2ui.detailGrid ? 'detailGrid' : 'userGrid';
|
||||
w2ui[gridName].clear();
|
||||
w2ui[gridName].add(records);
|
||||
|
||||
// ✅ 상단 요약 갱신
|
||||
const totalArea = await loadTotalArea(memberId);
|
||||
renderSummaryFromRecords({
|
||||
memberId,
|
||||
records,
|
||||
totalArea
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user