diff --git a/src/apis/user.js b/src/apis/user.js
new file mode 100644
index 0000000..0186cbd
--- /dev/null
+++ b/src/apis/user.js
@@ -0,0 +1,17 @@
+//----------------------------------------------------------------------------
+// Board : 유저관리
+//----------------------
+
+import axios from 'utils/axios';
+import { GET_USER_BOARD_LIST, SAVE_USER_BOARD, DELETE_USER_BOARD } from 'commons/ApiUrl';
+import { setRowId } from './common';
+
+// eslint-disable-next-line import/prefer-default-export
+export async function getBoardList(params) {
+ const res = await axios.get(GET_USER_BOARD_LIST, { params });
+ if (res.success) {
+ res.data = res.data.map((d, idx) => ({ ...d, rowId: setRowId(params, idx) }));
+ return res;
+ }
+ return res;
+}
diff --git a/src/commons/ApiUrl.js b/src/commons/ApiUrl.js
index 17653af..c50cc55 100644
--- a/src/commons/ApiUrl.js
+++ b/src/commons/ApiUrl.js
@@ -24,3 +24,8 @@ export const SAVE_PARKING_SIMSA_TARGET = '/api/v1/ctgy/parking/target';
export const GET_RESIDENT_DATA_LIST = '/api/v1/ctgy/resident/data';
export const SAVE_RESIDENT_DATA = '/api/v1/ctgy/resident/data';
export const GET_RESIDENT = '/api/v1/ctgy/resident/';
+
+// 사용자 관리
+export const GET_USER_BOARD_LIST = '/api/v1/ctgy/pboard/';
+export const SAVE_USER_BOARD = '/api/v1/ctgy/file/pboard';
+export const DELETE_USER_BOARD = '/api/v1/ctgy/file/pboard/';
diff --git a/src/routes/MainRoutes.js b/src/routes/MainRoutes.js
index 1a2322f..1caf62b 100755
--- a/src/routes/MainRoutes.js
+++ b/src/routes/MainRoutes.js
@@ -5,6 +5,7 @@ import MainLayout from 'layout/MainLayout';
import Loadable from 'ui-component/Loadable';
import AuthGuard from 'utils/route-guard/AuthGuard';
import ResidentDataReview from '../views/biz/resident/Review';
+import Juror from '../views/biz/user/Juror';
// sample page routing
const SamplePage = Loadable(lazy(() => import('views/sample-page')));
@@ -17,6 +18,7 @@ const Board = Loadable(lazy(() => import('views/biz/board/Board')));
const ParkingReview = Loadable(lazy(() => import('views/biz/parking/Review')));
const ParkingDetails = Loadable(lazy(() => import('views/biz/parking/ModalDetails')));
const ParkingRegister = Loadable(lazy(() => import('views/biz/parking/Regist')));
+const UserManager = Loadable(lazy(() => import('views/biz/user/UserManager')));
// component
const ModalForm = Loadable(lazy(() => import('views/form/Modal')));
@@ -83,7 +85,11 @@ const MainRoutes = {
/* 사용자 */
{
path: '/user/management',
- element:
+ element:
+ },
+ {
+ path: '/user/juror',
+ element:
},
/* SMS */
{
@@ -95,11 +101,6 @@ const MainRoutes = {
path: '/board',
element:
},
- {
- path: '/user/juror',
- element:
- },
-
{
path: '/parking/details',
element:
diff --git a/src/views/biz/user/Juror.jsx b/src/views/biz/user/Juror.jsx
new file mode 100644
index 0000000..377e611
--- /dev/null
+++ b/src/views/biz/user/Juror.jsx
@@ -0,0 +1,152 @@
+import { useEffect, useState } from 'react';
+
+// material-ui
+import { Button, Divider, Grid, InputAdornment, MenuItem, OutlinedInput, Select } from '@mui/material';
+
+// assets
+import { IconSearch } from '@tabler/icons';
+
+// berry ui
+import MainCard from 'ui-component/cards/MainCard';
+
+// project imports
+import MuiDataGrid from 'views/form/MuiDataGrid';
+import { getBoardList } from '../../../apis/user';
+import CmmModal from '../../form/Modal/CmmModal';
+import UserManagerForm from './UserManagerForm';
+import { deletePublicBoard, savePublicBoard } from '../../../apis/public';
+
+const UserManager = () => {
+ const [category, setCategory] = useState('ciTitle');
+ const [searchTxt, setSearchTxt] = useState('');
+
+ const [totalCount, setTotalCount] = useState(0);
+ const [rowsState, setRowsState] = useState({
+ page: 0,
+ pageSize: 10,
+ rows: []
+ // loading: false
+ });
+
+ // 등록 버튼 state
+ const [open, setOpen] = useState(false);
+ const [selectedRow, setSelectedRow] = useState({});
+ const [create, setCreate] = useState(false);
+ const [title, setTitle] = useState();
+
+ const columns = [
+ { headerName: '게시판코드', field: 'ciCode' },
+ { headerName: '글번호', field: 'ciContentno' },
+ { headerName: '제목', field: 'ciTitle', editable: true },
+ { headerName: '사용자ID', field: 'ciId' },
+ { headerName: '사용자 비번', field: 'ciPwd' }
+ ];
+ const handleSearch = async (event) => {
+ if (event.type === 'keydown' && event.key === 'Enter') {
+ const newString = event?.target.value;
+ setSearchTxt(newString);
+ }
+ };
+
+ const search = () => {
+ const params = {
+ page: rowsState.page,
+ size: rowsState.pageSize
+ };
+
+ getBoardList(params).then((response) => {
+ if (response && response.data) {
+ setTotalCount(response.count);
+ setRowsState((prevState) => ({ ...prevState, rows: response.data }));
+ }
+ });
+ };
+ useEffect(() => {
+ search();
+ }, [rowsState.page, rowsState.pageSize, category, searchTxt]); // rowsState.page, rowsState.pageSize, rowsState.rows]);
+
+ // model창
+ const submitPublicBoard = (type, payload) => {
+ switch (type) {
+ case 'SAVE':
+ savePublicBoard(payload).then(() => {
+ search();
+ setOpen(false);
+ }); // .then((res) => {
+ break;
+ case 'DELETE':
+ deletePublicBoard(payload).then(() => {
+ search();
+ setOpen(false);
+ }); // .then((res) => {
+ break;
+ default:
+ }
+ };
+
+ // 공지사항 버튼 이벤트
+ const handleCreate = () => {
+ setSelectedRow({});
+ setTitle('공지사항 등록');
+ setCreate(true);
+ setOpen(true);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default UserManager;
diff --git a/src/views/biz/user/JurorForm.jsx b/src/views/biz/user/JurorForm.jsx
new file mode 100644
index 0000000..f307bb7
--- /dev/null
+++ b/src/views/biz/user/JurorForm.jsx
@@ -0,0 +1,226 @@
+import { useMemo, useRef, useState } from 'react';
+
+import { useAlert } from 'react-alert';
+// material-ui
+import { Button, FormControl, Grid, MenuItem, Select, TextField } from '@mui/material';
+
+// assets
+
+// berry ui
+import ReactQuill from 'react-quill';
+import 'react-quill/dist/quill.snow.css';
+
+// project imports
+import InputLabel from 'ui-component/extended/Form/InputLabel';
+
+import { Delete, List, Save } from '@mui/icons-material';
+import { fileDownload } from '../../../apis/common';
+import FileForm from 'views/form/FileForm';
+
+const PublicBoardForm = (props) => {
+ // eslint-disable-next-line react/prop-types
+ const { create, inCode, inDept, inTitle, inHit, inName, inNalja, inFilename, inContents, setOpen, handleModalSave } = props;
+ const alert = useAlert();
+ const quillRef = useRef();
+ const [dept, setDept] = useState(inDept || '주정차위반');
+ const [subject, setSubject] = useState(inTitle || '');
+ const [contents, setContents] = useState(inContents || '');
+ const [filesInfo, setFilesInfo] = useState();
+ const [selectedFile, setSelectedFile] = useState(inFilename || ''); // 파일
+ // const [fileData, setFileData] = useState();
+
+ const onList = () => {
+ setOpen(false);
+ };
+ const onSave = () => {
+ // TODO : validation check 추가
+ const formData = new FormData();
+ formData.append('inCode', inCode ?? '');
+ formData.append('inTitle', subject);
+ formData.append('inDept', dept);
+ formData.append('inContents', contents);
+ formData.append('inFilename', selectedFile ?? '');
+
+ if (filesInfo && filesInfo.length > 0) {
+ // eslint-disable-next-line no-plusplus
+ for (let i = 0; i < filesInfo.length; i++) formData.append('files', filesInfo[i]);
+ }
+ handleModalSave('SAVE', formData);
+ };
+
+ const onDelete = () => {
+ handleModalSave('DELETE', inCode);
+ };
+
+ const imageHandler = () => {
+ const input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.click();
+
+ input.onchange = async () => {
+ if (input.files) {
+ const file = input.files[0];
+ const formData = new FormData();
+ formData.append('image', file);
+
+ console.log(formData);
+
+ // 파일이 input 태그에 담기면 실행 될 함수
+ input.onchange = async () => {
+ const file = input.files;
+ if (file !== null) {
+ formData.append('image', file[0]);
+
+ try {
+ // 서저 저장
+ // const res = await axios.get('/');
+ //
+ const url = '/Users/minuk/Pictures/test.png';
+
+ // 이미지 태그 생성
+ const range = quillRef.current?.getEditor().getSelection()?.index;
+ if (range !== null && range !== undefined) {
+ const quill = quillRef.current?.getEditor();
+
+ quill?.setSelection(range, 1);
+
+ quill?.clipboard.dangerouslyPasteHTML(range, ``);
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ };
+ }
+ };
+ };
+
+ const modules = useMemo(
+ () => ({
+ toolbar: {
+ container: [
+ ['bold', 'italic', 'underline', 'strike', 'blockquote'],
+ [{ size: ['small', false, 'large', 'huge'] }, { color: [] }],
+ [{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }, { align: [] }]
+ // ['image', 'video']
+ ],
+ handlers: {
+ image: imageHandler
+ }
+ }
+ }),
+ []
+ );
+
+ const onChangeFile = (file) => {
+ setSelectedFile(file.name);
+ setFilesInfo([file]);
+ };
+
+ // const onChangeFile = (e) => {
+ // setSelectedFile(e.target.files[0].name);
+ // setFilesInfo(e.target.files);
+ // };
+
+ const handleFileDownload = () => {
+ if (!inFilename) {
+ alert.show('등록된 파일이 없습니다.');
+ return;
+ }
+ fileDownload(inCode, inFilename, alert).then(() => {});
+ };
+
+ return (
+ <>
+
+
+
+ setSubject(e.target.value)} fullWidth />
+
+
+
+ 진술유형
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ if (element !== null) {
+ quillRef.current = element;
+ }
+ }}
+ value={contents}
+ onChange={setContents}
+ modules={modules}
+ theme="snow"
+ placeholder="내용을 입력해주세요."
+ />
+
+
+
+
+
+
+
+
+
+
+ } onClick={onList}>
+ 목록
+
+
+
+ } onClick={onSave}>
+ 저장
+
+
+ {!create && (
+
+ } onClick={onDelete}>
+ 삭제
+
+
+ )}
+
+ >
+ );
+};
+export default PublicBoardForm;
diff --git a/src/views/biz/user/UserManager.jsx b/src/views/biz/user/UserManager.jsx
new file mode 100644
index 0000000..307d3c3
--- /dev/null
+++ b/src/views/biz/user/UserManager.jsx
@@ -0,0 +1,182 @@
+import { useEffect, useState } from 'react';
+
+// material-ui
+import { Button, Divider, Grid, InputAdornment, MenuItem, OutlinedInput, Select, Link } from '@mui/material';
+
+// assets
+import { IconSearch, IconFileText } from '@tabler/icons';
+
+// berry ui
+import MainCard from 'ui-component/cards/MainCard';
+
+// project imports
+import MuiDataGrid from 'views/form/MuiDataGrid';
+import { getBoardList } from '../../../apis/user';
+import CmmModal from '../../form/Modal/CmmModal';
+import UserManagerForm from './UserManagerForm';
+import { deletePublicBoard, getPublicBoardList, modifyPublicBoardHitCount, savePublicBoard } from '../../../apis/public';
+
+const UserManager = () => {
+ const [category, setCategory] = useState('ciTitle');
+ const [searchTxt, setSearchTxt] = useState('');
+
+ const [totalCount, setTotalCount] = useState(0);
+ const [rowsState, setRowsState] = useState({
+ page: 0,
+ pageSize: 10,
+ rows: []
+ // loading: false
+ });
+
+ // 등록 버튼 state
+ const [open, setOpen] = useState(false);
+ const [selectedRow, setSelectedRow] = useState({});
+ const [create, setCreate] = useState(false);
+ const [title, setTitle] = useState();
+
+ const columns = [
+ { headerName: 'No.', headerAlign: 'center', field: 'rowId', align: 'center', width: 70 },
+ {
+ headerName: '사용자아이디',
+ headerAlign: 'center',
+ field: 'inDept',
+ align: 'center'
+ },
+ {
+ headerName: '이름',
+ headerAlign: 'center',
+ field: 'inTitle',
+ minWidth: 200,
+ renderCell: (params) => (
+
+ {params.value}
+
+ )
+ },
+ { headerName: '전화번호', headerAlign: 'center', field: 'a', align: 'center' },
+ { headerName: '이메일', headerAlign: 'center', field: 'b', align: 'center' },
+ { headerName: '사용여부', headerAlign: 'center', field: 'c', align: 'center' },
+ { headerName: '사용구분', headerAlign: 'center', field: 'd', align: 'center' },
+ { headerName: '생성일시', headerAlign: 'center', field: 'e', align: 'right' }
+ ];
+ // 리스트 조회
+ const search = () => {
+ const params = {
+ page: rowsState.page,
+ size: rowsState.pageSize
+ };
+
+ getPublicBoardList(params).then((response) => {
+ // console.log(response);
+ if (response && response.data) {
+ setTotalCount(response.count);
+ setRowsState((prevState) => ({ ...prevState, rows: response.data }));
+ }
+ });
+ };
+
+ const handleSearch = async (event) => {
+ if (event.type === 'keydown' && event.key === 'Enter') {
+ const newString = event?.target.value;
+ setSearchTxt(newString);
+ }
+ };
+ useEffect(() => {
+ search();
+ }, [rowsState.page, rowsState.pageSize, category, searchTxt]);
+
+ // 사용자 등록버튼 클릭 이벤트
+ const handleCreate = () => {
+ setSelectedRow({});
+ setTitle('사용자 등록');
+ setCreate(true);
+ setOpen(true);
+ };
+
+ const handleOnCellClick = (e) => {
+ if (e?.field === 'inTitle') {
+ setCreate(false);
+ setTitle('사용자 정보 변경');
+ setSelectedRow(e?.row);
+ modifyPublicBoardHitCount(e?.row?.inCode);
+ setOpen(true);
+ }
+ };
+
+ // model창
+ const submitPublicBoard = (type, payload) => {
+ switch (type) {
+ case 'SAVE':
+ savePublicBoard(payload).then(() => {
+ search();
+ setOpen(false);
+ }); // .then((res) => {
+ break;
+ case 'DELETE':
+ deletePublicBoard(payload).then(() => {
+ search();
+ setOpen(false);
+ }); // .then((res) => {
+ break;
+ default:
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default UserManager;
diff --git a/src/views/biz/user/UserManagerForm.jsx b/src/views/biz/user/UserManagerForm.jsx
new file mode 100644
index 0000000..2168e3e
--- /dev/null
+++ b/src/views/biz/user/UserManagerForm.jsx
@@ -0,0 +1,185 @@
+import { useMemo, useRef, useState } from 'react';
+
+import { useAlert } from 'react-alert';
+// material-ui
+import { Button, FormControl, Grid, MenuItem, Select, TextField } from '@mui/material';
+
+// assets
+
+// berry ui
+import ReactQuill from 'react-quill';
+import 'react-quill/dist/quill.snow.css';
+
+// project imports
+import InputLabel from 'ui-component/extended/Form/InputLabel';
+
+import { Delete, List, Save } from '@mui/icons-material';
+import { fileDownload } from '../../../apis/common';
+import FileForm from 'views/form/FileForm';
+
+const PublicBoardForm = (props) => {
+ // eslint-disable-next-line react/prop-types
+ const { create, inCode, inDept, inTitle, inHit, inName, inNalja, inFilename, inContents, setOpen, handleModalSave } = props;
+ const alert = useAlert();
+ const quillRef = useRef();
+ const [dept, setDept] = useState(inDept || '주정차위반');
+ const [subject, setSubject] = useState(inTitle || '');
+ const [contents, setContents] = useState(inContents || '');
+ const [filesInfo, setFilesInfo] = useState();
+ const [selectedFile, setSelectedFile] = useState(inFilename || ''); // 파일
+ // const [fileData, setFileData] = useState();
+
+ const onList = () => {
+ setOpen(false);
+ };
+ const onSave = () => {
+ // TODO : validation check 추가
+ const formData = new FormData();
+ formData.append('inCode', inCode ?? '');
+ formData.append('inTitle', subject);
+ formData.append('inDept', dept);
+ formData.append('inContents', contents);
+ formData.append('inFilename', selectedFile ?? '');
+
+ if (filesInfo && filesInfo.length > 0) {
+ // eslint-disable-next-line no-plusplus
+ for (let i = 0; i < filesInfo.length; i++) formData.append('files', filesInfo[i]);
+ }
+ handleModalSave('SAVE', formData);
+ };
+
+ const onDelete = () => {
+ handleModalSave('DELETE', inCode);
+ };
+
+ const imageHandler = () => {
+ const input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.click();
+
+ input.onchange = async () => {
+ if (input.files) {
+ const file = input.files[0];
+ const formData = new FormData();
+ formData.append('image', file);
+
+ console.log(formData);
+
+ // 파일이 input 태그에 담기면 실행 될 함수
+ input.onchange = async () => {
+ const file = input.files;
+ if (file !== null) {
+ formData.append('image', file[0]);
+
+ try {
+ // 서저 저장
+ // const res = await axios.get('/');
+ //
+ const url = '/Users/minuk/Pictures/test.png';
+
+ // 이미지 태그 생성
+ const range = quillRef.current?.getEditor().getSelection()?.index;
+ if (range !== null && range !== undefined) {
+ const quill = quillRef.current?.getEditor();
+
+ quill?.setSelection(range, 1);
+
+ quill?.clipboard.dangerouslyPasteHTML(range, ``);
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ };
+ }
+ };
+ };
+
+ const modules = useMemo(
+ () => ({
+ toolbar: {
+ container: [
+ ['bold', 'italic', 'underline', 'strike', 'blockquote'],
+ [{ size: ['small', false, 'large', 'huge'] }, { color: [] }],
+ [{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }, { align: [] }]
+ // ['image', 'video']
+ ],
+ handlers: {
+ image: imageHandler
+ }
+ }
+ }),
+ []
+ );
+
+ const onChangeFile = (file) => {
+ setSelectedFile(file.name);
+ setFilesInfo([file]);
+ };
+
+ // const onChangeFile = (e) => {
+ // setSelectedFile(e.target.files[0].name);
+ // setFilesInfo(e.target.files);
+ // };
+
+ const handleFileDownload = () => {
+ if (!inFilename) {
+ alert.show('등록된 파일이 없습니다.');
+ return;
+ }
+ fileDownload(inCode, inFilename, alert).then(() => {});
+ };
+
+ return (
+ <>
+
+
+
+ setSubject(e.target.value)} fullWidth />
+
+
+ setSubject(e.target.value)} fullWidth />
+
+
+ setSubject(e.target.value)} fullWidth />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!create && (
+
+ } onClick={onDelete}>
+ 삭제
+
+
+ )}
+
+ } onClick={onList}>
+ 목록
+
+
+
+ } onClick={onSave}>
+ 저장
+
+
+
+ >
+ );
+};
+export default PublicBoardForm;