395 lines
14 KiB
PHP
395 lines
14 KiB
PHP
<?php
|
|
include __DIR__ . '/layout_sales.php';
|
|
sales_layout_start("거래처 관리");
|
|
?>
|
|
|
|
<h2 class="text-2xl font-bold mb-4">거래처 관리</h2>
|
|
|
|
<div id="grid_clients" style="width: 100%; height: 720px;"></div>
|
|
|
|
<script type="module">
|
|
import { w2grid } from "https://cdn.jsdelivr.net/gh/vitmalina/w2ui@master/dist/w2ui.es6.min.js";
|
|
|
|
/* ------------------------------------------------------
|
|
⭐ 전화번호 자동 포맷 함수
|
|
------------------------------------------------------- */
|
|
function formatPhone(number) {
|
|
if (!number) return "";
|
|
|
|
number = number.replace(/\D/g, ""); // 숫자만 유지
|
|
|
|
// 휴대폰 010/011/016/017/018/019
|
|
if (/^01[016789]\d{7,8}$/.test(number)) {
|
|
if (number.length === 10)
|
|
return number.replace(/(01[016789])(\d{3})(\d{4})/, "$1-$2-$3");
|
|
return number.replace(/(01[016789])(\d{4})(\d{4})/, "$1-$2-$3");
|
|
}
|
|
|
|
// 070 인터넷전화
|
|
if (/^070\d{7,8}$/.test(number)) {
|
|
return number.replace(/(070)(\d{4})(\d{4})/, "$1-$2-$3");
|
|
}
|
|
|
|
// 서울 02
|
|
if (number.startsWith("02")) {
|
|
if (number.length === 9)
|
|
return number.replace(/(02)(\d{3})(\d{4})/, "$1-$2-$3");
|
|
if (number.length === 10)
|
|
return number.replace(/(02)(\d{4})(\d{4})/, "$1-$2-$3");
|
|
}
|
|
|
|
// 기타 지역번호 031~064
|
|
if (/^0[3-6]\d/.test(number)) {
|
|
return number.replace(/(0\d{2})(\d{3,4})(\d{4})/, "$1-$2-$3");
|
|
}
|
|
|
|
return number;
|
|
}
|
|
|
|
/* ------------------------------------------------------
|
|
1) 기관구분 고정 배열
|
|
------------------------------------------------------- */
|
|
const orgTypes = [
|
|
{ id: '공공기관', text: '공공기관' },
|
|
{ id: '일반기업', text: '일반기업' },
|
|
{ id: '교육기관', text: '교육기관' },
|
|
{ id: '기타', text: '기타' },
|
|
];
|
|
|
|
const businessTypes = [
|
|
{ id: '설계', text: '설계' },
|
|
{ id: '제작', text: '제작' },
|
|
{ id: '교육', text: '교육' },
|
|
{ id: '감리', text: '감리' },
|
|
{ id: '시공', text: '시공' },
|
|
{ id: '기타', text: '기타' },
|
|
];
|
|
|
|
/* ------------------------------------------------------
|
|
2) 영업담당자 리스트 로딩
|
|
------------------------------------------------------- */
|
|
let employeeList = [];
|
|
|
|
async function loadEmployees() {
|
|
let res = await fetch('/egbim/bbs/sales_members.php?action=list');
|
|
let json = await res.json();
|
|
|
|
if (json.status === "ok") {
|
|
employeeList = json.records.map(m => ({
|
|
id: m.emp_no,
|
|
text: `${m.emp_name} (${m.emp_no})`
|
|
}));
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------
|
|
3) 직원 먼저 불러와야 grid가 정상 동작
|
|
------------------------------------------------------- */
|
|
await loadEmployees();
|
|
|
|
/* ------------------------------------------------------
|
|
4) GRID 생성
|
|
------------------------------------------------------- */
|
|
let grid = new w2grid({
|
|
name: 'grid_clients',
|
|
box: '#grid_clients',
|
|
|
|
show: {
|
|
toolbar: true,
|
|
footer: true,
|
|
lineNumbers: true,
|
|
toolbarSave: true,
|
|
toolbarReload: true,
|
|
toolbarSearch: true,
|
|
toolbarColumns: true
|
|
},
|
|
|
|
multiSearch: true,
|
|
|
|
searches: [
|
|
{ field: 'client_code', label: '거래처코드', type: 'text' },
|
|
{ field: 'client_name', label: '거래처명', type: 'text', operator: 'contains' },
|
|
{ field: 'business_type', label: '업종', type: 'text' },
|
|
{ field: 'org_type', label: '기관구분', type: 'text' },
|
|
{ field: 'manager_emp_no', label: '영업담당자', type: 'text' },
|
|
{ field: 'biz_number', label: '사업자등록번호', size: '120px', editable: { type: 'text' }},
|
|
{ field: 'address', label: '주소', type: 'text' },
|
|
{ field: 'phone', label: '전화번호', type: 'text' },
|
|
{ field: 'remarks', label: '비고', type: 'text' },
|
|
{ field: 'created_at', label: '등록일', type: 'date' },
|
|
],
|
|
|
|
columns: [
|
|
{ field: 'client_code', text: '거래처코드', size: '120px',
|
|
editable: false, resizable: true, sortable: true },
|
|
|
|
{ field: 'client_name', text: '거래처명', size: '180px',
|
|
editable: { type: 'text' }, resizable: true, sortable: true },
|
|
|
|
/* -----------------------------------------------------
|
|
업종 — 콤보박스 적용
|
|
------------------------------------------------------ */
|
|
{
|
|
field: 'business_type',
|
|
text: '업종',
|
|
size: '120px',
|
|
sortable: true,
|
|
resizable: true,
|
|
editable: { type: 'combo', items: businessTypes, showAll: true },
|
|
},
|
|
|
|
/* -----------------------------------------------------
|
|
기관구분 — 콤보박스 적용
|
|
------------------------------------------------------ */
|
|
{
|
|
field: 'org_type',
|
|
text: '기관구분',
|
|
size: '140px',
|
|
sortable: true,
|
|
resizable: true,
|
|
editable: { type: 'combo', items: orgTypes, showAll: true },
|
|
},
|
|
|
|
/* -----------------------------------------------------
|
|
영업담당자 — 직원 목록 기반 콤보박스
|
|
------------------------------------------------------ */
|
|
{
|
|
field: 'manager_emp_no',
|
|
text: '영업담당자',
|
|
size: '160px',
|
|
sortable: true,
|
|
resizable: true,
|
|
editable: { type: 'combo', items: employeeList, filter: true },
|
|
},
|
|
{ field: 'biz_number', text: '사업자등록번호', size: '120px', editable: { type: 'text' }, resizable: true, sortable: true },
|
|
{ field: 'address', text: '주소', size: '220px', editable: { type: 'text' }, resizable: true, sortable: true },
|
|
{ field: 'phone', text: '전화번호', size: '120px', editable: { type: 'text' }, resizable: true, sortable: true },
|
|
{ field: 'remarks', text: '비고', size: '200px', editable: { type: 'text' }, resizable: true, sortable: true },
|
|
{ field: 'created_at', text: '등록일', size: '160px', resizable: true, sortable: true },
|
|
],
|
|
|
|
toolbar: {
|
|
items: [
|
|
{ id: 'add', type: 'button', text: '추가', icon: 'w2ui-icon-plus' },
|
|
{ id: 'btn_del', type: 'button', text: '삭제', icon: 'w2ui-icon-cross' }
|
|
],
|
|
|
|
onClick(event) {
|
|
const g = this.owner;
|
|
|
|
if (event.target === 'w2ui-reload') {
|
|
loadClients();
|
|
return;
|
|
}
|
|
|
|
if (event.target === 'add') {
|
|
|
|
$.post("/egbim/bbs/sales_clients.php", {
|
|
action: "insert"
|
|
}, function (res) {
|
|
|
|
const code = res.client_code;
|
|
|
|
g.add({
|
|
recid: code,
|
|
client_code: code,
|
|
client_name: "",
|
|
business_type: "",
|
|
org_type: "",
|
|
manager_emp_no: ""
|
|
});
|
|
|
|
g.refresh();
|
|
alert("새 거래처가 추가되었습니다. (코드: " + code + ")");
|
|
//alert(grid.records.length + 1);
|
|
g.scrollIntoView(grid.records.length + 1);
|
|
//g.editField(grid.records.length + 1, 2);
|
|
}, "json");
|
|
}
|
|
|
|
if (event.target === 'btn_del') {
|
|
|
|
console.log("삭제 버튼 클릭됨!");
|
|
const g = this.owner;
|
|
|
|
let sel = g.getSelection();
|
|
if (!sel.length) return;
|
|
|
|
if (!confirm("정말 삭제하시겠습니까?")) return;
|
|
|
|
sel.forEach(code => {
|
|
|
|
$.post("/egbim/bbs/sales_clients.php", {
|
|
action: "delete",
|
|
client_code: code
|
|
}, function(res) {
|
|
console.log("삭제 응답:", res);
|
|
}, "json");
|
|
|
|
g.remove(code);
|
|
});
|
|
}
|
|
|
|
},
|
|
onChange(event) {
|
|
if (event.column === 'manager_emp_no') {
|
|
let newValue = event.value_new?.text || event.value_new || '';
|
|
event.record.manager_emp_no = newValue;
|
|
this.set(event.recid, { manager_emp_no: newValue });
|
|
this.refresh();
|
|
}
|
|
}
|
|
},
|
|
|
|
/* ------------------------------------------------------
|
|
onSave() — DB 업데이트 전송
|
|
------------------------------------------------------ */
|
|
onSave(event) {
|
|
let changes = this.getChanges();
|
|
|
|
if (!changes.length) {
|
|
alert("변경된 내용이 없습니다.");
|
|
return;
|
|
}
|
|
|
|
Promise.all(
|
|
changes.map(ch => {
|
|
|
|
// 전화번호 자동 포맷
|
|
if (ch.phone !== undefined) {
|
|
let raw = (ch.phone + "").replace(/[^0-9]/g, "");
|
|
ch.phone = formatPhone(raw);
|
|
}
|
|
|
|
/* ------------------------------
|
|
🔵 1) 기관구분(org_type) 유효성 확인
|
|
------------------------------ */
|
|
if (ch.org_type !== undefined) {
|
|
let validOrg = orgTypes.map(o => o.id);
|
|
if (!validOrg.includes(ch.org_type)) {
|
|
alert("리스트에 있는 기관구분만 선택해주세요.");
|
|
throw "invalid org_type";
|
|
}
|
|
}
|
|
|
|
/* ------------------------------
|
|
🔵 2) 업종(business_type) 유효성 확인
|
|
------------------------------ */
|
|
if (ch.business_type !== undefined) {
|
|
let validBiz = businessTypes.map(b => b.id);
|
|
if (!validBiz.includes(ch.business_type)) {
|
|
alert("리스트에 있는 업종만 선택해주세요.");
|
|
throw "invalid business_type";
|
|
}
|
|
}
|
|
|
|
// ------------------------------
|
|
// 🔵 3) 영업담당자(manager_emp_no) 유효성 검사 + 원본 저장
|
|
// ------------------------------
|
|
if (ch.manager_emp_no !== undefined) {
|
|
|
|
let rawValue = ch.manager_emp_no;
|
|
|
|
// 콤보 선택 시 object 형태 → 텍스트로 변환하여 DB 저장
|
|
if (typeof rawValue === "object" && rawValue !== null) {
|
|
// 예: { id: "01201", text: "홍길동 (01201)" }
|
|
rawValue = rawValue.text;
|
|
}
|
|
|
|
// "" 허용
|
|
if (rawValue !== "") {
|
|
|
|
// rawValue 안에서 "(사번)" 부분만 추출
|
|
let match = rawValue.match(/\((.*?)\)/); // 괄호 안의 문자 추출
|
|
|
|
if (!match) {
|
|
alert("영업담당자 형식이 올바르지 않습니다. 예: 홍길동 (01201)");
|
|
throw "invalid manager_emp_no";
|
|
}
|
|
|
|
let extractedEmpNo = match[1]; // 괄호 안의 사번
|
|
|
|
let validEmployees = employeeList.map(e => e.id);
|
|
|
|
if (!validEmployees.includes(extractedEmpNo)) {
|
|
alert("영업담당자는 직원 목록에 있는 사람만 선택할 수 있습니다.");
|
|
throw "invalid manager_emp_no";
|
|
}
|
|
}
|
|
|
|
// 🔥 DB에는 사용자가 선택한 그대로 저장 (rawValue)
|
|
ch.manager_emp_no = rawValue;
|
|
}
|
|
|
|
if (ch.biz_number !== undefined) {
|
|
|
|
let raw = (ch.biz_number + "").replace(/[^0-9]/g, "");
|
|
|
|
if (raw.length !== 10) {
|
|
alert("사업자등록번호는 숫자 10자리여야 합니다. 예: 1234567890 또는 123-45-67890");
|
|
throw "invalid biz number";
|
|
}
|
|
|
|
// 10자리 → 하이픈 추가
|
|
let fmt = raw.replace(/(\d{3})(\d{2})(\d{5})/, "$1-$2-$3");
|
|
|
|
ch.biz_number = fmt; // 🔥 저장할 값 수정
|
|
}
|
|
|
|
let orgValue = (typeof ch.org_type === 'object' && ch.org_type?.id)
|
|
? ch.org_type.id
|
|
: ch.org_type;
|
|
|
|
let empValue = (typeof ch.manager_emp_no === 'object' && ch.manager_emp_no?.id)
|
|
? ch.manager_emp_no.id
|
|
: ch.manager_emp_no;
|
|
|
|
return $.post("/egbim/bbs/sales_clients.php", {
|
|
action: "update",
|
|
client_code: ch.recid,
|
|
|
|
client_name: ch.client_name,
|
|
business_type: ch.business_type,
|
|
org_type: orgValue,
|
|
manager_emp_no: empValue,
|
|
|
|
biz_number: ch.biz_number,
|
|
address: ch.address,
|
|
phone: ch.phone,
|
|
remarks: ch.remarks
|
|
});
|
|
|
|
})
|
|
).then(() => {
|
|
loadClients();
|
|
alert("저장되었습니다.");
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
/* -------------------------------------------------
|
|
🔵 loadClients() — DB 조회
|
|
-------------------------------------------------- */
|
|
function loadClients() {
|
|
fetch("/egbim/bbs/sales_clients.php?action=list")
|
|
.then(r => r.json())
|
|
.then(res => {
|
|
if (res.status === "ok") {
|
|
grid.records = res.records.map(row => ({
|
|
recid: row.client_code,
|
|
...row
|
|
}));
|
|
grid.refresh();
|
|
}
|
|
});
|
|
}
|
|
|
|
loadClients();
|
|
</script>
|
|
|
|
|
|
<?php
|
|
sales_layout_end();
|
|
?>
|