Compare commits

...

43 Commits
main ... mpower

Author SHA1 Message Date
jhseo b877d66a9b style: 문구 수정 및 설정 배포 관련 내용 추가
fix: 리액트 관련 일부 버전 업데이트
1 day ago
sjh88 2df9eda17f fix:
-Dashboard 심사자 이름 *로 변경
-심의 목록 차량번호 뒤 4자리 *로 변경
-모바일 사용 시 개별심사 데이터가 정확하게 보이지 않는 화면 개선 요청
-관리자 사용자관리 비활성 계정 복구 및 패스워드 변경 기능 추가
2 years ago
sjh88 bb8dbde9f7 style: 인쇄 문구 수정 2 years ago
sjh88 7cadb24e5a style: 자료등록 시 문구 추가 안내 2 years ago
sjh88 ad9d6e49bc fix: 사용자 심사마감일시 제거 2 years ago
sjh88 55da0f001d fix: post 통신 timeout 설정 2 years ago
sjh88 7622b85232 fix: 주정차 위반 심의등록 날짜 기능 추가 및 심의 처리 시 로딩바 표시되도록 적용 2 years ago
sjh88 621f02ad76 fix: 날짜 동작오류로 인해 x-date-pickers 적용 2 years ago
sjh88 64d6cf2bbc fix: 단속내용 인쇄기능 추가 및 답변 내용 수정, 심의목록 심사기간 및 마감일시 수정 기능, 심의 처리 시 에러나면 Exception나는 부분 제거 후 log insert 처리 2 years ago
Kurt92 72486e1b1e fix: logo Change final 2 years ago
Kurt92 87c139090f fix: logo Change final 2 years ago
Kurt92 996098016e Merge branch 'main' into mpower
# Conflicts:
#	src/ui-component/Logo.js
2 years ago
minuk926 42b70aa8f0 fix: 심사화면 vertical scroll 2 years ago
minuk926 0790af9d72 fix: react-query 제거
소스정리
2 years ago
minuk926 cbe146ba1c fix: 심사대상 등록 유효성 체크 fix 2 years ago
minuk926 c952afc0f6 fix: 이미지 업로드 preview size fix 2 years ago
minuk926 c41c37f682 fix: 심사 - 심사대상 이미지 view : 등록된 이미지만 보이도록 변경 2 years ago
minuk926 0bc3fddbb7 fix: 심사 - 심사대상 이미지 view size 조정 2 years ago
minuk926 0333e8087b feat: 심의결과 excel download 기능 추가 2 years ago
minuk926 5831c191a5 feat: 심의결과 excel download 기능 추가 2 years ago
minuk926 f8e270dc74 fix: Grid excel download rename 2 years ago
minuk926 a18cd21cae fix: Grid excel download rename 2 years ago
minuk926 d760c5ebff fix: 삭제 버튼 색생 fix 2 years ago
minuk926 9d05ef1d1c fix: 강남심사 반영 2 years ago
minuk926 d695f9b5c2 fix: 주정차 심사 반영 완료
source freezing
2 years ago
minuk926 fe405f54ac fix: 주정차 심사 반영 완료
source freezing
2 years ago
minuk926 0303af2827 fix: 주정차 심사 반영 완료 2 years ago
minuk926 5996a3c1d8 fix: 주정차 심사 반영중 2 years ago
minuk926 f72e9fed7c fix: 주정차 심사 반영중 2 years ago
minuk926 d9bc8c2abb fix: 주정차 심사 반영중 2 years ago
minuk926 afe55a91ac fix: 주정차 심사 반영중 2 years ago
minuk926 215a5d6a17 fix: 주정차 심사 반영중 2 years ago
minuk926 e9b1a7c4eb fix: dashboard 공지사항 제목 색상 fix 2 years ago
minuk926 51a0fbdcf0 fix: dashboard 공지사항 제목 색상 fix 2 years ago
minuk926 bc3f33fa63 fix: dashboard 공지사항 제목 색상 fix 2 years ago
minuk926 dab63d74b3 config: production confg fix 2 years ago
minuk926 aa07b2a93f config: production confg fix 2 years ago
minuk926 a3bbaee985 config: production confg fix 2 years ago
minuk926 96f9bef27a config: production confg fix 2 years ago
minuk926 43415c908d fix: cors middleware 설정 추가 2 years ago
minuk926 997786fe93 fix: cors middleware 설정 추가 2 years ago
minuk926 7841847321 fix: cors middleware 설정 추가 2 years ago
minuk926 5f41b17def fix: cors middleware 설정 추가 2 years ago

@ -1,13 +0,0 @@
# .git 과 .cache 폴더를 무시
.git
.cache
# 모든 마크다운 파일들 (md) 파일들을 무시,
# 모든 README*.md 파일 무시
*.md
IREADME*.md
node_modules
npm-debug.log
# build
.idea

@ -2,4 +2,5 @@ NODE_PATH=src
REACT_APP_MODE=local
REACT_APP_VERSION = v0.0.1
REACT_APP_API_URL=http://localhost:8090
REACT_APP_SERVER_TIMEOUT=6000
#REACT_APP_API_URL=http://211.119.124.73:8090
REACT_APP_SERVER_TIMEOUT=60000

@ -1,6 +1,7 @@
NODE_PATH=src
REACT_APP_MODE=production
REACT_APP_VERSION = v0.0.1
#REACT_APP_API_URL=http://211.119.124.9:8090
REACT_APP_API_URL=http://localhost:8090
REACT_APP_SERVER_TIMEOUT=6000
#REACT_APP_API_URL=http://211.119.124.9:8090
#REACT_APP_API_URL=http://211.119.124.62:8090
REACT_APP_SERVER_TIMEOUT=60000

@ -29,6 +29,7 @@
"react/no-array-index-key": 0,
"react/jsx-props-no-spreading": 0,
"react/forbid-prop-types": 0,
"react/no-unknown-property": 0,
"import/order": 0,
"import/no-cycle": 0,
"no-console": 0,

2
.gitignore vendored

@ -13,7 +13,7 @@
# misc
.DS_Store
#.env.local
#cal
#.env.production
npm-debug.log*

@ -1,22 +0,0 @@
FROM nginx
ADD ./build /usr/share/nginx/html
# 80 포트 오픈
EXPOSE 80
# container 실행 시 nginx 시작함
CMD ["nginx", "-g", "daemon off;"]
# root 에 app 폴더를 생성
# RUN mkdir /app
# work dir 고정
# WORKDIR /app
# work dir 에 build 폴더 생성 /app/build
# RUN mkdir ./build
# host pc의 현재경로의 build 폴더를 workdir 의 build 폴더로 복사
# ADD ./build ./build
# nginx 의 default.conf backup
# RUN mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.backup
# host pc 의 nginx.conf 를 아래 경로에 복사
# COPY ./nginx.conf /etc/nginx/conf.d

@ -1,12 +0,0 @@
node {
stage('Clone repository') {
checkout scm
}
stage('Build docker image') {
app = docker.build("xit/opst-fo:latest") //docker image build 및 이름을 xit/opst-fo:$BUILD_NUMBER(빌드번호) 설정
}
//stage('Docker run'){
// sh "docker run --rm --name opst-fo -d -p 80:80 xit/opst-fo:latest"
//}
}

@ -1,3 +1,17 @@
### Start
```text
# node 버전
v16.13.1
nvm 설치 시 다양한 버전 관리 및 사용 가능 (※nvm use 적용 안 될 경우: 기존 node 설치 폴더 삭제)
#배포 시 (Front)
- npm run build 명령어를 terminal에 입력 후 생성되는 build 폴더를 압축
- 기존 build 폴더는 백업한다
- 신규 생성된 build 폴더를 기존 폴더에 덮어씌운다. (D:\KangnamSIM)
- cmd 관리자실행 모드로 실행하여 D:\tools\was\nginx-1.20.2 폴더로 가서 nginx -s reload 명령어를 입력한다.
```
### core-js@2.6.12: core-js@<3.4 is no longer maintained and not recommended for usage due to the
number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.
```shell

49581
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -2,7 +2,9 @@
"name": "xit-opst-fo",
"version": "0.0.1",
"private": true,
"proxy": "http://localhost:8090",
"dependencies": {
"@date-io/jalaali": "^2.16.1",
"@emotion/cache": "^11.7.1",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
@ -20,6 +22,7 @@
"@mui/system": "^5.4.1",
"@mui/utils": "^5.4.1",
"@mui/x-data-grid": "^5.5.0",
"@mui/x-date-pickers": "^6.0.3",
"@react-pdf/renderer": "^2.1.1",
"@reduxjs/toolkit": "^1.7.2",
"@tabler/icons": "^1.53.0",
@ -29,7 +32,7 @@
"chance": "^1.1.8",
"core-js": "^3",
"csstype": "^3.0.10",
"date-fns": "^2.28.0",
"date-fns": "^2.29.3",
"draft-js": "^0.11.7",
"emoji-picker-react": "^3.5.1",
"env-cmd": "^10.1.0",
@ -69,9 +72,11 @@
"react-quill": "^2.0.0-beta.4",
"react-redux": "^7.2.6",
"react-resizable": "^3.0.4",
"react-responsive": "^9.0.2",
"react-router-dom": "^6.2.1",
"react-scripts": "^4.0.3",
"react-slick": "^0.28.1",
"react-spinners": "^0.13.8",
"react-syntax-highlighter": "^15.4.5",
"react-timer-hook": "^3.0.5",
"react-to-print": "^2.14.4",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -1,18 +0,0 @@
<svg width="46" height="55" viewBox="0 0 46 55" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0)">
<path d="M19.6667 55C8.82205 55 0 46.2504 0 35.4968C0 24.7431 8.82292 15.9935 19.6667 15.9935C30.5105 15.9935 39.3334 24.7431 39.3334 35.4968C39.3334 46.2504 30.5122 55 19.6667 55ZM19.6667 17.8563C9.8587 17.8563 1.87839 25.7686 1.87839 35.4959C1.87839 45.2233 9.8587 53.1355 19.6667 53.1355C29.4747 53.1355 37.4559 45.2215 37.4559 35.4942C37.4559 25.7668 29.4765 17.8563 19.6667 17.8563Z" fill="#2196F3"/>
<path d="M33.9387 36.3618C33.3269 34.1133 27.7188 33.8706 24.3807 34.6949C22.6326 35.1283 20.846 35.6917 19.0034 36.0159C20.3521 37.2026 21.8005 38.3251 23.879 38.6042C29.0361 39.2942 32.2404 37.6898 33.9387 36.3618Z" fill="#2196F3"/>
<path d="M23.8788 38.6042C21.7959 38.3251 20.3519 37.2026 19.0032 36.016C16.9159 34.1792 15.0594 32.189 11.4154 32.9379C5.62198 34.1289 4.85978 40.9247 9.3333 45.2917C11.254 47.2864 13.7197 48.6822 16.4284 49.3079C19.137 49.9336 21.9709 49.7621 24.5828 48.8144C27.1946 47.8667 29.4709 46.1839 31.1327 43.9724C32.7945 41.7608 33.7696 39.1165 33.9385 36.3635C32.2402 37.6898 29.0358 39.2942 23.8788 38.6042Z" fill="#673AB7"/>
<path d="M26.9105 23.8962C26.1876 25.4331 32.6321 27.1381 33.4031 32.2419C33.7746 27.2178 27.8046 21.9962 26.9105 23.8962Z" fill="#2196F3"/>
<path d="M13.3649 30.3107C14.5267 29.8335 15.0784 28.5126 14.5972 27.3604C14.116 26.2083 12.784 25.6611 11.6222 26.1384C10.4604 26.6156 9.90867 27.9365 10.3899 29.0887C10.8712 30.2408 12.2031 30.7879 13.3649 30.3107Z" fill="#673AB7"/>
<path d="M18.5351 24.1103C19.0786 23.5714 19.0786 22.6977 18.5351 22.1587C17.9917 21.6198 17.1106 21.6198 16.5672 22.1587C16.0238 22.6977 16.0238 23.5714 16.5672 24.1103C17.1106 24.6492 17.9917 24.6492 18.5351 24.1103Z" fill="#2196F3"/>
<path d="M23.4513 15.2376C25.4617 9.3485 24.1103 4.64345 19.9786 2.40881C17.1544 2.97831 15.4779 4.334 14.5444 6.20544C20.0843 5.76077 23.5999 9.1994 23.4513 15.2376Z" fill="#2196F3"/>
<path d="M46.0001 10.0923C36.0487 6.55051 29.7685 7.76491 28.7808 15.8349C34.4841 21.6703 40.2286 18.8774 46.0001 10.0923Z" fill="#2196F3"/>
<path d="M38.0851 6.89635C38.5466 4.94082 38.7861 2.6299 38.8219 0C28.5017 2.27885 23.8473 6.6337 27.3584 13.9782C27.5333 14.0198 27.7011 14.0536 27.8698 14.0883C28.6905 8.34132 32.3031 6.2133 38.0851 6.89635Z" fill="#2196F3"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="46" height="55" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@ -2,7 +2,7 @@
<html lang="en">
<head>
<title>주정차 위반 의견진술 심사</title>
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<!-- Meta Tags-->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

@ -1,33 +0,0 @@
//----------------------------------------------------------------------------
// Board : 게시판 관리
//----------------------------------------------------------------------------
import axios from 'utils/axios';
import { GET_BOARD_LIST, REMOVE_BOARD, SAVE_BOARD, SAVE_BOARD_HIT_CNT, GET_BOARD_LIST2 } from 'commons/ApiUrl';
import { setRowId } from './common';
// eslint-disable-next-line import/prefer-default-export
export async function findBoards2(params) {
const res = await axios.get(GET_BOARD_LIST2, { params });
console.log(res);
if (res.success) {
res.data = res.data.map((d, idx) => ({ ...d, rowId: setRowId(params, idx) }));
return res;
}
return res;
}
export async function saveBoard(params) {
// eslint-disable-next-line no-return-await
return await axios.post(SAVE_BOARD, params);
}
export async function removeBoard(inCode) {
// eslint-disable-next-line no-return-await
return await axios.post(REMOVE_BOARD + inCode);
}
export async function modifyBoardHitCount(inCode) {
// eslint-disable-next-line no-return-await
return await axios.put(SAVE_BOARD_HIT_CNT + inCode);
}

@ -18,14 +18,22 @@ import {
GET_JUDGE_LIST,
SAVE_JUDGE_RESULT,
SAVE_ADMIN_JUDGE_STDS,
GET_DASHBOARD
GET_DASHBOARD,
SAVE_PARKING_JUDGE_RESULT,
GET_PARKING_FRECAD_IMAGE,
GET_PARKING_CONTAD_IMAGE,
GET_PARKING_PICAD_IMAGE,
GET_PARKING_JUDGE_FILE_DOWNLOAD,
SAVE_ADMIN_DATE_DATA
} from 'commons/ApiUrl';
import { setRowId } from './common';
import FileSaver from 'file-saver';
import _ from 'lodash';
export async function findDashboard() {
const res = await axios.get(GET_DASHBOARD);
// 23.04.06 sjh 통신 오래걸리는 작업이 있을 경우 적용
const configCustom = { timeout: 300000 };
export async function findDashboard(params) {
const res = await axios.get(GET_DASHBOARD, { params });
if (res.success) {
// res.data = res.data.map((d, idx) => ({ ...d, rowId: setRowId(params, idx) }));
return res;
@ -137,33 +145,33 @@ export async function removeJudge(params) {
return await axios.post(REMOVE_ADMIN_JUDGE, params);
}
export async function judgeFileDownload(params, alert) {
await axios
.get(GET_JUDGE_FILE_DOWNLOAD, {
responseType: 'blob',
params
})
// eslint-disable-next-line consistent-return
.then((res) => {
if (res?.isAxiosError || res?.status === 404 || res?.size <= 0) {
alert.show('파일을 다운로드 할 수 없습니다 [파일정보 오류]');
} else {
// eslint-disable-next-line no-lonely-if
if (res?.type.includes('image')) {
// const url = window.URL.createObjectURL(res);
alert.show(<img alt="~~~" src={URL.createObjectURL(res)} style={{ margin: 'auto' }} />);
// URL.revokeObjectURL()
} else {
FileSaver.saveAs(res, 'filename');
}
}
});
}
// export async function judgeFileDownload(params, alert) {
// await axios
// .get(GET_JUDGE_FILE_DOWNLOAD, {
// responseType: 'blob',
// params
// })
// // eslint-disable-next-line consistent-return
// .then((res) => {
// if (res?.isAxiosError || res?.status === 404 || res?.size <= 0) {
// alert.show('파일을 다운로드 할 수 없습니다 [파일정보 오류]');
// } else {
// // eslint-disable-next-line no-lonely-if
// if (res?.type.includes('image')) {
// // const url = window.URL.createObjectURL(res);
// alert.show('~~~~~');
// alert.show(<img alt="~~~" src={URL.createObjectURL(res)} style={{ margin: 'auto' }} />);
// // URL.revokeObjectURL()
// } else {
// FileSaver.saveAs(res, 'filename');
// }
// }
// });
// }
export async function saveJudgeStds(params) {
// eslint-disable-next-line no-return-await
return await axios.post(SAVE_ADMIN_JUDGE_STDS, params);
return await axios.post(SAVE_ADMIN_JUDGE_STDS, params, configCustom);
}
//----------------------------------------------------------------
@ -209,7 +217,7 @@ async function judgeImgList(res, scCode, fieldCnt, fieldName, dataGb, methodName
return arrRtn;
}
export async function findImages(row) {
export async function findJudgeImages(row) {
const dataGb = row?.msDatagb;
const scCode = row?.msMaincode;
@ -230,7 +238,64 @@ export async function findImages(row) {
return res;
}
async function parkingJudgeImgList(arrImgInfo) {
// console.log(arrImgInfo);
const arrRtn = [];
// eslint-disable-next-line no-restricted-syntax
for (const idx of _.range(1, arrImgInfo.length + 1, 1)) {
if (arrImgInfo[idx - 1].imgName) {
// eslint-disable-next-line no-await-in-loop
await axios
.get(GET_PARKING_JUDGE_FILE_DOWNLOAD, {
responseType: 'blob',
params: { absFileName: arrImgInfo[idx - 1].url }
})
// eslint-disable-next-line no-loop-func
.then((r) => {
if (r.size > 0) {
arrRtn.push({ imgName: arrImgInfo[idx - 1].imgName, url: URL.createObjectURL(r) });
} else {
arrRtn.push({ imgName: arrImgInfo[idx - 1].imgName, url: '/images/noFile.png' });
}
});
} else {
arrRtn.push({ imgName: '', url: '/images/noImage.png' });
}
}
return arrRtn;
}
export async function saveJudgeResult(params) {
// eslint-disable-next-line no-return-await
return await axios.post(SAVE_JUDGE_RESULT, params);
}
export async function findParkingImages(rcMaincode) {
const [frecadImgs, contadImgs, picadImgs] = await Promise.all([
await axios.get(GET_PARKING_FRECAD_IMAGE + rcMaincode),
await axios.get(GET_PARKING_CONTAD_IMAGE + rcMaincode),
await axios.get(GET_PARKING_PICAD_IMAGE + rcMaincode)
]);
const [frecads, contads, picads] = await Promise.all([
parkingJudgeImgList(frecadImgs?.data),
parkingJudgeImgList(contadImgs?.data),
parkingJudgeImgList(picadImgs?.data)
]);
return {
arrFrecadImg: frecads,
arrContadImg: contads,
arrPicadImg: picads
};
}
export async function saveParkingJudgeResult(params) {
// eslint-disable-next-line no-return-await
return await axios.post(SAVE_PARKING_JUDGE_RESULT, params);
}
export async function saveDateData(params) {
// eslint-disable-next-line no-return-await
return await axios.post(SAVE_ADMIN_DATE_DATA, params);
}

@ -12,6 +12,9 @@ import {
} from 'commons/ApiUrl';
import { setRowId } from './common';
// 23.04.06 sjh 통신 오래걸리는 작업이 있을 경우 적용
const configCustom = { timeout: 300000 };
// eslint-disable-next-line no-return-await
export async function findParkings(params) {
const res = await axios.get(GET_PARKING_LIST, { params });
@ -33,7 +36,7 @@ export async function findParkingJudgeTargets(params) {
export async function saveParkingJudgeTargets(params) {
// eslint-disable-next-line no-return-await
return await axios.post(SAVE_PARKING_JUDGE_TARGET_LIST, params);
return await axios.post(SAVE_PARKING_JUDGE_TARGET_LIST, params, configCustom);
}
export async function removeParkingJudge(params) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

@ -0,0 +1,43 @@
@media print {
.report + .report {
margin-top: 0;
}
}
@page {
size: A4;
margin: 20mm;
}
@page :first {margin:0 20mm}
.report {
//break-after: page;
margin-top: 20mm;
width: 100%;
border-style: double;
border-width: 2px;
border-color: #000000;
border-collapse: collapse;
color: #000000;
}
.report + .report {
margin-top: 40px;
}
.report th, td{
border: 1px solid #000000;
font-family: "??";
font-size:12px;
color: #525252;
}
.tit_text2 {
font-size:1.5em;
font-family: "??";
color:#666666;
text-decoration: none;
line-height: normal;
font-weight: bold;
}

@ -42,10 +42,18 @@ export const REMOVE_ADMIN_JUDGE = '/api/v2/ctgy/admin/remove';
export const SAVE_ADMIN_JUDGE_STDS = '/api/v2/ctgy/admin/judge';
export const SAVE_ADMIN_DATE_DATA = '/api/v2/ctgy/admin/date';
export const GET_JUDGE_LIST = '/api/v2/ctgy/judge';
export const SAVE_JUDGE_RESULT = '/api/v2/ctgy/judge';
export const GET_PARKING_IMAGE2 = '/api/v2/ctgy/parking/judge2/';
export const GET_PARKING_PICAD_IMAGE = '/api/v2/ctgy/parking/judge/picad/';
export const GET_PARKING_FRECAD_IMAGE = '/api/v2/ctgy/parking/judge/frecad/';
export const GET_PARKING_CONTAD_IMAGE = '/api/v2/ctgy/parking/judge/contad/';
export const SAVE_PARKING_JUDGE_RESULT = '/api/v2/ctgy/parking/judge';
export const GET_JUDGE_FILE_DOWNLOAD = '/api/v2/ctgy/cmm/download/judge';
export const GET_PARKING_JUDGE_FILE_DOWNLOAD = '/api/v2/ctgy/cmm/download/park';
// 사용자 관리
export const GET_USER_LIST = '/api/v2/ctgy/user';

@ -173,6 +173,10 @@ export const removeAlert = (confirmProcess, dismissProcess) => {
confirmAlert('삭제 하시겠습니까?', confirmProcess, dismissProcess);
};
export const updateAlert = (confirmProcess, dismissProcess) => {
confirmAlert('변경 하시겠습니까?', confirmProcess, dismissProcess);
};
export const Toast = swal.mixin({
toast: true,
backdrop: true,

@ -29,8 +29,8 @@ const verifyToken = (accessToken) => {
return false;
}
const decoded = jwtDecode(accessToken);
console.log(decoded);
console.log(decoded.exp > Date.now() / 1000);
// console.log(decoded);
// console.log(decoded.exp > Date.now() / 1000);
/**
* Property 'exp' does not exist on type '<T = unknown>(token, options?: JwtDecodeOptions | undefined) => T'.
@ -63,8 +63,7 @@ export const JWTProvider = ({ children }) => {
if (accessToken && verifyToken(accessToken)) {
setLocalStorage(ACCESS_TOKEN_NAME, accessToken);
const response = await axios.get('/api/v2/ctgy/user/info');
console.log(response);
// TODO : 적용 필요
// console.log(response);
const { userid, email, name, accesstype } = response.data;
dispatch({
type: LOGIN,
@ -99,7 +98,7 @@ export const JWTProvider = ({ children }) => {
// console.log(response);
if (response && response.data) {
const { accessToken, refreshToken, user } = response.data;
console.log(user);
// console.log(user);
setLocalStorage(ACCESS_TOKEN_NAME, accessToken);
if (refreshToken) setLocalStorage(REFRESH_TOKEN_NAME, refreshToken);

@ -1,11 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
// third party
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { PersistGate } from 'redux-persist/integration/react';
import { transitions, positions, Provider as AlertProvider, types } from 'react-alert';
@ -21,7 +18,6 @@ import { ConfigProvider } from 'contexts/ConfigContext';
// style + assets
import 'assets/scss/style.scss';
import axios from 'axios';
// ==============================|| REACT DOM RENDER ||============================== //
@ -37,33 +33,9 @@ const options = {
}
};
const queryClient = new QueryClient({
mutationCache: new MutationCache({
onError: (error) => {
if (axios.isAxiosError(error)) {
const errorCode = error.response?.data.code;
console.log(`###################@@@@@@@@@@@@@@${errorCode}`); // 에러 팝업 띄우기
} else {
throw error; // error boundary로 전달
}
}
}),
queryCache: new QueryCache({
onError: (error) => {
if (axios.isAxiosError(error)) {
const errorCode = error.response?.data.code;
console.log(`###################@@@@@@@@@@@@@@${errorCode}`); // 에러 팝업 띄우기
} else {
throw error; // error boundary로 전달
}
}
})
});
ReactDOM.render(
// <React.StrictMode>
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<PersistGate loading={null} persistor={persister}>
<ConfigProvider>
<BrowserRouter basename={BASE_PATH}>
@ -75,10 +47,6 @@ ReactDOM.render(
</BrowserRouter>
</ConfigProvider>
</PersistGate>
{/* //TODO : 개발완료시 교체 */}
<ReactQueryDevtools initialIsOpen />
{/* <ReactQueryDevtools initialIsOpen={process.env.NODE_ENV !== 'production'} /> */}
</QueryClientProvider>
</Provider>,
// </React.StrictMode>,
document.getElementById('root')

@ -35,7 +35,7 @@ const ProfileSection = () => {
const theme = useTheme();
const { borderRadius } = useConfig();
const [selectedIndex, setSelectedIndex] = useState(-1);
const [selectedIndex] = useState(-1);
const { logout, user } = useAuth();
const [open, setOpen] = useState(false);
/**

@ -1,6 +1,6 @@
// material-ui
import { useTheme } from '@mui/material/styles';
import { Avatar, Box, Link } from '@mui/material';
import { Avatar, Box } from '@mui/material';
// project imports
import LogoSection from '../LogoSection';

@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
// material-ui
import { useTheme } from '@mui/material/styles';
import { Divider, List, Typography } from '@mui/material';
import { List, Typography } from '@mui/material';
// project imports
import NavItem from '../NavItem';

@ -6,7 +6,6 @@ import Loadable from 'ui-component/Loadable';
import AuthGuard from 'utils/route-guard/AuthGuard';
// sample page routing
const SamplePage = Loadable(lazy(() => import('views/sample-page')));
const Dashboard = Loadable(lazy(() => import('views/dashboard')));
// admin page routing
@ -26,9 +25,6 @@ const UserByJudgeReview = Loadable(lazy(() => import('views/biz/judge/JudgeByUse
// user
const UserManager = Loadable(lazy(() => import('views/biz/user/UserManager')));
// component
const ModalForm = Loadable(lazy(() => import('views/form/Modal')));
// ==============================|| MAIN ROUTING ||============================== //
const MainRoutes = {
@ -113,15 +109,6 @@ const MainRoutes = {
{
path: '/judge/disabled/review',
element: <UserByJudgeReview msDatagb="2" menuName="장애인" />
},
{
path: '/sample-page',
element: <SamplePage />
},
{
path: '/modalForm',
element: <ModalForm />
}
]
};

@ -1,10 +1,6 @@
// third-party
import { createSlice } from '@reduxjs/toolkit';
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
// ----------------------------------------------------------------------
const initialState = {

@ -9,64 +9,14 @@ import { useTheme } from '@mui/material/styles';
*
*/
import Llogo from '../assets/images/logo/lightLogoNew.png';
import Dlogo from '../assets/images/logo/darkLogoNew.png';
import Llogo from '../assets/images/logo/lightLogo.png';
import Dlogo from '../assets/images/logo/darkLogo.png';
// ==============================|| LOGO SVG ||============================== //
const Logo = () => {
const theme = useTheme();
return (
/**
* if you want to use image instead of svg uncomment following, and comment out <svg> element.
*
* <img src={theme.palette.mode === 'dark' ? logoDark : logo} alt="Berry" width="100" />
*
*/
<img src={theme.palette.mode === 'dark' ? Dlogo : Llogo} alt="Berry" width="100" />
// <svg width="92" height="32" viewBox="0 0 92 32" fill="none" xmlns="http://www.w3.org/2000/svg">
// <path
// d="M33.085 26.4841V12.3839H37.9541C39.6408 12.3839 40.9202 12.7131 41.7922 13.3717C42.6642 14.0237 43.1002 14.9825 43.1002 16.2478C43.1002 16.9387 42.9251 17.5488 42.5751 18.0782C42.225 18.6011 41.7381 18.9853 41.1143 19.2306C41.8272 19.4114 42.3873 19.7761 42.7947 20.3249C43.2084 20.8737 43.4152 21.5452 43.4152 22.3392C43.4152 23.695 42.9888 24.7215 42.1359 25.4188C41.283 26.1161 40.0673 26.4712 38.4888 26.4841H33.085ZM35.9492 20.3443V24.1502H38.4028C39.0775 24.1502 39.6026 23.9888 39.9781 23.666C40.36 23.3367 40.551 22.8848 40.551 22.3102C40.551 21.0189 39.8922 20.3637 38.5747 20.3443H35.9492ZM35.9492 18.2912H38.0687C39.5135 18.2654 40.236 17.6811 40.236 16.5384C40.236 15.8992 40.0514 15.4408 39.6822 15.1632C39.3194 14.8792 38.7434 14.7371 37.9541 14.7371H35.9492V18.2912ZM53.9365 20.3733H48.4371V24.1502H54.8913V26.4841H45.573V12.3839H54.8723V14.7371H48.4371V18.0976H53.9365V20.3733ZM61.7175 21.3224H59.436V26.4841H56.5717V12.3839H61.7365C63.379 12.3839 64.6455 12.7551 65.5365 13.4975C66.4276 14.24 66.8734 15.2891 66.8734 16.6449C66.8734 17.6069 66.6661 18.4107 66.2527 19.0563C65.8455 19.6954 65.2248 20.2055 64.3907 20.5864L67.3985 26.3485V26.4841H64.3242L61.7175 21.3224ZM59.436 18.9691H61.746C62.4656 18.9691 63.0226 18.7851 63.417 18.4172C63.8114 18.0427 64.0092 17.5294 64.0092 16.8773C64.0092 16.2124 63.8214 15.6894 63.4455 15.3085C63.0768 14.9276 62.5069 14.7371 61.7365 14.7371H59.436V18.9691ZM74.2058 21.3224H71.9237V26.4841H69.0594V12.3839H74.2248C75.8667 12.3839 77.1337 12.7551 78.0248 13.4975C78.9159 14.24 79.3611 15.2891 79.3611 16.6449C79.3611 17.6069 79.1544 18.4107 78.7404 19.0563C78.3332 19.6954 77.7125 20.2055 76.879 20.5864L79.8863 26.3485V26.4841H76.8119L74.2058 21.3224ZM71.9237 18.9691H74.2343C74.9533 18.9691 75.5103 18.7851 75.9052 18.4172C76.2997 18.0427 76.4969 17.5294 76.4969 16.8773C76.4969 16.2124 76.3092 15.6894 75.9337 15.3085C75.5645 14.9276 74.9946 14.7371 74.2248 14.7371H71.9237V18.9691ZM85.8823 18.7367L88.7751 12.3839H91.9064L87.3427 21.3708V26.4841H84.4309V21.3708L79.8673 12.3839H83.008L85.8823 18.7367Z"
// fill={theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.grey[900]}
// />
// <path
// d="M10.987 31.5841C4.92849 31.5841 0 26.626 0 20.5323C0 14.4385 4.92899 9.48041 10.987 9.48041C17.045 9.48041 21.974 14.4385 21.974 20.5323C21.974 26.626 17.0459 31.5841 10.987 31.5841ZM10.987 10.536C5.50765 10.536 1.04938 15.0196 1.04938 20.5318C1.04938 26.044 5.50765 30.5275 10.987 30.5275C16.4663 30.5275 20.9251 26.0429 20.9251 20.5308C20.9251 15.0186 16.4673 10.536 10.987 10.536Z"
// fill={theme.palette.primary.main}
// />
// <path
// d="M18.96 21.0225C18.6182 19.7483 15.4851 19.6108 13.6203 20.0779C12.6437 20.3235 11.6456 20.6428 10.6162 20.8265C11.3697 21.4989 12.1788 22.135 13.34 22.2932C16.2211 22.6842 18.0112 21.775 18.96 21.0225Z"
// fill={theme.palette.primary.main}
// />
// <path
// d="M13.34 22.2932C12.1764 22.135 11.3697 21.4989 10.6162 20.8265C9.45013 19.7857 8.41298 18.6579 6.37723 19.0823C3.14069 19.7572 2.71488 23.6081 5.21404 26.0828C6.28706 27.2131 7.66455 28.0041 9.17779 28.3586C10.691 28.7132 12.2742 28.616 13.7333 28.079C15.1924 27.5419 16.4641 26.5883 17.3925 25.3352C18.3209 24.0819 18.8656 22.5835 18.96 21.0235C18.0112 21.775 16.221 22.6842 13.34 22.2932Z"
// fill={theme.palette.secondary.main}
// />
// <path
// d="M15.034 13.9586C14.6301 14.8295 18.2304 15.7957 18.6611 18.6879C18.8687 15.8409 15.5335 12.882 15.034 13.9586Z"
// fill={theme.palette.primary.main}
// />
// <path
// d="M7.46619 17.5935C8.11524 17.3231 8.42345 16.5746 8.15463 15.9217C7.8858 15.2688 7.14167 14.9587 6.49262 15.2292C5.84357 15.4996 5.53536 16.2481 5.80418 16.9011C6.07306 17.5539 6.81714 17.8639 7.46619 17.5935Z"
// fill={theme.palette.secondary.main}
// />
// <path
// d="M10.3549 14.08C10.6585 13.7746 10.6585 13.2795 10.3549 12.9741C10.0513 12.6687 9.55909 12.6687 9.25551 12.9741C8.95194 13.2795 8.95194 13.7746 9.25551 14.08C9.55909 14.3854 10.0513 14.3854 10.3549 14.08Z"
// fill={theme.palette.primary.main}
// />
// <path
// d="M13.1014 9.05206C14.2245 5.7149 13.4696 3.04871 11.1614 1.78241C9.58359 2.10513 8.647 2.87335 8.12549 3.93383C11.2204 3.68185 13.1844 5.63041 13.1014 9.05206Z"
// fill={theme.palette.primary.main}
// />
// <path
// d="M25.6983 6.13641C20.1389 4.1294 16.6304 4.81756 16.0786 9.39055C19.2648 12.6973 22.474 11.1146 25.6983 6.13641Z"
// fill={theme.palette.primary.main}
// />
// <path
// d="M21.2765 4.32541C21.5343 3.21728 21.6681 1.90776 21.6881 0.41748C15.9226 1.70883 13.3224 4.17658 15.2839 8.33846C15.3816 8.36203 15.4754 8.38119 15.5696 8.40085C16.0281 5.14422 18.0463 3.93835 21.2765 4.32541Z"
// fill={theme.palette.primary.main}
// />
// </svg>
);
return <img src={theme.palette.mode === 'dark' ? Dlogo : Llogo} alt="Berry" width="100" />;
};
export default Logo;

@ -7,8 +7,8 @@ import Swal from 'sweetalert2';
const axiosService = axios.create({
// baseURL: process.env.NODE_ENV === 'development' ? process.env.REACT_APP_API_URL : '',
baseURL: process.env.REACT_APP_API_URL,
withCredentials: process.env.NODE_ENV !== 'production', // 개발시만 사용 : crossdomain
// baseURL: process.env.REACT_APP_API_URL,
withCredentials: true, // 개발시만 사용 : crossdomain
timeout: Number(process.env.REACT_APP_SERVER_TIMEOUT),
headers: {
'Content-Type': 'application/json'

@ -1,4 +1,5 @@
import { useState } from 'react';
import { useState, useRef } from 'react';
import ReactToPrint, { useReactToPrint } from 'react-to-print';
import _ from 'lodash';
import PropTypes from 'prop-types';
@ -6,12 +7,13 @@ import NumberFormat from 'react-number-format';
import { Grid, TextField, MenuItem, Select, FormControl, InputLabel, Divider } from '@mui/material';
import Button from '@mui/material/Button';
import { Delete, List } from '@mui/icons-material';
import { List, Print, Delete } from '@mui/icons-material';
import { judgeImgDownload } from 'apis/judge';
import ImageFileViewForm from 'views/cmm/file-ctl/ImageFileViewForm';
import CmmImgViewModal from 'views/cmm/CmmImgViewModal';
import { removeAlert } from 'commons/XitCmm';
import JudgeDataPrintForm from './JudgeDataPrintForm';
const ModifyJudgeDataForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSave, onModify, setDetail }) => {
const [selectedContDoc, setSelectedContDoc] = useState(rowData?.scContDoc);
@ -50,6 +52,8 @@ const ModifyJudgeDataForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
setImgName(fileName);
};
const ref = useRef();
return (
<>
<Grid mt={1}>
@ -61,7 +65,7 @@ const ModifyJudgeDataForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
<TextField disabled size="small" required label="전송상태" fullWidth value={rowData?.scTransferNm} />
</Grid>
<Grid item xs={3}>
<TextField disabled size="small" required label="자료상태" fullWidth value={rowData?.scStateNm} />
<TextField disabled size="small" required label="자료상태" fullWidth value={rowData.scStateNm} />
</Grid>
<Grid item xs={3}>
<TextField disabled required label="차량번호" size="small" fullWidth value={rowData?.scCarnum} autoFocus />
@ -218,6 +222,13 @@ const ModifyJudgeDataForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
))}
</Grid>
</Grid>
{(rowData?.scState === '3' || rowData?.scState === '4') && (
<Grid container mt={1}>
<Grid item xs={12}>
<TextField disabled required label="답변내용" size="small" fullWidth value={rowData?.scAnswer} />
</Grid>
</Grid>
)}
<Grid container mt={1}>
<Grid item xs={12}>
<Divider />
@ -229,13 +240,26 @@ const ModifyJudgeDataForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
목록
</Button>
</Grid>
<Grid item>
<ReactToPrint
trigger={() => (
<Button variant="contained" size="small" startIcon={<Print />}>
인쇄
</Button>
)}
content={() => ref.current}
/>
<div style={{ display: 'none' }}>
<JudgeDataPrintForm ref={ref} content={rowData} />
</div>
</Grid>
<Grid item style={{ marginLeft: 'auto' }}>
<Button variant="contained" color="primary" size="small" onClick={onModify}>
변경하기
</Button>
</Grid>
<Grid item>
<Button variant="contained" size="small" startIcon={<Delete />} onClick={onRemove}>
<Button variant="contained" size="small" color="error" startIcon={<Delete />} onClick={onRemove}>
삭제
</Button>
</Grid>

@ -29,6 +29,7 @@ const JudgeDataModifyForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
const [scCdate, setScCdate] = useState(rowData?.scCdate);
const [scJbtime, setScJbtime] = useState(rowData?.scJbtime);
const [scPos, setScPos] = useState(rowData?.scPos ?? '');
const [scAnswer, setScAnswer] = useState(rowData?.scAnswer);
const [picads, setPicads] = useState({});
const [frecads, setFrecads] = useState({});
@ -55,6 +56,7 @@ const JudgeDataModifyForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
formData.append('zipcode2', zipcode1 ? zipcode1.substring(3) : '');
formData.append('scJuso', scJuso || '');
formData.append('scBunji', scBunji || '');
formData.append('scAnswer', scAnswer || '');
Object.values(picads).forEach((v) => {
formData.append('picadFiles', v);
@ -414,6 +416,20 @@ const JudgeDataModifyForm = ({ rowData, contDocs, ingbs, setOpen, handleModalSav
))}
</Grid>
</Grid>
{(rowData?.scState === '3' || rowData?.scState === '4') && (
<Grid container mt={1}>
<Grid item xs={12}>
<TextField
size="small"
required
label="답변내용"
fullWidth
value={scAnswer || ''}
onChange={(e) => setScAnswer(e?.target?.value)}
/>
</Grid>
</Grid>
)}
<Grid container spacing={1} mt={1}>
<Grid item xs={12}>
<Divider />

@ -340,6 +340,7 @@ const JudgeDataNewForm = ({ scDatagb, contDocs, ingbs, handleModalSave, setOpen,
<Grid container spacing={1} mt={1}>
<Grid item xs={12}>
<Divider />
모든 첨부파일 용량을 더해서 용량이 200MB를 넘지 않아야 합니다. 초과할 경우 저장 오류가 발생할 있습니다.
</Grid>
</Grid>
<Grid container spacing={0.5} mt={1}>

@ -0,0 +1,178 @@
import { forwardRef } from 'react';
import 'assets/scss/print.scss';
import NumberFormat from 'react-number-format';
import format from 'date-fns/format';
const toDate = new Date();
// eslint-disable-next-line
const JudgeDataPrintForm = forwardRef((props, ref) => {
return (
<table ref={ref} className="report">
<tr>
<td colSpan="5" align="center" className="tit_text2" height="50">
{props.content.scDatagb === '1' && '부정주차 이의신청'}
{props.content.scDatagb === '2' && '장애인주차구역 위반 의견진술'}
&nbsp;처리결과 통지서
</td>
</tr>
<tr>
<td rowSpan="2" align="center" width="50">
{props.content.scDatagb === '1' && <b>신청인</b>}
{props.content.scDatagb === '2' && (
<b>
&nbsp;&nbsp;&nbsp;
<br />
진술인
</b>
)}
</td>
<td align="center" height="40" width="50">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td colSpan="3" width="480">
{props.content.scName}
</td>
</tr>
<tr>
<td align="center" height="40" width="50">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td colSpan="3">
{props.content.scJuso}&nbsp;{props.content.scBunji}
</td>
</tr>
<tr>
<td colSpan="2" align="center" height="40" width="100">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td align="center" width="120">
{props.content.scSeq}
</td>
<td align="center" width="100">
<b>차량등록번호</b>
</td>
<td width="260">{props.content.scCarnum}</td>
</tr>
<tr>
<td colSpan="2" align="center" height="40" width="100">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td align="center" width="120">
<NumberFormat format="####-##-##" value={props.content.scWdate} displayType="text" />
&nbsp;
<NumberFormat format="##:##" value={props.content.scJbtime} displayType="text" />
</td>
<td align="center" width="100">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td width="260">
{props.content.scDatagb === '1' && '거주자우선주차장 내 부정주차'}
{props.content.scDatagb === '2' && '장애인전용주차 구역내 일반차량 주차'}
</td>
</tr>
<tr>
<td colSpan="2" align="center" height="40" width="100">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td colSpan="3">
{props.content.scDong}&nbsp;{props.content.scPos}
</td>
</tr>
<tr>
<td colSpan="2" align="center" height="40" width="100">
<b>&nbsp;&nbsp;&nbsp;</b>
</td>
<td colSpan="3">
<br />
<br />
<span className="tit_text2">({props.content.scStateNm})</span>
<br />
답변
<br />
{props.content.scAnswer}
{props.content.scDatagb === '1' && props.content.scState === '4' && (
<div>
<br />
<b>부정주차 단속 주차요금 부과 근거</b>
<br /> 주차장법 제8조의 2 제9조
<br /> 서울특별시 강남구 주차장 설치 관리조례 제6조
</div>
)}
<br />
<br />
</td>
</tr>
<tr>
{props.content.scDatagb === '1' && (
<td colSpan="5">
<b>
<br />
<br />
&nbsp;&nbsp; 거주자우선주차장 부정주차 단속에 대하여 제출하신 이의 신청 건을 심의한 결과 위와 같이 결정되었음을
통보합니다.
<br />
<br />
<br />
<br />
<br />
<br />
<br />
&nbsp;&nbsp; 기타문의안내 : ARS 1544-2113
<br />
<br />
<br />
</b>
</td>
)}
{props.content.scDatagb === '2' && (
<td colSpan="5">
<b>
<br />
<br />
&nbsp;&nbsp; 장애인주차구역내 일반차량 주차와 관련하여 제출하신 의견진술에 대하여 심의위원회에서 장애인, 노인, 임산부 등의
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;편의 증진 보장에 관한 법률 17 제3항 제27조 제2항에 의거하여 장애인 전용 주차구역
위반 내용을 심의 결과
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;위와 같이 결정되었음을 통보합니다.
<br />
<br />
&nbsp;&nbsp; 심의결과에 이의가 있으시면 이의신청서를 작성하여 제출하시면 단속자료와 함께 관할 법원으로 통보하여 비송사건
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;절차법에 의한 과태료재판을 받으실 있습니다.
<br />
<br />
<br />
&nbsp;&nbsp; : 과태료부과 고지서 받은 60 이내
<br />
&nbsp;&nbsp; : 구청직접방문, 팩스, 인터넷
<br />
&nbsp;&nbsp; : 이의신청서, 과태료고지서, 증빙서류 첨부가능
<br />
&nbsp;&nbsp; 기타문의안내 : TEL 02)3423-6448, &nbsp;&nbsp;FAX : 02)3423-8868
<br />
<br />
<br />
</b>
</td>
)}
</tr>
<tr>
<td colSpan="5" align="center" height="90">
<b>{format(toDate, 'yyyy년 MM월 dd일')}</b>
<br />
<br />
<span className="tit_text2">
{props.content.scDatagb === '1' && '강남구청 대행 강남구도시관리공단'}
{props.content.scDatagb === '2' && '서 울 특 별 시 강 남 구 도 시 관 리 공 단'}
</span>
{props.content.scDatagb === '1' && '(직인생략)'}
</td>
</tr>
</table>
);
});
export default JudgeDataPrintForm;

@ -16,12 +16,12 @@ import JudgeDataDetailForm from './JudgeDataDetailForm';
import { useAlert } from 'react-alert';
import { getComboCodeList } from 'apis/common';
import JudgeDataModifyForm from './JudgeDataModifyForm';
import { useQuery } from 'react-query';
const JudgeDataReview = ({ scDatagb, menuName }) => {
const showAlert = useAlert();
const [scContDocs, setScContDocs] = useState([]);
const [scIngbs, setScIngbs] = useState([]);
const [scStates, setScStates] = useState([]);
const [newOpen, setNewOpen] = useState(false);
const [dtlOpen, setDtlOpen] = useState(false);
@ -97,13 +97,16 @@ const JudgeDataReview = ({ scDatagb, menuName }) => {
}, [search]);
useEffect(() => {
console.log('~~~~~~~~~~~');
// console.log('~~~~~~~~~~~');
getComboCodeList({ codeMcd: 'SC_CONT_DOC' }).then((res) => {
setScContDocs(res.data);
});
getComboCodeList({ codeMcd: 'RC_INGB' }).then((res) => {
setScIngbs(res.data);
});
getComboCodeList({ codeMcd: 'SC_STATE' }).then((res) => {
setScStates(res.data);
});
}, []);
const handleCreate = () => {
@ -194,6 +197,7 @@ const JudgeDataReview = ({ scDatagb, menuName }) => {
scDatagb={scDatagb}
contDocs={scContDocs}
ingbs={scIngbs}
states={scStates}
setOpen={setNewOpen}
setCreate={setCreate}
/>
@ -205,6 +209,7 @@ const JudgeDataReview = ({ scDatagb, menuName }) => {
rowData={rowData}
contDocs={scContDocs}
ingbs={scIngbs}
states={scStates}
setDetail={setDetail}
handleModalSave={handleJudgeData}
onModify={openModify}
@ -218,6 +223,7 @@ const JudgeDataReview = ({ scDatagb, menuName }) => {
rowData={rowData}
contDocs={scContDocs}
ingbs={scIngbs}
states={scStates}
setModify={setModify}
handleModalSave={handleJudgeData}
onModify={openModify}

@ -0,0 +1,137 @@
import { useState } from 'react';
import PropTypes from 'prop-types';
import { useAlert } from 'react-alert';
import { Grid, TextField } from '@mui/material';
import Button from '@mui/material/Button';
import { saveAlert } from 'commons/XitCmm';
import { MuiXDatePicker, MuiXMobileTimePicker } from 'views/cmm/MuiXDatePicker';
import format from 'date-fns/format';
const toDate = new Date();
const JudgeDateModifyForm = ({ dateDatas, setDateModify, handleModalSave }) => {
const alert = useAlert();
const [msDatagb, setMsDatagb] = useState(dateDatas?.msDatagb);
const [msYear, setMsYear] = useState(dateDatas?.msYear);
const [msChasu, setMsChasu] = useState(dateDatas?.msChasu);
const [msSdate, setMsSdate] = useState(dateDatas?.msSdate);
const [msStartsi, setMsStartsi] = useState(dateDatas?.msStartsi);
const [msEdate, setMsEdate] = useState(dateDatas?.msEdate);
const [msCdate, setMsCdate] = useState(dateDatas?.msCdate);
const [msClosesi, setMsClosesi] = useState(dateDatas?.msClosesi);
const onSave = () => {
// TODO : validation check
const param = {
msDatagb,
msYear,
msChasu,
msSdate,
msStartsi,
msEdate,
msCdate,
msClosesi
};
//
if (msSdate.length < 8) {
alert.show('심사 시작일자는 필수입니다.');
return;
}
if (msEdate.length < 8) {
alert.show('심사 종료일자는 필수입니다.');
return;
}
if (msCdate.length < 8) {
alert.show('심사 마감일자는 필수입니다.');
return;
}
if (msStartsi.length === 1) {
setMsStartsi(`0${msStartsi}`);
}
if (msStartsi.length < 2) {
alert.show('심사 시작시간은 필수입니다.');
return;
}
if (msClosesi.length < 2) {
alert.show('심사 마감시간은 필수입니다.');
return;
}
if (msEdate.replace(/-/g, '') > msCdate.replace(/-/g, '')) {
alert.show('심사 종료일자가 심사 마감일자보다 클 수 없습니다.');
return;
}
setDateModify(false);
saveAlert(
() => {
handleModalSave('SAVE', param);
},
() => {
setDateModify(true);
}
);
};
const onCancel = () => {
setDateModify(false);
};
return (
<>
<Grid mt={2}>
<Grid container spacing={0.5} mb={1.5}>
<Grid item xs={6}>
<TextField disabled required label="심의 년도" size="small" fullWidth value={msYear} autoFocus />
</Grid>
<Grid item xs={6}>
<TextField disabled required label="심의 차수" size="small" fullWidth value={msChasu} autoFocus />
</Grid>
</Grid>
<Grid container spacing={0.5} mb={1.5}>
<Grid item xs={6}>
<MuiXDatePicker label="심사 시작일자" date={msSdate} setDate={setMsSdate} />
</Grid>
<Grid item xs={6}>
<MuiXMobileTimePicker label="심사 시작시간" date={`${format(toDate, 'yyyy-MM-dd')} ${msStartsi}:00`} setDate={setMsStartsi} />
</Grid>
</Grid>
<Grid container spacing={0.5} mb={1.5}>
<Grid item xs={6}>
<MuiXDatePicker label="심사 종료일자" date={msEdate} setDate={setMsEdate} />
</Grid>
<Grid item xs={6} />
</Grid>
<Grid container spacing={0.5} mb={1.5}>
<Grid item xs={6}>
<MuiXDatePicker label="심사 마감일자" date={msCdate} setDate={setMsCdate} />
</Grid>
<Grid item xs={6}>
<MuiXMobileTimePicker label="심사 마감시간" date={`${format(toDate, 'yyyy-MM-dd')} ${msClosesi}:00`} setDate={setMsClosesi} />
</Grid>
</Grid>
</Grid>
<Grid item container spacing={0.5} xs={12} mt={1}>
<Grid item>
<Button variant="contained" color="error" size="small" onClick={onCancel}>
취소
</Button>
</Grid>
<Grid item style={{ marginLeft: 'auto' }}>
<Button variant="contained" color="primary" size="small" onClick={onSave}>
저장
</Button>
</Grid>
</Grid>
</>
);
};
JudgeDateModifyForm.propTypes = {
dateDatas: PropTypes.object.isRequired,
handleModalSave: PropTypes.func.isRequired,
setDateModify: PropTypes.func.isRequired
};
export default JudgeDateModifyForm;

@ -9,6 +9,7 @@ import Button from '@mui/material/Button';
import combo from 'commons/combo_data';
import { useState } from 'react';
import { saveJudgeStds } from 'apis/judge';
import Loading from 'views/cmm/Loding';
const style = {
position: 'relative',
@ -25,12 +26,14 @@ const style = {
const CmmModal = ({ isBackdrop = false, open, setOpen, title, judgeData = () => {}, dataGb, showAlert, callback }) => {
const [judgeStd, setJudgeStd] = useState('1');
const [loading, setLoading] = useState(false);
const handleClose = () => {
setOpen(false);
};
const handleJudge = () => {
if (window.confirm(`${judgeStd}명[부과] 기준으로 ${judgeData.length}건 심사 처리 하시겠습니까?`)) {
setLoading(true);
const param = {
dataGb,
judgeStdCnt: judgeStd,
@ -38,6 +41,7 @@ const CmmModal = ({ isBackdrop = false, open, setOpen, title, judgeData = () =>
};
saveJudgeStds(param).then((res) => {
setLoading(false);
if (res?.success) {
showAlert.show(`${judgeData.length}건 처리되었습니다`);
setOpen(false);
@ -87,6 +91,7 @@ const CmmModal = ({ isBackdrop = false, open, setOpen, title, judgeData = () =>
</Button>
</Grid>
</Grid>
{loading && <Loading />}
</MainCard>
</Modal>
</div>

@ -17,19 +17,33 @@ import xitCmm, { ErrorToast, saveAlert } from 'commons/XitCmm';
import CmmModal from 'views/cmm/CmmModal';
import JudgeTargetSaveForm from 'views/biz/admin/judge/JudgeTargetSaveForm';
import NumberFormat from 'react-number-format';
import ExcelDownload from 'views/cmm/file-ctl/ExcelDownload';
import ExcelDownloadGrid from 'views/cmm/file-ctl/ExcelDownloadGrid';
import { findJudgeTargets, saveJudgeTargets } from 'apis/judge';
import PropTypes from 'prop-types';
import getYear from 'date-fns/getYear';
import { useAlert } from 'react-alert';
import CmmModalStyle from 'views/cmm/CmmModalStyle';
const year = getYear(new Date());
const year = getYear(new Date()).toString();
const style = {
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 500,
minHeight: 300,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 3
};
const JudgeRegistReview = ({ scDatagb, menuName }) => {
const showAlert = useAlert();
const [scTransfer, setScTransfer] = useState('1');
const [scSeq1, setScSeq1] = useState(year);
const [scSeq2, setScSeq2] = useState(year);
const [scSeq1, setScSeq1] = useState(`${year}000001`);
const [scSeq2, setScSeq2] = useState(`${year}999999`);
const [selectionModel, setSelectionModel] = useState([]);
const [totalCount, setTotalCount] = useState(0);
const [rowsState, setRowsState] = useState({
@ -61,6 +75,14 @@ const JudgeRegistReview = ({ scDatagb, menuName }) => {
];
const search = () => {
if (scSeq1.length < 10 || scSeq2.length < 10) {
showAlert.show('접수번호를 10자리로 입력해 주세요[ex:2022000001]');
return;
}
if (scSeq1 > scSeq2) {
showAlert.show('접수번호 조건을 확인해 주세요');
return;
}
const params = {
scDatagb, //
scTransfer,
@ -114,9 +136,7 @@ const JudgeRegistReview = ({ scDatagb, menuName }) => {
};
const handleSearch = () => {
if (scSeq1 && scSeq2) {
search();
}
};
const handleOnKeyDown = (event) => {
@ -198,7 +218,7 @@ const JudgeRegistReview = ({ scDatagb, menuName }) => {
</Button>
</Grid>
<Grid item>
<ExcelDownload
<ExcelDownloadGrid
fileName={`${menuName} 의견진술 심의목록`}
gridColumns={columns}
excelDatas={rowsState.rows}
@ -225,9 +245,10 @@ const JudgeRegistReview = ({ scDatagb, menuName }) => {
handleSelection={handleSelection}
selectionModel={selectionModel}
/>
<CmmModal isBackdrop title={title} open={open} setOpen={setOpen}>
{/* <CmmModal isBackdrop title={title} open={open} setOpen={setOpen}> */}
<CmmModalStyle isBackdrop title={title} open={open} setOpen={setOpen} style={style}>
<JudgeTargetSaveForm isDisabled={selectionModel.length === 0} handleModalSave={submitJudgeTargets} />
</CmmModal>
</CmmModalStyle>
</MainCard>
);
};

@ -16,12 +16,27 @@ import MainCard from 'ui-component/cards/MainCard';
// project imports
import MuiDataGrid from 'views/cmm/mui-grid/MuiDataGrid';
import InputLabel from 'ui-component/extended/Form/InputLabel';
import { findJudgeResults, findJudges, removeJudge } from 'apis/judge';
import { findJudgeResults, findJudges, removeJudge, saveDateData } from 'apis/judge';
import CmmModal from 'views/cmm/CmmModal';
import ModalJudgeResult from './ModalJudgeResult';
import { findParkings, removeParkingJudge } from '../../../../apis/parking';
import { useAlert } from 'react-alert';
import { removeAlert } from '../../../../commons/XitCmm';
import JudgeDateModifyForm from './JudgeDateModifyForm';
import CmmModalStyle from 'views/cmm/CmmModalStyle';
const style = {
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 500,
minHeight: 300,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 3
};
const year = getYear(new Date());
const years = _.range(year, year - 14, -1);
@ -30,6 +45,7 @@ const JudgeReview = ({ msDatagb, menuName }) => {
const showAlert = useAlert();
const [open, setOpen] = useState(false);
const [dateModify, setDateModify] = useState(false);
const [title, setTitle] = useState();
const [selectedYear, setSelectedYear] = useState(year);
@ -52,6 +68,16 @@ const JudgeReview = ({ msDatagb, menuName }) => {
judgeTeam: ''
});
const [judgeDatas, setJudgeDatas] = useState([]);
const [dateDatas, setDateDatas] = useState({
msDatagb: '',
msYear: '',
msChas: '',
msSdate: '',
msStartsi: '',
msEdate: '',
msCdate: '',
msClosesi: ''
});
const search = useCallback(
async (datagb) => {
@ -88,7 +114,7 @@ const JudgeReview = ({ msDatagb, menuName }) => {
} else {
res = await removeParkingJudge(row);
}
console.log(res);
// console.log(res);
if (res && res.success) {
setRowsState({
...rowsState,
@ -103,6 +129,21 @@ const JudgeReview = ({ msDatagb, menuName }) => {
[]
);
const handleDateData = (type, payload) => {
switch (type) {
case 'SAVE':
saveDateData(payload).then((res) => {
if (res?.success) {
search();
} else {
showAlert.show(`${res?.data.message}`);
}
});
break;
default:
}
};
useEffect(() => {
search();
}, [search]);
@ -134,6 +175,11 @@ const JudgeReview = ({ msDatagb, menuName }) => {
minWidth: 150,
width: 200,
valueGetter: (params) => `${params.row.msCdate} ${params.row.msClosesi}`,
renderCell: (params) => (
<Link underline="hover" href="#">
{params.value}
</Link>
),
align: 'center'
},
{
@ -142,7 +188,9 @@ const JudgeReview = ({ msDatagb, menuName }) => {
field: 'actions',
type: 'actions',
width: 80,
getActions: (params) => [<GridActionsCellItem icon={<DeleteIcon />} label="Delete" onClick={deleteJudge(params.row)} />],
getActions: (params) => [
<GridActionsCellItem icon={<DeleteIcon />} color="error" label="Delete" onClick={deleteJudge(params.row)} />
],
align: 'center'
}
];
@ -177,7 +225,7 @@ const JudgeReview = ({ msDatagb, menuName }) => {
arrJudgeData.push({ msMaincode: res.data.judgeUserData[idx].msMaincode, msSeq: res.data.judgeUserData[idx].msSeq });
}
}
console.log(arrJudgeData);
// console.log(arrJudgeData);
setJudgeDatas(arrJudgeData);
setJudgeResultData({
@ -190,6 +238,21 @@ const JudgeReview = ({ msDatagb, menuName }) => {
setTitle(`${e.row.msCdate} ${menuName} 심사 결과 (${e.row.msChasu}차 - 총 ${e.row.cnt}건)`);
setOpen(true);
}
if (e?.field === 'msCdate') {
const params = {
msDatagb: e.row.msDatagb,
msYear: selectedYear,
msChasu: e.row.msChasu,
msSdate: e.row.msSdate,
msStartsi: e.row.msStartsi,
msEdate: e.row.msEdate,
msCdate: e.row.msCdate,
msClosesi: e.row.msClosesi
};
setDateDatas(params);
setDateModify(true);
}
};
return (
@ -248,6 +311,10 @@ const JudgeReview = ({ msDatagb, menuName }) => {
<CmmModal isBackdrop title={title} open={open} setOpen={setOpen}>
<ModalJudgeResult {...judgeResultData} judgeData={judgeDatas} />
</CmmModal>
,
<CmmModalStyle isBackdrop title="심사 기간 및 마감일시 수정" open={dateModify} setOpen={setDateModify} style={style}>
<JudgeDateModifyForm dateDatas={dateDatas} setDateModify={setDateModify} handleModalSave={handleDateData} />
</CmmModalStyle>
</MainCard>
);
};

@ -2,38 +2,65 @@ import { useState } from 'react';
import NumberFormat from 'react-number-format';
import format from 'date-fns/format';
import getHours from 'date-fns/getHours';
import koLocale from 'date-fns/locale/ko';
import { Grid, TextField, MenuItem, Select, FormControl, InputLabel, Divider } from '@mui/material';
import DateAdapter from '@mui/lab/AdapterDateFns';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import { DatePicker, TimePicker } from '@mui/lab';
import { Grid, TextField, MenuItem, Select, FormControl, InputLabel } from '@mui/material';
import Button from '@mui/material/Button';
import PropTypes from 'prop-types';
import { IconFileExport } from '@tabler/icons';
import combo from 'commons/combo_data';
import { useAlert } from 'react-alert';
import { MuiXDatePicker, MuiXMobileTimePicker } from 'views/cmm/MuiXDatePicker';
const toDate = new Date();
const JudgeTargetSaveForm = ({ handleModalSave }) => {
const [msuTeam, setMsuTeam] = useState(combo.teams[0].code);
const showAlert = useAlert();
const [msuTeam, setMsuTeam] = useState(' ');
const [msChasu, setMsChasu] = useState();
const [msSdate, setMsSdate] = useState(format(toDate, 'yyyy-MM-dd'));
const [msStartsi, setMsStartsi] = useState(getHours(toDate));
const [msStartsi, setMsStartsi] = useState('00');
const [msEdate, setMsEdate] = useState(format(toDate, 'yyyy-MM-dd'));
const [msChasu, setMsChasu] = useState(99);
const [msCdate, setMsCdate] = useState(format(toDate, 'yyyy-MM-dd'));
const [msClosesi, setMsClosesi] = useState(getHours(toDate));
const [msClosesi, setMsClosesi] = useState('23');
const onSave = () => {
// TODO : validation check
if (!msuTeam || msuTeam.length < 3) {
showAlert.show('심의팀을 선택해 주세요');
return;
}
if (!msChasu || msChasu.length === 0) {
showAlert.show('심의 차수를 입력해 주세요');
return;
}
if (msSdate.toString() >= msEdate.toString()) {
showAlert.show('심의시작일과 심의종료일을 확인해 주세요');
return;
}
if (msEdate.replace(/-/g, '') > msCdate.replace(/-/g, '')) {
showAlert.show('심사 종료일자가 심사 마감일자보다 클 수 없습니다.');
return;
}
if (msStartsi.length < 2) {
showAlert.show('심사 시작시간은 필수입니다.');
return;
}
if (msClosesi.length < 2) {
showAlert.show('심사 마감시간은 필수입니다.');
return;
}
handleModalSave({
msuTeam,
msChasu,
msSdate,
msStartsi,
msEdate,
msChasu,
msCdate,
msClosesi
});
@ -42,59 +69,13 @@ const JudgeTargetSaveForm = ({ handleModalSave }) => {
return (
<>
<Grid container spacing={2} mt={1.5}>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<DatePicker
// size="small"
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의시작일"
value={msSdate}
inputFormat="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setMsSdate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
{/* <MuiDatePicker label="심의시작일" date={msSdate} setDate={setMsSdate()} /> */}
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<TimePicker
size="small"
views={['hours']}
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의시작시간"
value={msStartsi}
inputFormat="HH"
mask="__"
onChange={(newValue) => {
// setMsStartsi(format(newValue, 'HH'));
setMsStartsi(getHours(newValue));
}}
/>
</LocalizationProvider>
{/* <MuiTimePicker label="심의시작시간" date={msStartsi} setDate={setMsStartsi()} /> */}
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<DatePicker
size="small"
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의종료일"
value={msEdate}
inputFormat="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setMsEdate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
</Grid>
<Grid item xs={12} sm={2}>
<Grid item xs={12} sm={6}>
<FormControl fullWidth>
<InputLabel required></InputLabel>
<InputLabel required>심의팀</InputLabel>
<Select defaultValue={msuTeam} onChange={(e) => setMsuTeam(e.target.value)}>
<MenuItem key={0} value=" ">
팀선택
</MenuItem>
{combo.teams.map((team) => (
<MenuItem key={team.code} value={team.code}>
{team.value}
@ -103,63 +84,34 @@ const JudgeTargetSaveForm = ({ handleModalSave }) => {
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={2}>
<Grid item xs={12} sm={6}>
<NumberFormat
customInput={TextField}
required
id="msChasu"
name="msChasu"
label="차수"
label="심의차수"
format="######"
fullWidth
value={msChasu}
onValueChange={(values) => setMsChasu(values.value)}
/>
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<DatePicker
size="small"
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의마감일"
value={msCdate}
inputFormat="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setMsCdate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
{/* <TextField */}
{/* type="date" */}
{/* value={msCdate} */}
{/* defaultValue={msCdate} */}
{/* InputLabelProps={{ shrink: true }} */}
{/* onChange={(e) => setMsCdate(format(e.target.value), 'yyyy-MM-dd')} */}
{/* /> */}
<Grid item xs={12} sm={6}>
<MuiXDatePicker label="심사 시작일자" date={msSdate} setDate={setMsSdate} />
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<TimePicker
size="small"
views={['hours']}
// renderInput={(props) => <TextField fullWidth {...props} />}
renderInput={(props) => <NumberFormat customInput={TextField} fullWidth {...props} format="##" />}
label="심의마감시간"
value={msClosesi}
inputFormat="HH"
mask="__"
onChange={(newValue) => {
setMsClosesi(getHours(newValue));
}}
/>
</LocalizationProvider>
<Grid item xs={12} sm={6}>
<MuiXMobileTimePicker label="심사 시작시간" date={`${format(toDate, 'yyyy-MM-dd')} ${msStartsi}:00`} setDate={setMsStartsi} />
</Grid>
<Grid item xs={12} sm={6}>
<MuiXDatePicker label="심사 종료일자" date={msEdate} setDate={setMsEdate} />
</Grid>
<Grid item xs={12} sm={6} />
<Grid item xs={12} sm={6}>
<MuiXDatePicker label="심사 마감일자" date={msCdate} setDate={setMsCdate} />
</Grid>
<Grid container spacing={1} item xs={12} mt={1}>
<Grid item xs={12}>
<Divider />
<Grid item xs={12} sm={6}>
<MuiXMobileTimePicker label="심사 마감시간" date={`${format(toDate, 'yyyy-MM-dd')} ${msClosesi}:00`} setDate={setMsClosesi} />
</Grid>
</Grid>
<Grid item container spacing={0.5} xs={12} mt={1}>

@ -10,13 +10,15 @@ import { FormControl, Grid, InputLabel, MenuItem, Select, TableFooter, Typograph
import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
import combo from 'commons/combo_data';
import { useCallback, useState } from 'react';
import { useCallback, useRef, useState } from 'react';
import Button from '@mui/material/Button';
import { IconSearch } from '@tabler/icons';
import { IconFileExport, IconSearch } from '@tabler/icons';
import { findJudgeResults } from 'apis/judge';
import _ from 'lodash';
import { useAlert } from 'react-alert';
import JudgeModal from './JudgeModal';
import saveAs from 'file-saver';
import * as Excel from 'exceljs';
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
@ -57,6 +59,19 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
});
const [judgeDatas, setJudgeDatas] = useState(judgeData ?? []);
const [msuTeam, setMsuTeam] = useState(judgeTeam ?? '001');
const [judgeDataCnt, setJudgeDataCnt] = useState(judgeUserData.filter((d) => d.msResult === '0').length);
const onChangeTeam = (e) => {
setJudgeResult({
...judgeResult,
totJudgeUsers: [],
totJudgeUserData: [],
judgeCars: [],
judgeUserData: []
});
setJudgeDataCnt(0);
setMsuTeam(e.target.value);
};
const onSearch = async () => {
if (msuTeam) {
@ -77,7 +92,6 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
}
}
setJudgeDatas(arrJudgeData);
// judgeDatas.current = arrJudgeData;
setJudgeResult({
...judgeResult,
@ -86,14 +100,9 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
judgeCars: res.data?.judgeCars,
judgeUserData: res.data?.judgeUserData
});
setJudgeDataCnt(res.data?.judgeUserData.filter((d) => d.msResult === '0').length);
console.log(res.data?.judgeUserData.filter((d) => d.msResult === '0').length);
} else {
setJudgeResult({
...judgeResult,
totJudgeUsers: [],
totJudgeUserData: [],
judgeCars: [],
judgeUserData: []
});
alert.show('조회된 데이타가 없습니다.');
}
}
@ -113,6 +122,73 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
[]
);
const handleExcelDownload = () => {
const colNames = ['No.', '접수번호', '차량번호'];
judgeResult.totJudgeUsers.forEach((u) => colNames.push(u.NAME));
colNames.push('결과');
const excelDatas = [];
judgeResult.totJudgeUserData.forEach((u, idx) => {
excelDatas.push(['', totLabel[idx], '', ...u]);
});
judgeResult.judgeCars.forEach((d, idx) => {
excelDatas.push([
idx + 1,
d.msSeq,
d.msCarnum,
..._.range(idx, judgeResult.judgeUserData.length, judgeResult.judgeCars.length).map((i) => judgeResult.judgeUserData[i].msuResult),
judgeResult.judgeUserData[idx].msResultNm
]);
});
if (!excelDatas || excelDatas.length === 0) {
alert.show('다운로드할 대상이 없습니다.[데이타 조회후 실행]');
return;
}
const workbook = new Excel.Workbook();
const worksheet = workbook.addWorksheet('Sheet'); // sheet My Sheet
const headerRow = worksheet.addRow();
worksheet.getRow(1).font = { bold: true };
colNames.forEach((col, idx) => {
worksheet.getColumn(idx + 1).width = 10;
const cell = headerRow.getCell(idx + 1);
cell.value = col;
});
worksheet.properties.outlineProperties = {
summaryBelow: false,
summaryRight: false
};
excelDatas.forEach((row) => {
const dataRow = worksheet.addRow();
colNames.forEach((col, i) => {
const cell = dataRow.getCell(i + 1);
cell.value = row[i];
return false;
});
});
let fileName = '';
if (!selectedRow.msDatagb) {
fileName = '주정차';
} else {
fileName = selectedRow.msDatagb === '1' ? '거주자' : '장애인';
}
workbook.xlsx.writeBuffer().then((buffer) => {
saveAs(
new Blob([buffer], { type: 'application/octet-stream' }),
`${fileName} 심사결과[${selectedRow.msChasu}차-${msuTeam.substring(2)}팀(${selectedRow.msSdate} ~ ${selectedRow.msEdate})].xlsx`
);
});
};
return (
<Box
sx={{
@ -125,23 +201,17 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
>
<Grid container spacing={1} alignItems="center" mb={1}>
<Grid container spacing={1}>
<Grid item xs={7}>
<Grid item xs={6}>
<Typography variant="subtitle1">
심의차수: {selectedRow.msChasu} 심의기간: {selectedRow.msSdate} ~ {selectedRow.msEdate}
</Typography>
</Grid>
<Grid item xs={5}>
<Grid container spacing={0.5} alignItems="center" mb={1}>
<Grid item xs={6} style={{ marginLeft: 'auto' }}>
<Grid item xs={6}>
<Grid container spacing={0.5} style={{ marginLeft: 'auto' }} alignItems="flex-end" mb={1}>
<Grid item xs={3.7}>
<FormControl fullWidth>
<InputLabel required></InputLabel>
<Select
sx={{ marginTop: 1 }}
defaultValue={msuTeam}
value={msuTeam}
onChange={(e) => setMsuTeam(e.target.value)}
size="small"
>
<Select sx={{ marginTop: 1 }} defaultValue={msuTeam} value={msuTeam} onChange={onChangeTeam} size="small">
{combo.teams.map((team, idx) => (
<MenuItem key={idx} value={team.code}>
{team.value}
@ -150,12 +220,12 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
</Select>
</FormControl>
</Grid>
<Grid item xs={6} sx={{ marginTop: 1 }}>
<Grid item xs={8} sx={{ marginTop: 1, marginLeft: 1 }} alignItems="flex-end">
<Button variant="contained" color="primary" size="small" startIcon={<IconSearch />} onClick={onSearch}>
조회
</Button>
<Button
disabled={judgeDatas.length === 0}
disabled={judgeDataCnt === 0}
variant="contained"
color="primary"
size="small"
@ -164,6 +234,15 @@ const ModalJudgeResult = ({ totJudgeUsers, totJudgeUserData, judgeCars, judgeUse
>
일괄처리
</Button>
<Button
disabled={judgeResult.totJudgeUsers.length === 0}
variant="contained"
size="small"
startIcon={<IconFileExport />}
onClick={handleExcelDownload}
>
엑셀다운로드
</Button>
</Grid>
</Grid>
</Grid>

@ -14,16 +14,34 @@ import MainCard from 'ui-component/cards/MainCard';
import MuiDataGrid from 'views/cmm/mui-grid/MuiDataGrid';
import xitCmm, { ErrorToast, saveAlert } from 'commons/XitCmm';
import CmmModal from 'views/cmm/CmmModal';
import SaveParkingTargetForm from './SaveParkingTargetForm';
import NumberFormat from 'react-number-format';
import ExcelDownload from 'views/cmm/file-ctl/ExcelDownload';
import ExcelDownloadGrid from 'views/cmm/file-ctl/ExcelDownloadGrid';
import { findParkingJudgeTargets, saveParkingJudgeTargets } from 'apis/parking';
import getYear from 'date-fns/getYear';
import { useAlert } from 'react-alert';
import CmmModalStyle from 'views/cmm/CmmModalStyle';
const year = getYear(new Date()).toString();
const style = {
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 500,
minHeight: 300,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 3
};
const ParkingRegister = () => {
const showAlert = useAlert();
const [rcIrTransfer, setRcIrTransfer] = useState('1');
const [rcSeq1, setRcSeq1] = useState('2022200801');
const [rcSeq2, setRcSeq2] = useState('2022200899');
const [rcSeq1, setRcSeq1] = useState(`${year}000001`);
const [rcSeq2, setRcSeq2] = useState(`${year}999999`);
const [selectionModel, setSelectionModel] = useState([]);
const [totalCount, setTotalCount] = useState(0);
const [rowsState, setRowsState] = useState({
@ -55,6 +73,15 @@ const ParkingRegister = () => {
];
const search = () => {
if (rcSeq1.length < 10 || rcSeq2.length < 10) {
showAlert.show('접수번호를 10자리로 입력해 주세요[ex:2022000001]');
return;
}
if (rcSeq1 > rcSeq2) {
showAlert.show('접수번호 조건을 확인해 주세요');
return;
}
const params = {
rcIrTransfer,
rcSeq1,
@ -191,7 +218,7 @@ const ParkingRegister = () => {
</Button>
</Grid>
<Grid item>
<ExcelDownload fileName="심사등록대상" gridColumns={columns} excelDatas={rowsState.rows} isDisabled={totalCount === 0} />
<ExcelDownloadGrid fileName="심사등록대상" gridColumns={columns} excelDatas={rowsState.rows} isDisabled={totalCount === 0} />
</Grid>
</Grid>
</Grid>
@ -213,9 +240,9 @@ const ParkingRegister = () => {
handleSelection={handleSelection}
selectionModel={selectionModel}
/>
<CmmModal isBackdrop title="심의등록" open={open} setOpen={setOpen}>
<CmmModalStyle isBackdrop title="심의등록" open={open} setOpen={setOpen} style={style}>
<SaveParkingTargetForm isDisabled={selectionModel.length === 0} handleModalSave={submitParkingTargets} />
</CmmModal>
</CmmModalStyle>
</MainCard>
);
};

@ -2,38 +2,65 @@ import { useState } from 'react';
import NumberFormat from 'react-number-format';
import format from 'date-fns/format';
import getHours from 'date-fns/getHours';
import koLocale from 'date-fns/locale/ko';
import { Grid, TextField, MenuItem, Select, FormControl, InputLabel } from '@mui/material';
import DateAdapter from '@mui/lab/AdapterDateFns';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import { DatePicker, TimePicker } from '@mui/lab';
import Button from '@mui/material/Button';
import PropTypes from 'prop-types';
import { IconFileExport } from '@tabler/icons';
import combo from 'commons/combo_data';
import { useAlert } from 'react-alert';
import { MuiXDatePicker, MuiXMobileTimePicker } from 'views/cmm/MuiXDatePicker';
const toDate = new Date();
const SaveParkingTargetForm = ({ handleModalSave }) => {
const [msuTeam, setMsuTeam] = useState(combo.teams[0].code);
const showAlert = useAlert();
const [msuTeam, setMsuTeam] = useState(' ');
const [msChasu, setMsChasu] = useState();
const [msSdate, setMsSdate] = useState(format(toDate, 'yyyy-MM-dd'));
const [msStartsi, setMsStartsi] = useState(getHours(toDate));
const [msStartsi, setMsStartsi] = useState('00');
const [msEdate, setMsEdate] = useState(format(toDate, 'yyyy-MM-dd'));
const [msChasu, setMsChasu] = useState(99);
const [msCdate, setMsCdate] = useState(format(toDate, 'yyyy-MM-dd'));
const [msClosesi, setMsClosesi] = useState(getHours(toDate));
const [msClosesi, setMsClosesi] = useState('23');
const onSave = () => {
// TODO : validation check
if (!msuTeam || msuTeam.length < 3) {
showAlert.show('심의팀을 선택해 주세요');
return;
}
if (!msChasu || msChasu.length === 0) {
showAlert.show('심의 차수를 입력해 주세요');
return;
}
if (msSdate.toString() >= msEdate.toString()) {
showAlert.show('심의시작일과 심의종료일을 확인해 주세요');
return;
}
if (msEdate.replace(/-/g, '') > msCdate.replace(/-/g, '')) {
showAlert.show('심사 종료일자가 심사 마감일자보다 클 수 없습니다.');
return;
}
if (msStartsi.length < 2) {
showAlert.show('심사 시작시간은 필수입니다.');
return;
}
if (msClosesi.length < 2) {
showAlert.show('심사 마감시간은 필수입니다.');
return;
}
handleModalSave({
msuTeam,
msChasu,
msSdate,
msStartsi,
msEdate,
msChasu,
msCdate,
msClosesi
});
@ -42,59 +69,13 @@ const SaveParkingTargetForm = ({ handleModalSave }) => {
return (
<>
<Grid container spacing={2} mt={1.5}>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<DatePicker
// size="small"
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의시작일"
value={msSdate}
inputFormat="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setMsSdate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
{/* <MuiDatePicker label="심의시작일" date={msSdate} setDate={setMsSdate()} /> */}
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<TimePicker
size="small"
views={['hours']}
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의시작시간"
value={msStartsi}
inputFormat="HH"
mask="__"
onChange={(newValue) => {
// setMsStartsi(format(newValue, 'HH'));
setMsStartsi(getHours(newValue));
}}
/>
</LocalizationProvider>
{/* <MuiTimePicker label="심의시작시간" date={msStartsi} setDate={setMsStartsi()} /> */}
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<DatePicker
size="small"
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의종료일"
value={msEdate}
inputFormat="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setMsEdate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
</Grid>
<Grid item xs={12} sm={2}>
<Grid item xs={12} sm={6}>
<FormControl fullWidth>
<InputLabel required></InputLabel>
<Select name="reviewYear" defaultValue={msuTeam} onChange={(e) => setMsuTeam(e.target.value)}>
<InputLabel required>심의팀</InputLabel>
<Select defaultValue={msuTeam} onChange={(e) => setMsuTeam(e.target.value)}>
<MenuItem key={0} value=" ">
팀선택
</MenuItem>
{combo.teams.map((team) => (
<MenuItem key={team.code} value={team.code}>
{team.value}
@ -103,65 +84,43 @@ const SaveParkingTargetForm = ({ handleModalSave }) => {
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={2}>
<Grid item xs={12} sm={6}>
<NumberFormat
customInput={TextField}
required
id="msChasu"
name="msChasu"
label="차수"
label="심의차수"
format="######"
fullWidth
value={msChasu}
onValueChange={(values) => setMsChasu(values.value)}
/>
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<DatePicker
size="small"
renderInput={(props) => <TextField fullWidth {...props} />}
label="심의마감일"
value={msCdate}
inputFormat="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setMsCdate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
{/* <TextField */}
{/* type="date" */}
{/* value={msCdate} */}
{/* defaultValue={msCdate} */}
{/* InputLabelProps={{ shrink: true }} */}
{/* onChange={(e) => setMsCdate(format(e.target.value), 'yyyy-MM-dd')} */}
{/* /> */}
<Grid item xs={12} sm={6}>
<MuiXDatePicker label="심사 시작일자" date={msSdate} setDate={setMsSdate} />
</Grid>
<Grid item xs={12} sm={4}>
<LocalizationProvider dateAdapter={DateAdapter} locale={koLocale}>
<TimePicker
size="small"
views={['hours']}
// renderInput={(props) => <TextField fullWidth {...props} />}
renderInput={(props) => <NumberFormat customInput={TextField} fullWidth {...props} format="##" />}
label="심의마감시간"
value={msClosesi}
inputFormat="HH"
mask="__"
onChange={(newValue) => {
setMsClosesi(getHours(newValue));
}}
/>
</LocalizationProvider>
<Grid item xs={12} sm={6}>
<MuiXMobileTimePicker label="심사 시작시간" date={`${format(toDate, 'yyyy-MM-dd')} ${msStartsi}:00`} setDate={setMsStartsi} />
</Grid>
<Grid item xs={12} sm={6}>
<MuiXDatePicker label="심사 종료일자" date={msEdate} setDate={setMsEdate} />
</Grid>
<Grid item xs={12} sm={6} />
<Grid item xs={12} sm={6}>
<MuiXDatePicker label="심사 마감일자" date={msCdate} setDate={setMsCdate} />
</Grid>
<Grid item xs={12} sm={6}>
<MuiXMobileTimePicker label="심사 마감시간" date={`${format(toDate, 'yyyy-MM-dd')} ${msClosesi}:00`} setDate={setMsClosesi} />
</Grid>
<Grid item sx={{ marginTop: 3 }}>
</Grid>
<Grid item container spacing={0.5} xs={12} mt={1}>
<Grid item style={{ marginLeft: 'auto' }}>
<Button variant="contained" color="primary" size="small" startIcon={<IconFileExport />} onClick={onSave}>
저장
</Button>
</Grid>
</Grid>
</>
);
};

@ -182,7 +182,7 @@ const ModifyBoardForm = (props) => {
</Button>
</Grid>
<Grid item>
<Button disabled={!owner} variant="contained" size="small" startIcon={<Delete />} onClick={onRemove}>
<Button disabled={!owner} variant="contained" size="small" color="error" startIcon={<Delete />} onClick={onRemove}>
삭제
</Button>
</Grid>

@ -136,16 +136,16 @@ const JudgeByUserReview = ({ msDatagb, menuName }) => {
valueGetter: (params) => `${params.row.msSdate} ~ ${params.row.msEdate}`,
align: 'center'
},
{
headerName: '심의 마감 일시',
headerAlign: 'center',
field: 'msCdate',
type: 'dateTime',
minWidth: 150,
width: 200,
valueGetter: (params) => `${params.row.msCdate} ${params.row.msClosesi}`,
align: 'center'
},
// {
// headerName: ' ',
// headerAlign: 'center',
// field: 'msCdate',
// type: 'dateTime',
// minWidth: 150,
// width: 200,
// valueGetter: (params) => `${params.row.msCdate} ${params.row.msClosesi}`,
// align: 'center'
// },
{
headerName: '개별심사',
headerAlign: 'center',

@ -31,7 +31,7 @@ const ParkingJudgeByUserReview = () => {
});
const [open, setOpen] = useState(false);
const [title, setTitle] = useState('');
const [rowDatas] = useState([]);
const [rowDatas, setRowDatas] = useState([]);
const [minSdate, setMinSdate] = useState('');
const [maxEdate, setMaxEdate] = useState('');
const [minSeq, setMinSeq] = useState(0);
@ -55,18 +55,18 @@ const ParkingJudgeByUserReview = () => {
}, []);
const onJudge = () => {
// setRowDatas(rowsState?.rows);
// setTitle(` `);
// setOpen(true);
alert('적용예정');
setRowDatas(rowsState?.rows);
setTitle(`주정차 의견진술 심의 결정`);
setOpen(true);
// alert('');
};
const processJudge = useCallback(
(row) => () => {
// setRowDatas([row]);
// setTitle(` `);
// setOpen(true);
alert('적용예정');
setRowDatas([row]);
setTitle(`주정차 의견진술 심의 결정`);
setOpen(true);
// alert('');
},
[]
);
@ -136,16 +136,16 @@ const ParkingJudgeByUserReview = () => {
valueGetter: (params) => `${params.row.msSdate} ~ ${params.row.msEdate}`,
align: 'center'
},
{
headerName: '심의 마감 일시',
headerAlign: 'center',
field: 'msCdate',
type: 'dateTime',
minWidth: 150,
width: 200,
valueGetter: (params) => `${params.row.msCdate} ${params.row.msClosesi}`,
align: 'center'
},
// {
// headerName: ' ',
// headerAlign: 'center',
// field: 'msCdate',
// type: 'dateTime',
// minWidth: 150,
// width: 200,
// valueGetter: (params) => `${params.row.msCdate} ${params.row.msClosesi}`,
// align: 'center'
// },
{
headerName: '개별심사',
headerAlign: 'center',

@ -2,10 +2,12 @@ import { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Button, Divider, FormControl, Grid, ImageList, InputLabel, MenuItem, Select, TextField } from '@mui/material';
import { findImages, saveJudgeResult } from 'apis/judge';
import { findJudgeImages, saveJudgeResult } from 'apis/judge';
import { SkipNext, SkipPrevious, Save } from '@mui/icons-material';
import ImgItem from '../../cmm/ImgItem';
import NumberFormat from 'react-number-format';
// eslint-disable-next-line import/no-extraneous-dependencies
import { useMediaQuery } from 'react-responsive';
const ProcessJudge = (props) => {
const { rowDatas, setOpen, showAlert } = props;
@ -19,9 +21,17 @@ const ProcessJudge = (props) => {
const [selectedResult, setSelectedResult] = useState();
const [selectedImg, setSelectedImg] = useState({});
const isDesktopOrLaptop = useMediaQuery({
query: '(min-width: 1224px)'
});
const isTabletOrMobile = useMediaQuery({ query: '(max-width: 1224px)' });
const size2 = (isDesktopOrLaptop && 2) || (isTabletOrMobile && 12);
const size6 = (isDesktopOrLaptop && 6) || (isTabletOrMobile && 12);
const getImgList = (row) => {
findImages(row).then((res) => {
findJudgeImages(row).then((res) => {
const { arrFrecadImg, arrContadImg, arrPicadImg } = res;
// console.log(arrFrecadImg, arrContadImg, arrPicadImg);
setFrecadImgs(arrFrecadImg);
setContadImgs(arrContadImg);
setPicadImgs(arrPicadImg);
@ -44,7 +54,7 @@ const ProcessJudge = (props) => {
};
const handleSave = () => {
console.log('~~~');
// console.log('~~~');
if (!selectedResult || selectedResult === '0') {
showAlert.show('심의결정[미부과/부과]을 선택해 주세요');
return;
@ -53,7 +63,12 @@ const ProcessJudge = (props) => {
showAlert.show('결정사유는 필수 입력해야 합니다.');
return;
}
saveJudgeResult({ msuCode: curDataRef.current.msuCode, msuResult: selectedResult, msuReason: reason }).then((res) => {
saveJudgeResult({
msuCode: curDataRef.current.msuCode,
msuUserid: rowDatas[pageRef.current].msuUserid,
msuResult: selectedResult,
msuReason: reason
}).then((res) => {
if (res?.success) {
curDataRef.current.msuResult = selectedResult;
curDataRef.current.msuReason = reason;
@ -88,47 +103,50 @@ const ProcessJudge = (props) => {
return (
<>
<Grid container spacing={1}>
<Grid item xs={6.5}>
<Grid item xs={size6}>
<ImageList cols={4}>
{frecadImgs?.map((img, idx) => (
{frecadImgs
?.filter((img) => img.imgName !== '')
.map((img, idx) => (
<ImgItem key={idx} idx={idx} title={`진술서${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
))}
</ImageList>
<ImageList cols={4}>
{contadImgs?.map((img, idx) => (
{contadImgs
?.filter((img) => img.imgName !== '')
.map((img, idx) => (
<ImgItem key={idx} idx={idx} title={`첨부파일${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
))}
</ImageList>
<ImageList cols={4}>
{picadImgs?.map((img, idx) => (
{picadImgs
?.filter((img) => img.imgName !== '')
.map((img, idx) => (
<ImgItem key={idx} idx={idx} title={`단속사진${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
))}
</ImageList>
</Grid>
<Grid item xs={5.5}>
<Grid container spacing={1}>
<Grid item xs={(isDesktopOrLaptop && 5.9) || (isTabletOrMobile && 12)} ml={0.8} border={1}>
<Grid container>
<Grid item xs={12}>
{selectedImg && (
<img
src={selectedImg.url}
srcSet={`${selectedImg.url}?w=400&h=400&fit=crop&auto=format&dpr=2 2x`}
alt={selectedImg.imgName}
loading="lazy"
/>
<ImageList sx={{ width: '100%', height: 554, margin: '0' }}>
<img style={{ maxWidth: '690px' }} resizemode="contain" src={selectedImg.url} alt={selectedImg.imgName} loading="lazy" />
</ImageList>
)}
</Grid>
</Grid>
</Grid>
<Grid container m={1}>
<Grid container>
<Grid item xs={12}>
<Divider />
</Grid>
</Grid>
<Grid container spacing={1} mt={1}>
<Grid item xs={2}>
<Grid item xs={size2}>
<TextField size="small" required disabled label="접수번호" fullWidth value={rowDatas[pageRef.current].msSeq} />
</Grid>
<Grid item xs={2}>
<Grid item xs={size2}>
<NumberFormat
disabled
size="small"
@ -137,13 +155,13 @@ const ProcessJudge = (props) => {
label="위반일자"
format="####-##-##"
fullWidth
value={rowDatas[pageRef.current].scWdate}
value={rowDatas[pageRef.current]?.msWdate || ''}
/>
</Grid>
<Grid item xs={6}>
<TextField size="small" required disabled label="위반장소" fullWidth value={rowDatas[pageRef.current].scPos} />
<Grid item xs={size6}>
<TextField size="small" required disabled label="위반장소" fullWidth value={rowDatas[pageRef.current]?.msPos || ''} />
</Grid>
<Grid item xs={2}>
<Grid item xs={size2}>
<FormControl fullWidth>
<InputLabel disabled required>
심의결정

@ -2,10 +2,12 @@ import { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Button, Divider, FormControl, Grid, ImageList, InputLabel, MenuItem, Select, TextField } from '@mui/material';
import { findImages, saveJudgeResult } from 'apis/judge';
import { findParkingImages, saveParkingJudgeResult } from 'apis/judge';
import { SkipNext, SkipPrevious, Save } from '@mui/icons-material';
import ImgItem from '../../cmm/ImgItem';
import NumberFormat from 'react-number-format';
// eslint-disable-next-line import/no-extraneous-dependencies
import { useMediaQuery } from 'react-responsive';
const ProcessParkingJudge = (props) => {
const { rowDatas, setOpen, showAlert } = props;
@ -19,9 +21,17 @@ const ProcessParkingJudge = (props) => {
const [selectedResult, setSelectedResult] = useState();
const [selectedImg, setSelectedImg] = useState({});
const isDesktopOrLaptop = useMediaQuery({
query: '(min-width: 1224px)'
});
const isTabletOrMobile = useMediaQuery({ query: '(max-width: 1224px)' });
const size2 = (isDesktopOrLaptop && 2) || (isTabletOrMobile && 12);
const size6 = (isDesktopOrLaptop && 6) || (isTabletOrMobile && 12);
const getImgList = (row) => {
findImages(row).then((res) => {
findParkingImages(row?.rcMaincode).then((res) => {
const { arrFrecadImg, arrContadImg, arrPicadImg } = res;
// console.log(arrFrecadImg, arrContadImg, arrPicadImg);
setFrecadImgs(arrFrecadImg);
setContadImgs(arrContadImg);
setPicadImgs(arrPicadImg);
@ -52,11 +62,17 @@ const ProcessParkingJudge = (props) => {
showAlert.show('결정사유는 필수 입력해야 합니다.');
return;
}
saveJudgeResult({ msuCode: curDataRef.current.msuCode, msuResult: selectedResult, msuReason: reason }).then((res) => {
saveParkingJudgeResult({
msuCode: curDataRef.current.msuCode,
msuUserid: rowDatas[pageRef.current].msuUserid,
msuResult: selectedResult,
msuReason: reason
}).then((res) => {
if (res?.success) {
curDataRef.current.msuResult = selectedResult;
curDataRef.current.msuReason = reason;
showAlert.show('심의처리 되었습니다');
// setOpen(false)
} else {
showAlert.show(`${res?.data.message}`);
}
@ -87,47 +103,50 @@ const ProcessParkingJudge = (props) => {
return (
<>
<Grid container spacing={1}>
<Grid item xs={6.5}>
<Grid item xs={size6}>
<ImageList cols={4}>
{frecadImgs?.map((img, idx) => (
<ImgItem idx={idx} title={`진술서${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
{frecadImgs
?.filter((img) => img.imgName !== '')
.map((img, idx) => (
<ImgItem key={idx} idx={idx} title={`진술서${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
))}
</ImageList>
<ImageList cols={4}>
{contadImgs?.map((img, idx) => (
<ImgItem idx={idx} title={`첨부파일${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
{contadImgs
?.filter((img) => img.imgName !== '')
.map((img, idx) => (
<ImgItem key={idx} idx={idx} title={`첨부파일${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
))}
</ImageList>
<ImageList cols={4}>
{picadImgs?.map((img, idx) => (
<ImgItem idx={idx} title={`단속사진${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
{picadImgs
?.filter((img) => img.imgName !== '')
.map((img, idx) => (
<ImgItem key={idx} idx={idx} title={`단속사진${idx + 1}`} imgInfo={img} onViewImage={viewImage} />
))}
</ImageList>
</Grid>
<Grid item xs={5.5}>
<Grid item xs={(isDesktopOrLaptop && 5.9) || (isTabletOrMobile && 12)} ml={0.8} border={1}>
<Grid container spacing={1}>
<Grid item xs={12}>
{selectedImg && (
<img
src={selectedImg.url}
srcSet={`${selectedImg.url}?w=400&h=400&fit=crop&auto=format&dpr=2 2x`}
alt={selectedImg.imgName}
loading="lazy"
/>
<ImageList sx={{ width: '100%', height: 554, margin: '0' }}>
<img style={{ maxWidth: '690px' }} resizemode="contain" src={selectedImg.url} alt={selectedImg.imgName} loading="lazy" />
</ImageList>
)}
</Grid>
</Grid>
</Grid>
<Grid container m={1}>
<Grid container>
<Grid item xs={12}>
<Divider />
</Grid>
</Grid>
<Grid container spacing={1} mt={1}>
<Grid item xs={2}>
<Grid item xs={size2}>
<TextField size="small" required disabled label="접수번호" fullWidth value={rowDatas[pageRef.current].msSeq} />
</Grid>
<Grid item xs={2}>
<Grid item xs={size2}>
<NumberFormat
disabled
size="small"
@ -136,13 +155,13 @@ const ProcessParkingJudge = (props) => {
label="위반일자"
format="####-##-##"
fullWidth
value={rowDatas[pageRef.current].scWdate}
value={rowDatas[pageRef.current]?.msWdate || ''}
/>
</Grid>
<Grid item xs={6}>
<TextField size="small" required disabled label="위반장소" fullWidth value={rowDatas[pageRef.current].scPos} />
<Grid item xs={size6}>
<TextField size="small" required disabled label="위반장소" fullWidth value={rowDatas[pageRef.current]?.msPos || ''} />
</Grid>
<Grid item xs={2}>
<Grid item xs={size2}>
<FormControl fullWidth>
<InputLabel disabled required>
심의결정

@ -210,7 +210,7 @@ const ModifyPublicBoardForm = (props) => {
}
}}
>
<Button disabled={!owner} variant="contained" size="small" startIcon={<Delete />} onClick={onRemove}>
<Button disabled={!owner} variant="contained" size="small" color="error" startIcon={<Delete />} onClick={onRemove}>
삭제
</Button>
</Grid>

@ -104,8 +104,8 @@ const UserManager = () => {
align: 'center',
width: 80,
valueFormatter: (params) => (params.value === '0' ? '비활성' : '활성')
},
{ headerName: '구청코드', headerAlign: 'center', field: 'gu', align: 'right' }
}
// { headerName: '', headerAlign: 'center', field: 'gu', align: 'right' }
];
//
const search = useCallback(() => {

@ -7,9 +7,9 @@ import { Button, Divider, FormControl, Grid, InputLabel, MenuItem, Select, TextF
import 'react-quill/dist/quill.snow.css';
// project imports
import { Delete, List, Save } from '@mui/icons-material';
import { Delete, List, Save, Update } from '@mui/icons-material';
import PropTypes from 'prop-types';
import { removeAlert, saveAlert } from '../../../commons/XitCmm';
import { removeAlert, saveAlert, updateAlert } from '../../../commons/XitCmm';
import { useAlert } from 'react-alert';
const UserManagementForm = (props) => {
@ -72,10 +72,16 @@ const UserManagementForm = (props) => {
isenable
};
setOpen(false);
if (isenable === '1')
removeAlert(
() => handleModalSave('DELETE', saveParam),
() => setOpen(true)
);
if (isenable === '0')
updateAlert(
() => handleModalSave('DELETE', saveParam),
() => setOpen(true)
);
};
return (
@ -96,6 +102,7 @@ const UserManagementForm = (props) => {
<Grid item sm={5.9}>
<TextField
size="small"
// disabled={!create}
required
label="비밀번호"
type="password"
@ -175,8 +182,15 @@ const UserManagementForm = (props) => {
}
}}
>
<Button variant="contained" size="small" startIcon={<Delete />} onClick={onRemove}>
삭제
<Button
variant="contained"
size="small"
color={(rowData.isenable === '0' && 'warning') || (rowData.isenable === '1' && 'error')}
startIcon={(rowData.isenable === '0' && <Update />) || (rowData.isenable === '1' && <Delete />)}
onClick={onRemove}
>
{rowData.isenable === '0' && '복구'}
{rowData.isenable === '1' && '삭제'}
</Button>
</Grid>
)}

@ -10,12 +10,13 @@ const style = {
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '98%',
minHeight: '98%',
width: '80%',
height: '85%',
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 3
p: 2,
overflowY: 'auto'
};
const CmmFullModal = ({ isBackdrop = false, open, setOpen, title, children, callback = () => {} }) => {

@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import Modal from '@mui/material/Modal';
import { Grid, IconButton } from '@mui/material';
import { Grid, IconButton, ImageList } from '@mui/material';
import CloseOutlined from '@mui/icons-material/CloseOutlined';
import MainCard from 'ui-component/cards/MainCard';
@ -11,7 +11,7 @@ const style = {
left: '50%',
transform: 'translate(-50%, -50%)',
width: 1000,
minHeight: 800,
height: 800,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
@ -38,9 +38,11 @@ const CmmImgViewModal = ({ isBackdrop = false, open, setOpen, title, imgUrl, img
}
>
<Grid container spacing={1}>
<ImageList sx={{ width: '100%', height: 650 }}>
<Grid item xs={12}>
<img src={imgUrl} srcSet={`${imgUrl}?w=400&h=400&fit=crop&auto=format&dpr=2 2x`} alt={imgName} loading="lazy" />
<img style={{ maxWidth: '920px' }} resizemode="contain" src={imgUrl} alt={imgName} loading="lazy" />
</Grid>
</ImageList>
</Grid>
</MainCard>
</Modal>

@ -0,0 +1,44 @@
import PropTypes from 'prop-types';
import Modal from '@mui/material/Modal';
import { IconButton } from '@mui/material';
import CloseOutlined from '@mui/icons-material/CloseOutlined';
import MainCard from 'ui-component/cards/MainCard';
const CmmModal = ({ isBackdrop = false, open, setOpen, title, children, style, callback = () => {} }) => {
const handleClose = () => {
if (callback) callback();
setOpen(false);
};
return (
<div className="modalGroup">
{/* <Button onClick={handleOpen}>Grid Modal(List)</Button> */}
<Modal hideBackdrop={isBackdrop} open={open} aria-labelledby="modal-modal-title" aria-describedby="modal-modal-description">
<MainCard
sx={style}
title={title}
content
secondary={
<IconButton size="small" variant="rounded" onClick={handleClose}>
<CloseOutlined fontSize="small" />
</IconButton>
}
>
{children}
</MainCard>
</Modal>
</div>
);
};
CmmModal.propTypes = {
isBackdrop: PropTypes.bool,
open: PropTypes.bool,
title: PropTypes.string,
children: PropTypes.node,
setOpen: PropTypes.func,
callback: PropTypes.func
};
export default CmmModal;

@ -4,19 +4,14 @@ import PropTypes from 'prop-types';
const ImgItem = ({ idx, title, imgInfo, onViewImage }) => (
<ImageListItem key={idx}>
<img
src={imgInfo.url}
// srcSet={`${item.img}?w=164&h=164&fit=crop&auto=format&dpr=2 2x`}
alt={imgInfo.imgName}
loading="lazy"
/>
<img src={imgInfo.url} style={{ maxHeight: '135px' }} alt={imgInfo.imgName} loading="lazy" />
{imgInfo.imgName && (
<ImageListItemBar
title={title}
subtitle={imgInfo.imgName}
actionIcon={
<IconButton
sx={{ color: 'rgba(255, 255, 255, 0.54)' }}
sx={{ color: 'rgba(255, 255, 255, 0.54)', alignItems: 'baseline' }}
aria-label={`info about ${imgInfo.imgName}`}
onClick={onViewImage(imgInfo)}
>

@ -0,0 +1,31 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { ClockLoader } from 'react-spinners';
const style = {
borderRadius: '5%',
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
backgroundColor: 'white',
width: 150,
height: 100,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
color: '#36d7b7'
};
function Loading() {
return (
<div>
<div style={style}>
<ClockLoader color="#36d7b7" />
<font> Process Loding... </font>
</div>
</div>
);
}
export default Loading;

@ -6,10 +6,11 @@ import CloseIcon from '@mui/icons-material/Close';
import AlertTitle from '@mui/material/AlertTitle';
import PropTypes from 'prop-types';
// TODO : severity double-quote - prettier-ignore
// severity double-quote - prettier-ignore
// prettier-ignore
export default function MuiAlert({ severity = "info", title = '', message, open, setOpen }) {
console.log(severity);
// console.log(severity);
return (
<Box sx={{ width: '100%' }}>
<Collapse in={open}>

@ -0,0 +1,63 @@
import format from 'date-fns/format';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { LocalizationProvider, DateTimePicker, DatePicker, MobileTimePicker } from '@mui/x-date-pickers';
import PropTypes from 'prop-types';
const MuiXDateTimePicker = ({ label, date, setDate }) => (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateTimePicker
label={label}
value={new Date(date)}
format="yyyy-MM-dd HH:mm:ss"
mask="____-__-__ __:__:__"
onChange={(newValue) => {
setDate(format(newValue, 'yyyy-MM-dd HH:mm:ss'));
}}
/>
</LocalizationProvider>
);
MuiXDateTimePicker.propTypes = {
label: PropTypes.string,
date: PropTypes.string,
setDate: PropTypes.func
};
const MuiXDatePicker = ({ label, date, setDate }) => (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label={label}
value={new Date(date)}
format="yyyy-MM-dd"
mask="____-__-__"
onChange={(newValue) => {
setDate(format(newValue, 'yyyy-MM-dd'));
}}
/>
</LocalizationProvider>
);
MuiXDatePicker.propTypes = {
label: PropTypes.string,
date: PropTypes.string,
setDate: PropTypes.func
};
const MuiXMobileTimePicker = ({ label, date, setDate }) => (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<MobileTimePicker
label={label}
value={new Date(date)}
views={['hours']}
onChange={(newValue) => {
setDate(format(newValue, 'HH'));
}}
/>
</LocalizationProvider>
);
MuiXMobileTimePicker.propTypes = {
label: PropTypes.string,
date: PropTypes.string,
setDate: PropTypes.func
};
export { MuiXDateTimePicker, MuiXDatePicker, MuiXMobileTimePicker };

@ -5,7 +5,7 @@ import * as Excel from 'exceljs';
import saveAs from 'file-saver';
import { useAlert } from 'react-alert';
const ExcelDownload = ({ fileName, gridColumns, excelDatas, isDisabled = true }) => {
const ExcelDownloadGrid = ({ fileName, gridColumns, excelDatas, isDisabled = true }) => {
const alert = useAlert();
const handleExcelDownload = () => {
@ -101,11 +101,11 @@ const ExcelDownload = ({ fileName, gridColumns, excelDatas, isDisabled = true })
);
};
ExcelDownload.propTypes = {
ExcelDownloadGrid.propTypes = {
fileName: PropTypes.string.isRequired,
gridColumns: PropTypes.array.isRequired,
excelDatas: PropTypes.array.isRequired,
isDisabled: PropTypes.bool.isRequired
};
export default ExcelDownload;
export default ExcelDownloadGrid;

@ -14,7 +14,14 @@ const FileForm = ({
const onChangeFile = (e) => {
const file = e.target.files[0];
if (file.type.includes('image')) {
alert.show(<img alt={`${file.name}`} src={URL.createObjectURL(file)} style={{ margin: 'auto' }} />);
alert.show(
<img
alt={`${file.name}`}
style={{ maxWidth: '400px', maxHeight: '400px', margin: 'auto' }}
resizemode="contain"
src={URL.createObjectURL(file)}
/>
);
}
handleChangeFile(file);
};

@ -7,7 +7,9 @@ const ImageFileInputForms = ({ fieldName, index, labelName, selectedFile, fileNa
const onChangeFile = (e) => {
const file = e.target.files[0];
if (file.type.includes('image')) {
alert.show(<img alt={`${file.name}`} src={URL.createObjectURL(file)} style={{ margin: 'auto' }} />);
alert.show(
<img alt={`${file.name}`} style={{ maxWidth: '400px', maxHeight: '400px', margin: 'auto' }} src={URL.createObjectURL(file)} />
);
}
handleChangeFile(e);
};

@ -1,7 +1,7 @@
import { useEffect, useState, useCallback } from 'react';
// material-ui
import { Card, CardContent, Grid, Link, Typography } from '@mui/material';
import { Card, CardContent, Grid, Typography } from '@mui/material';
import PlaylistAddCheckIcon from '@mui/icons-material/PlaylistAddCheck';
// project imports
@ -12,10 +12,12 @@ import { IconFileText } from '@tabler/icons';
import { useTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import { useAlert } from 'react-alert';
import useAuth from 'hooks/useAuth';
// ==============================|| DEFAULT DASHBOARD ||============================== //
const Dashboard = () => {
const { accesstype } = useAuth();
const theme = useTheme();
const showAlert = useAlert();
const [totalCount, setTotalCount] = useState(0);
@ -66,12 +68,7 @@ const Dashboard = () => {
headerName: '제목',
headerAlign: 'center',
field: 'inTitle',
width: 400,
renderCell: (params) => (
<Link underline="hover" href="#">
{params.value}
</Link>
)
width: 400
},
{
headerName: '첨부파일',
@ -136,8 +133,8 @@ const Dashboard = () => {
// size: rowsState.pageSize
// };
findDashboard().then((res) => {
console.log(res);
findDashboard({ accesstype }).then((res) => {
// console.log(res);
if (res && res?.success) {
const rows = res.data?.pBoardList.content.map((d, idx) => ({ ...d, rowId: idx + 1 }));
setTotalCount(rows.count);

@ -62,13 +62,13 @@ const FirebaseLogin = ({ loginProp, ...others }) => {
<Formik
initialValues={{
userid: 'xitdev',
passwd: 'xitdev',
userid: '',
passwd: '',
submit: null
}}
validationSchema={Yup.object().shape({
userid: Yup.string().max(255).required('User ID is required'),
passwd: Yup.string().max(255).required('Password is required')
userid: Yup.string().max(255).required('사용자ID는 필수값 입니다'),
passwd: Yup.string().max(255).required('비밀번호는 필수값 입니다')
})}
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
try {

@ -1,20 +0,0 @@
// material-ui
import { Typography } from '@mui/material';
// project imports
import MainCard from 'ui-component/cards/MainCard';
// ==============================|| SAMPLE PAGE ||============================== //
const SamplePage = () => (
<MainCard title="Sample Card">
<Typography variant="body2">
Lorem ipsum dolor sit amen, consenter nipissing eli, sed do elusion tempos incident ut laborers et doolie magna alissa. Ut enif ad
minim venice, quin nostrum exercitation illampu laborings nisi ut liquid ex ea commons construal. Duos aube grue dolor in reprehended
in voltage veil esse colum doolie eu fujian bulla parian. Exceptive sin ocean cuspidate non president, sunk in culpa qui officiate
descent molls anim id est labours.
</Typography>
</MainCard>
);
export default SamplePage;
Loading…
Cancel
Save