507 lines
14 KiB
JavaScript
507 lines
14 KiB
JavaScript
import { w2grid, w2ui, w2popup, w2alert, w2confirm } from 'https://cdn.jsdelivr.net/gh/vitmalina/w2ui@master/dist/w2ui.es6.min.js'
|
|
/* -------------------------------------------------
|
|
공통 유틸
|
|
------------------------------------------------- */
|
|
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
|
|
})
|
|
}
|
|
|
|
/* -------------------------------------------------
|
|
기업 관리자 페이지 Grid
|
|
------------------------------------------------- */
|
|
export async function createUserGrid(boxId, options = {}) {
|
|
// 🔥 DB에서 권한 코드 로딩
|
|
const authItems = await loadBaseCode('BS100')
|
|
const { loadSummary = true, memberId = null } = options
|
|
|
|
destroyGrid('userGrid')
|
|
|
|
const grid = new w2grid({
|
|
name: boxId === '#detailGrid' ? 'detailGrid' : 'userGrid',
|
|
box: boxId,
|
|
|
|
show: {
|
|
footer: true,
|
|
selectColumn: true,
|
|
},
|
|
|
|
columns: [
|
|
{ field: 'recid', text: '#', size: '50px', attr: 'align=center', editable: false, resizable: true, 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: 'reg_date', text: '등록일', size: '100px', editable: false, resizable: true, sortable: true },
|
|
{
|
|
field: 'use_yn',
|
|
text: '사용',
|
|
size: '80px',
|
|
attr: 'align=center',
|
|
resizable: true,
|
|
sortable: true,
|
|
|
|
editable: {
|
|
type: 'list',
|
|
items: [
|
|
{ id: 'Y', text: 'Y' },
|
|
{ id: 'N', text: 'N' }
|
|
]
|
|
},
|
|
|
|
render(record) {
|
|
return record.use_yn === 'Y' ? 'Y' : 'N'
|
|
}
|
|
},
|
|
/* ✅ 권한 콤보 (DB 연동) */
|
|
{
|
|
field: 'auth_bc',
|
|
text: '권한',
|
|
size: '120px',
|
|
editable: {
|
|
type: 'list',
|
|
items: authItems
|
|
},
|
|
render(record) {
|
|
const item = authItems.find(i => i.id === record.auth_bc)
|
|
return item ? item.text : record.auth_bc
|
|
}
|
|
},
|
|
{ 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 = '변경 시에만 입력'
|
|
}
|
|
},
|
|
|
|
records: [],
|
|
})
|
|
|
|
loadData({
|
|
loadSummary,
|
|
memberId
|
|
})
|
|
}
|
|
|
|
function loadUsers() {
|
|
fetch('/kngil/bbs/adm_comp.php')
|
|
.then(res => res.text()) // 🔥 먼저 text로 확인
|
|
.then(text => {
|
|
try {
|
|
const json = JSON.parse(text)
|
|
w2ui.userGrid.clear()
|
|
w2ui.userGrid.add(json.records)
|
|
} catch (e) {
|
|
console.error('JSON 파싱 실패:', text)
|
|
}
|
|
})
|
|
}
|
|
|
|
export function loadUsersByMember(member_id) {
|
|
|
|
if (!member_id) return
|
|
|
|
// 🔥 실제 존재하는 grid 찾기
|
|
const g = w2ui.detailGrid || w2ui.userGrid
|
|
if (!g) {
|
|
console.error('사용자 grid가 없습니다')
|
|
return
|
|
}
|
|
|
|
fetch('/kngil/bbs/adm_comp.php')
|
|
.then(res => res.json())
|
|
.then(json => {
|
|
g.clear()
|
|
g.add(json.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')
|
|
.then(res => res.json())
|
|
.then(async d => {
|
|
|
|
if (d.status !== 'success') {
|
|
w2alert('데이터 로딩 실패')
|
|
return
|
|
}
|
|
|
|
const records = d.records || []
|
|
const memberId = d.member_id // ⭐ 여기서 확정
|
|
|
|
if (loadSummary && memberId) {
|
|
const totalArea = await loadTotalArea(memberId)
|
|
|
|
renderSummaryFromRecords({
|
|
memberId,
|
|
records,
|
|
totalArea
|
|
})
|
|
}
|
|
|
|
const gridName = w2ui.detailGrid ? 'detailGrid' : 'userGrid'
|
|
w2ui[gridName].clear()
|
|
w2ui[gridName].add(records)
|
|
})
|
|
.catch(err => {
|
|
console.error(err)
|
|
w2alert('서버 통신 오류')
|
|
})
|
|
}
|
|
|
|
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 === '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 = 'Silver'
|
|
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() + '㎡'
|
|
|
|
document.getElementById('usedBar').style.width = percent + '%'
|
|
document.getElementById('usedBar').textContent = percent + '%'
|
|
document.getElementById('remainBar').style.width =
|
|
(100 - 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,
|
|
auth_bc : 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('저장 완료')
|
|
loadUsersByMember(g.records[0].member_id)
|
|
} 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
|
|
|
|
// 신규 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: 'Y',
|
|
auth_bc: 'BS100400',
|
|
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('삭제 완료')
|
|
loadUsersByMember(g.records[0].member_id)
|
|
} else {
|
|
w2alert(json.message || '삭제 실패')
|
|
}
|
|
} catch (e) {
|
|
console.error(text)
|
|
w2alert('서버 응답 오류 (JSON 아님)')
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
function loadTotalArea(memberId) {
|
|
return fetch(`/kngil/bbs/adm_comp.php?action=total_area&member_id=${memberId}`)
|
|
.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
|
|
g.clear()
|
|
g.add(records)
|
|
})
|
|
}
|
|
|
|
|
|
document.getElementById('btnSearch')
|
|
?.addEventListener('click', doSearch)
|
|
|
|
document.getElementById('schKeyword')
|
|
?.addEventListener('keydown', e => {
|
|
if (e.key === 'Enter') doSearch()
|
|
})
|