From c57e0dc7dc4694a7c3efabc318c1615bea520dd2 Mon Sep 17 00:00:00 2001 From: Kurt92 Date: Thu, 7 Apr 2022 16:35:25 +0900 Subject: [PATCH] test --- src/apis/user.js | 17 ++ src/commons/ApiUrl.js | 5 + src/routes/MainRoutes.js | 13 +- src/views/biz/user/Juror.jsx | 152 +++++++++++++++++ src/views/biz/user/JurorForm.jsx | 226 +++++++++++++++++++++++++ src/views/biz/user/UserManager.jsx | 182 ++++++++++++++++++++ src/views/biz/user/UserManagerForm.jsx | 185 ++++++++++++++++++++ 7 files changed, 774 insertions(+), 6 deletions(-) create mode 100644 src/apis/user.js create mode 100644 src/views/biz/user/Juror.jsx create mode 100644 src/views/biz/user/JurorForm.jsx create mode 100644 src/views/biz/user/UserManager.jsx create mode 100644 src/views/biz/user/UserManagerForm.jsx 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="내용을 입력해주세요." + /> + + + + + + + + + + + + + + + + {!create && ( + + + + )} + + + ); +}; +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 && ( + + + + )} + + + + + + + + + ); +}; +export default PublicBoardForm;