381 lines
14 KiB
TypeScript
381 lines
14 KiB
TypeScript
"use client"
|
|
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
|
|
import ComponentCard from '@/components/common/ComponentCard2';
|
|
import CtTable1 from '@/components/tables/CtTable1';
|
|
import Button from '@/components/ui/button/Button2';
|
|
import { DocsIcon, FileIcon, TableIcon, PlusIcon, TrashBinIcon, PencilIcon } from "@/icons";
|
|
import WithLabel from '@/components/form/WithLabel';
|
|
import Input from '@/components/form/input/InputField2';
|
|
import DatePicker from '@/components/form/date-picker2';
|
|
import Badge from "@/components/ui/badge/Badge";
|
|
|
|
import React, { Key } from "react";
|
|
import { useEffect, useState } from 'react';
|
|
import api, { addDaysYMD, convertDateTime2, convertDateTime3, postFileDownload, todayYMD, useAuthStore } from '@/lib/_AG';
|
|
|
|
import { useModal } from "@/hooks/useModal";
|
|
import AddModifyAccountModal, { AccountModalProps } from './AddModifyAccountModal';
|
|
import { useMultiState } from "@/hooks/useMultiState";
|
|
|
|
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, addNodeByKey, deleteNodeByKey } from "@/components/CtTree";
|
|
import { reqBizGroupTree2 } from "@/app/(admin)/biz-group/BizGroupContent";
|
|
import Select from "@/components/form/Select2";
|
|
import PageCountSelector from "@/components/PageCountSelector";
|
|
|
|
|
|
const SEARCH_LABEL_WIDTH_PX = 80;
|
|
//const COUNT_PER_PAGE = 10;
|
|
const PAGE_NUM_COUNT = 5;
|
|
|
|
|
|
export default function Account() {
|
|
const tokenPayload = useAuthStore((s) => s.tokenPayload); //Bruce, JWT
|
|
|
|
const [ tableData, setTableData ] = useState<any[]>([]);
|
|
const [ tableOffset, setTableOffset ] = useState<number>(0);
|
|
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
|
|
|
|
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
|
|
|
|
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
|
|
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
|
|
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
|
|
|
|
// group search fields
|
|
const [ name, setName ] = useState<string>("");
|
|
const [ biz_reg_num, setBizRegNum ] = useState<string>("");
|
|
|
|
//search fields
|
|
const [ user_id, setUserId ] = useState<string>("");
|
|
const [ email, setEmail ] = useState<string>("");
|
|
const [ nick_name, setNickName ] = useState<string>("");
|
|
const [ date_start, setDateStart ] = useState<string>();
|
|
const [ date_end, setDateEnd ] = useState<string>();
|
|
|
|
// modal
|
|
const { isOpen, openModal, closeModal } = useModal();
|
|
const modalData = useMultiState<AccountModalProps>({ biz_group_name: "", isModify: false,
|
|
gid: "", biz_group_id: "", user_id: "", user_pw: "", name: "", phone: "", email: "", state: "1",
|
|
perm_group: true, perm_uid1: true, perm_cancel: true, perm_account: true });
|
|
|
|
//function part
|
|
//
|
|
function reqAccountList(is_excel: boolean, biz_group_id: string) {
|
|
if (!biz_group_id)
|
|
return;
|
|
|
|
const params = {
|
|
offset: tableOffset,
|
|
limit: COUNT_PER_PAGE,
|
|
user_id: user_id,
|
|
email: email,
|
|
nick_name: nick_name,
|
|
date_start: date_start,
|
|
date_end: date_end,
|
|
biz_group_id: biz_group_id,
|
|
}
|
|
|
|
if (is_excel == true) {
|
|
postFileDownload('/api/get-account.do', params);
|
|
return;
|
|
}
|
|
|
|
api.post('/api/get-account.do', params).then((resp) => {
|
|
console.log(resp);
|
|
|
|
if (resp.data.errCode === 0) {
|
|
if (resp.data.result.list.length == 0) {
|
|
alert("조회 결과가 없습니다.");
|
|
setTableTotalCount(0);
|
|
setTableData([]);
|
|
return;
|
|
}
|
|
|
|
resp.data.result.list.forEach((item: any) => {
|
|
item.perm_group = (item.permission & 0x2) === 0x2;
|
|
item.perm_uid1 = (item.permission & 0x4) === 0x4;
|
|
item.perm_cancel = (item.permission & 0x8) === 0x8;
|
|
});
|
|
|
|
setTableTotalCount(resp.data.result.totalCount);
|
|
setTableData(resp.data.result.list);
|
|
}
|
|
else {
|
|
alert("일시적으로 사용할 수 없습니다 : " + resp.data.errCode);
|
|
}
|
|
})
|
|
.catch((err) => console.error(err));
|
|
}
|
|
|
|
function reqRemoveAccount(gid: string) {
|
|
const params = {
|
|
ids: gid
|
|
}
|
|
|
|
api.post('/api/remove-account.do', params).then((resp) => {
|
|
console.log(resp);
|
|
|
|
if (resp.data.errCode == 0) {
|
|
reqAccountList(false, selectedTreeKeys[0] as string);
|
|
}
|
|
else {
|
|
alert("일시적으로 사용할 수 없습니다 : " + resp.data.errCode);
|
|
}
|
|
})
|
|
.catch((err) => console.error(err))
|
|
}
|
|
//
|
|
|
|
|
|
// event processing part
|
|
//
|
|
const handleClickGroupSearch = () => {
|
|
if (tokenPayload?.permission == 0xffffffff) {
|
|
if (name == "" && biz_reg_num == "") {
|
|
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
|
|
return;
|
|
}
|
|
if (name != "" && name.length < 2) {
|
|
alert("그룹(사업자)명은 두글자 이상 입력해야 합니다.");
|
|
return;
|
|
}
|
|
if (biz_reg_num != "" && biz_reg_num.length < 2) {
|
|
alert("사업자등록번호는 두글자 이상 입력해야 합니다.");
|
|
return;
|
|
}
|
|
|
|
//reqBizGroupTree3("", setTreeData, setSelectedTreeKeys, setExpandedTreeKeys);
|
|
reqBizGroupTree2(true, "", "", "", "", name, biz_reg_num, treeData, setTreeData);
|
|
}
|
|
};
|
|
|
|
const handleClickNode = (key: Key) => {
|
|
//console.log("handleClickNode, key = ", key);
|
|
setTableOffset(0);
|
|
reqAccountList(false, key as string);
|
|
}
|
|
|
|
const handleClickTreeExpanded = (key: Key) => {
|
|
//console.log("handleClickTreeExpanded, key = ", key);
|
|
//const node = findNodeByKey(treeData, key);
|
|
//if (node.children == undefined)
|
|
// reqBizGroupTree2(false, key as string, "", "", "", "", "", treeData, setTreeData);
|
|
}
|
|
|
|
const handleClickAdd = () => {
|
|
if (selectedTreeKeys.length <= 0) {
|
|
alert("생성할 계정의 사업자를 선택하세요.");
|
|
return;
|
|
}
|
|
|
|
const node = findNodeByKey(treeData, selectedTreeKeys[0]);
|
|
modalData.setAll({biz_group_name: node.name, biz_reg_num: node.biz_reg_num,
|
|
isModify: false, gid: "", user_id: "", user_pw: "", name: "", phone: "", email: "", state: "1", biz_group_id: node.key});
|
|
openModal();
|
|
};
|
|
|
|
const handleClickDownload = () => {
|
|
reqAccountList(true, selectedTreeKeys[0] as string);
|
|
};
|
|
|
|
const handleClickSearch = () => {
|
|
if (selectedTreeKeys.length <= 0) {
|
|
alert("조회하려면 사업자를 선택해야 합니다.");
|
|
return;
|
|
}
|
|
|
|
reqAccountList(false, selectedTreeKeys[0] as string);
|
|
};
|
|
|
|
const handlePageChange = (page: number) => {
|
|
setTableOffset((page - 1) * COUNT_PER_PAGE);
|
|
};
|
|
|
|
const handleRowClickModify = (row: number) => {
|
|
const node = findNodeByKey(treeData, selectedTreeKeys[0]);
|
|
modalData.setAll({...tableData[row],
|
|
biz_group_name: node.name,
|
|
biz_reg_num: node.biz_reg_num,
|
|
isModify: true});
|
|
openModal();
|
|
};
|
|
|
|
const handleRowClickDelete = (row: number) => {
|
|
if (confirm("'" + tableData[row].user_id + "' 계정을 삭제하시겠습니까?")) {
|
|
reqRemoveAccount(tableData[row].gid);
|
|
}
|
|
};
|
|
|
|
const handleModalOk = () => {
|
|
closeModal();
|
|
reqAccountList(false, selectedTreeKeys[0] as string);
|
|
}
|
|
|
|
//useEffect(() => {
|
|
//}, []);
|
|
|
|
useEffect(() => {
|
|
//reqAccountList(false, selectedTreeKeys[0] as string);
|
|
}, [tableOffset]);
|
|
|
|
const columns = [
|
|
{
|
|
title: "등록일",
|
|
key: "reg_time" ,
|
|
renderItem: (item:any) => convertDateTime3(item.reg_time),
|
|
viewMobile: true,
|
|
},
|
|
{
|
|
title: "그룹",
|
|
key: "biz_group_name",
|
|
viewMobile: true,
|
|
},
|
|
{
|
|
title: "아이디",
|
|
key: "user_id",
|
|
viewMobile: true,
|
|
},
|
|
{
|
|
title: "이름",
|
|
key: "name",
|
|
},
|
|
{
|
|
title: "휴대폰번호",
|
|
key: "phone",
|
|
},
|
|
{
|
|
title: "이메일",
|
|
key: "email",
|
|
},
|
|
{
|
|
title: "상태",
|
|
key: "state",
|
|
renderItem: (item : any) => (
|
|
<Badge size="sm" color={item.state === 1 ? "success" : item.state === 4 ? "error" : "warning"}>
|
|
{item.state === 1 ? "정상" : "정지"}
|
|
</Badge>
|
|
)
|
|
},
|
|
{
|
|
title: "수정",
|
|
key: "_",
|
|
renderItem: (item: any, row: number) => (
|
|
<div>
|
|
<PencilIcon
|
|
className="cursor-pointer hover:fill-error-500 dark:hover:fill-error-500 fill-gray-700 dark:fill-gray-400"
|
|
onClick={() => {handleRowClickModify(row)}} />
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
title: "삭제",
|
|
key: "_",
|
|
renderItem: (item: any, row: number) => (
|
|
<div>
|
|
<TrashBinIcon
|
|
className="cursor-pointer hover:fill-error-500 dark:hover:fill-error-500 fill-gray-700 dark:fill-gray-400"
|
|
onClick={() => {handleRowClickDelete(row)}} />
|
|
</div>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div>
|
|
<PageBreadcrumb pageTitle1="계정 및 그룹관리" pageTitle2="계정관리" />
|
|
|
|
<div className="space-y-3">
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<ComponentCard title="사업자 선택">
|
|
<div className="flex-1 space-y-6">
|
|
{/*<div className="hidden sm:block h-[86px]"></div>*/}
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<WithLabel label="그룹(사업자)명" label_width={SEARCH_LABEL_WIDTH_PX}>
|
|
<Input type="text" placeholder="조회할 그룹(사업자)명 입력하세요." value={name} onChange={(e) => setName(e.target.value)}
|
|
onKeyDown={(e) => {if (e.key === "Enter") handleClickGroupSearch()}} />
|
|
</WithLabel>
|
|
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH_PX}>
|
|
<Input type="text" placeholder="조회할 사업자번호를 입력하세요." value={biz_reg_num} onChange={(e) => setBizRegNum(e.target.value)}
|
|
onKeyDown={(e) => {if (e.key === "Enter") handleClickGroupSearch()}} />
|
|
</WithLabel>
|
|
</div>
|
|
<div className="flex items-center justify-end gap-5">
|
|
<Button size="sm" variant="primary" onClick={handleClickGroupSearch}>사업자 조회</Button>
|
|
</div>
|
|
</div>
|
|
</ComponentCard>
|
|
|
|
<ComponentCard title="사업자 목록(여기서는 최상위 사업자만 조회됨)">
|
|
<div className="h-[100px] overflow-auto">
|
|
<CtTree
|
|
treeData={treeData}
|
|
selectedKeys={selectedTreeKeys}
|
|
setSelectedKeys={setSelectedTreeKeys}
|
|
onClickNode={handleClickNode}
|
|
expandedKeys={expandedTreeKeys}
|
|
setExpandedKeys={setExpandedTreeKeys}
|
|
onClickExpanded={handleClickTreeExpanded}
|
|
/>
|
|
</div>
|
|
</ComponentCard>
|
|
</div>
|
|
|
|
<ComponentCard title="계정 목록 조회" titleIcon={<TableIcon />}>
|
|
|
|
<div className="space-y-3">
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
<WithLabel label="아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
|
|
<Input type="text" placeholder="조회할 아이디를 입력하세요." value={user_id} onChange={(e) => setUserId(e.target.value)} />
|
|
</WithLabel>
|
|
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH_PX}>
|
|
<Input type="email" placeholder="조회할 이메일을 입력하세요." value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
</WithLabel>
|
|
<WithLabel label="닉네임" label_width={SEARCH_LABEL_WIDTH_PX}>
|
|
<Input type="text" placeholder="조회할 닉네임을 입력하세요." value={nick_name} onChange={(e) => setNickName(e.target.value)} />
|
|
</WithLabel>
|
|
</div>
|
|
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<WithLabel label="등록일" label_width={50}>
|
|
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
|
|
<DatePicker
|
|
id="date_start-picker"
|
|
placeholder="조회 시작일"
|
|
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
|
|
defaultDate={date_start}
|
|
/>
|
|
<DatePicker
|
|
id="date_end-picker"
|
|
placeholder="조회 종료일"
|
|
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
|
|
defaultDate={date_end}
|
|
/>
|
|
</div>
|
|
</WithLabel>
|
|
<div className="flex items-center justify-end gap-5">
|
|
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}>엑셀파일 다운로드</Button>
|
|
<Button size="sm" variant="primary" onClick={handleClickSearch}>조회</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-end gap-5">
|
|
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
|
|
</div>
|
|
|
|
<CtTable1 columns={columns} bodyData={tableData}
|
|
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
|
|
onClickPageChange={handlePageChange} />
|
|
|
|
<div>
|
|
<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickAdd}>신규 등록하기</Button>
|
|
</div>
|
|
|
|
</ComponentCard>
|
|
|
|
<AddModifyAccountModal multiState={modalData} onOk={handleModalOk} isOpen={isOpen} closeModal={closeModal} />
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|