# Conflicts: # src/routes/GLDUserRoutes.jsmaster
@@ -149,6 +149,9 @@ function Header(props) { | |||||
<li> | <li> | ||||
<Link className="holidaySetting" to='/setting/holiday'><Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>Holiday Setting</Typography></Link> | <Link className="holidaySetting" to='/setting/holiday'><Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>Holiday Setting</Typography></Link> | ||||
</li> | </li> | ||||
<li> | |||||
<Link className="holidaySetting" to='/setting/drImport'><Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>DR Import</Typography></Link> | |||||
</li> | |||||
<li> | <li> | ||||
<Link className="announcement" to='/setting/announcement'><Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>Announcement</Typography></Link> | <Link className="announcement" to='/setting/announcement'><Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>Announcement</Typography></Link> | ||||
</li> | </li> | ||||
@@ -21,7 +21,7 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||||
width: 250, | width: 250, | ||||
cellClassName: 'announceDate', | cellClassName: 'announceDate', | ||||
renderCell: (params) => { | renderCell: (params) => { | ||||
return DateUtils.datetimeStr(params?.value); | |||||
return DateUtils.dateStr(params?.value); | |||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
@@ -70,7 +70,7 @@ const Index = () => { | |||||
<div style={BackgroundHead}> | <div style={BackgroundHead}> | ||||
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center"> | <Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center"> | ||||
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}> | <Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}> | ||||
<FormattedMessage id="paymentHistory"/> | |||||
<FormattedMessage id="systemMessage"/> | |||||
</Typography> | </Typography> | ||||
</Stack> | </Stack> | ||||
</div> | </div> | ||||
@@ -0,0 +1,204 @@ | |||||
import * as React from "react"; | |||||
import * as HttpUtils from "utils/HttpUtils"; | |||||
import * as DateUtils from "utils/DateUtils"; | |||||
import * as UrlUtils from "utils/ApiPathConst"; | |||||
import { | |||||
Grid, Typography, Button, | |||||
Stack, Box, | |||||
Dialog, DialogTitle, DialogContent, DialogActions, | |||||
} from '@mui/material'; | |||||
import { notifyDownloadSuccess } from 'utils/CommonFunction'; | |||||
import { FormattedMessage, useIntl } from "react-intl"; | |||||
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | |||||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | |||||
const Index = () => { | |||||
const [isWarningPopUp, setIsWarningPopUp] = React.useState(false); | |||||
const [warningText, setWarningText] = React.useState(""); | |||||
const [resultStr, setResultStr] = React.useState(""); | |||||
const [wait, setWait] = React.useState(false); | |||||
const intl = useIntl(); | |||||
const BackgroundHead = { | |||||
backgroundImage: `url(${titleBackgroundImg})`, | |||||
width: 'auto', | |||||
height: 'auto', | |||||
backgroundSize: 'contain', | |||||
backgroundRepeat: 'no-repeat', | |||||
backgroundColor: '#0C489E', | |||||
backgroundPosition: 'right' | |||||
} | |||||
const readFile = (event) => { | |||||
let file = event.target.files[0]; | |||||
setWait(true); | |||||
if (file) { | |||||
if (file.name.toLowerCase().substr(file.name.length - 5).includes(".xlsx") | |||||
) { | |||||
HttpUtils.postWithFiles({ | |||||
url: UrlUtils.DR_IMPORT, | |||||
params:null, | |||||
files: [event.target.files[0]], | |||||
onSuccess: function (responData) { | |||||
setWait(false); | |||||
if(responData?.msg){ | |||||
setResultStr(<>{DateUtils.datetimeStr(new Date())}<br/><span style={{"color": "red"}}>Error</span><br/><span style={{"whiteSpace": "pre-line"}}>{responData?.msg}</span></>) | |||||
}else if(responData?.success){ | |||||
setResultStr(<>{DateUtils.datetimeStr(new Date())}<br/><span style={{"color": "green"}}>Success</span><br/>Record Count: {responData.recordCount}</>) | |||||
} | |||||
}, | |||||
onError: function(){ | |||||
setWait(false); | |||||
setResultStr(<>{DateUtils.datetimeStr(new Date())}<br/><span style={{"color": "red"}}>Error</span><br/>Action Fail: Please import valid file.</>) | |||||
} | |||||
}); | |||||
} else { | |||||
setWait(false); | |||||
setWarningText("Please upload a valid file (file format: .xlsx)"); | |||||
setIsWarningPopUp(true); | |||||
document.getElementById("uploadFileBtn").value = ""; | |||||
return; | |||||
} | |||||
}else{ | |||||
setWait(false); | |||||
} | |||||
document.getElementById("uploadFileBtn").value = ""; | |||||
} | |||||
return ( | |||||
<Grid container sx={{ minHeight: '87vh', backgroundColor: 'backgroundColor.default' }} direction="column" alignItems="center"> | |||||
<Grid item xs={12} md={12} width="100%" > | |||||
<div style={BackgroundHead}> | |||||
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center"> | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}> | |||||
DR Import | |||||
</Typography> | |||||
</Stack> | |||||
</div> | |||||
</Grid> | |||||
<Grid item xs={12} md={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1, }} width="98%"> | |||||
<Box xs={12} md={12} sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}> | |||||
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center"> | |||||
<Button | |||||
aria-label={intl.formatMessage({ id: 'uploadFileBtn' })} | |||||
component="span" | |||||
variant="outlined" | |||||
size="large" | |||||
onClick={()=>{ | |||||
HttpUtils.fileDownload({ | |||||
url: UrlUtils.DR_EXPORT, | |||||
onSuccess: ()=>{ | |||||
notifyDownloadSuccess(); | |||||
} | |||||
}); | |||||
}} | |||||
>Export DR Excel</Button> | |||||
<Grid item sx={{ pl: 4 }}> | |||||
<Grid container direction="row" justifyContent="flex-start" alignItems="center"> | |||||
<Grid item xs={12} md={6} lg={6} sx={{ wordBreak: 'break-word' }}> | |||||
<input | |||||
id="uploadFileBtn" | |||||
name="file" | |||||
type="file" | |||||
accept=".xlsx" | |||||
style={{ display: 'none' }} | |||||
onChange={(event) => { | |||||
readFile(event) | |||||
}} | |||||
/> | |||||
</Grid> | |||||
</Grid> | |||||
</Grid> | |||||
<Grid item > | |||||
<Grid container direction="row" justifyContent="flex-start" alignItems="center"> | |||||
<Grid item xs={12} > | |||||
<label htmlFor="uploadFileBtn"> | |||||
<Button | |||||
aria-label={intl.formatMessage({ id: 'uploadFileBtn' })} | |||||
component="span" | |||||
variant="outlined" | |||||
size="large" | |||||
>Import DR Excel</Button> | |||||
</label> | |||||
</Grid> | |||||
</Grid> | |||||
</Grid> | |||||
</Stack> | |||||
</Box> | |||||
</Grid> | |||||
<Grid item xs={12} md={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1, }} width="98%" > | |||||
<Box xs={12} md={12} sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}> | |||||
<Typography variant="h4">Result:</Typography> | |||||
<Box xs={12} md={12} sx={{ pl: 4 }}> | |||||
{resultStr} | |||||
</Box> | |||||
</Box> | |||||
</Grid> | |||||
<div> | |||||
<Dialog | |||||
open={isWarningPopUp} | |||||
onClose={() => setIsWarningPopUp(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle> | |||||
Action Fail | |||||
</DialogTitle> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Typography variant="h3" style={{ padding: '16px' }}>{warningText}</Typography> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button | |||||
aria-label={intl.formatMessage({ id: 'ok' })} | |||||
onClick={() => { setIsWarningPopUp(false); }} | |||||
> | |||||
<FormattedMessage id="ok" /> | |||||
</Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
<div> | |||||
<Dialog | |||||
open={wait} | |||||
onClose={() => setWait(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Typography variant="h4" style={{ padding: '16px' }}>Please wait ...</Typography> | |||||
</DialogContent> | |||||
</Dialog> | |||||
</div> | |||||
</Grid> | |||||
); | |||||
}; | |||||
export default Index; |
@@ -33,7 +33,7 @@ const SearchDemandNoteForm = () => { | |||||
list.push( | list.push( | ||||
<Stack direction="column" > | <Stack direction="column" > | ||||
<Typography variant='h4' align="justify"><b>{locale === 'en' ?item.subjectEng:locale === 'zh-HK' ?item.subjectCht:item.subjectChs}</b></Typography> | <Typography variant='h4' align="justify"><b>{locale === 'en' ?item.subjectEng:locale === 'zh-HK' ?item.subjectCht:item.subjectChs}</b></Typography> | ||||
<Typography align="justify">{DateUtils.datetimeStr(item.announceDate)}</Typography> | |||||
<Typography align="justify">{DateUtils.dateStr(item.announceDate)}</Typography> | |||||
<Typography align="justify"sx={{ pt: 1 }}>{locale === 'en' ?item.contentEng:locale === 'zh-HK' ?item.contentCht:item.contentChs}</Typography> | <Typography align="justify"sx={{ pt: 1 }}>{locale === 'en' ?item.contentEng:locale === 'zh-HK' ?item.contentCht:item.contentChs}</Typography> | ||||
<Divider fullWidth sx={{ pt: 1 }}></Divider> | <Divider fullWidth sx={{ pt: 1 }}></Divider> | ||||
</Stack> | </Stack> | ||||
@@ -26,6 +26,7 @@ const EmailTemplatePage = Loadable(lazy(() => import('pages/EmailTemplate/Search | |||||
const EmailTemplateDetailPage = Loadable(lazy(() => import('pages/EmailTemplate/Detail_GLD'))); | const EmailTemplateDetailPage = Loadable(lazy(() => import('pages/EmailTemplate/Detail_GLD'))); | ||||
const HolidayPage = Loadable(lazy(() => import('pages/Holiday'))); | const HolidayPage = Loadable(lazy(() => import('pages/Holiday'))); | ||||
const GazetteIssuePage = Loadable(lazy(() => import('pages/GazetteIssue/index'))); | const GazetteIssuePage = Loadable(lazy(() => import('pages/GazetteIssue/index'))); | ||||
const DrImport = Loadable(lazy(() => import('pages/Setting/DrImport'))); | |||||
// ==============================|| MAIN ROUTING ||============================== // | // ==============================|| MAIN ROUTING ||============================== // | ||||
@@ -120,6 +121,10 @@ const GLDUserRoutes = { | |||||
path: '/setting/gazetteissuepage', | path: '/setting/gazetteissuepage', | ||||
element: <GazetteIssuePage/> | element: <GazetteIssuePage/> | ||||
}, | }, | ||||
{ | |||||
path: '/setting/drImport', | |||||
element: <DrImport /> | |||||
}, | |||||
] | ] | ||||
}, | }, | ||||
] | ] | ||||
@@ -67,6 +67,11 @@ export const POST_FILE_LIST = apiPath+'/file/list'; | |||||
export const GET_FILE_DELETE = apiPath+'/file/delete'; | export const GET_FILE_DELETE = apiPath+'/file/delete'; | ||||
//export const FILE_DOWN_GET = ({id,skey,filename})=>{ return apiPath+'/file/dl/'+id+'/'+skey+'/'+filename}; | //export const FILE_DOWN_GET = ({id,skey,filename})=>{ return apiPath+'/file/dl/'+id+'/'+skey+'/'+filename}; | ||||
export const DR_EXPORT = apiPath+'/settings/dr/export'; | |||||
export const DR_IMPORT = apiPath+'/settings/dr/import'; | |||||
// POST request | // POST request | ||||
//Login | //Login | ||||
export const POST_LOGIN = '/login'; | export const POST_LOGIN = '/login'; | ||||
@@ -1,109 +1,110 @@ | |||||
import axios from "axios"; | import axios from "axios"; | ||||
import {FILE_UP_POST, FILE_DOWN_GET} from "../utils/ApiPathConst"; | |||||
import { FILE_UP_POST, FILE_DOWN_GET } from "../utils/ApiPathConst"; | |||||
export const get = ({url, params, onSuccess, onFail, onError}) =>{ | |||||
axios.get(url,{ | |||||
export const get = ({ url, params, onSuccess, onFail, onError }) => { | |||||
axios.get(url, { | |||||
params: params | params: params | ||||
}).then( | }).then( | ||||
(response)=>{onResponse(response, onSuccess, onFail);} | |||||
(response) => { onResponse(response, onSuccess, onFail); } | |||||
).catch(error => { | ).catch(error => { | ||||
return handleError(error,onError); | |||||
return handleError(error, onError); | |||||
}); | }); | ||||
}; | }; | ||||
//TODO | //TODO | ||||
export const put = ({url,params, onSuccess, onFail, onError}) =>{ | |||||
axios.put(url,params).then( | |||||
(response)=>{onResponse(response, onSuccess, onFail);} | |||||
export const put = ({ url, params, onSuccess, onFail, onError }) => { | |||||
axios.put(url, params).then( | |||||
(response) => { onResponse(response, onSuccess, onFail); } | |||||
).catch(error => { | ).catch(error => { | ||||
return handleError(error,onError); | |||||
return handleError(error, onError); | |||||
}); | }); | ||||
}; | }; | ||||
export const patch = ({url,params, onSuccess, onFail, onError}) =>{ | |||||
axios.patch(url,params).then( | |||||
(response)=>{onResponse(response, onSuccess, onFail);} | |||||
export const patch = ({ url, params, onSuccess, onFail, onError }) => { | |||||
axios.patch(url, params).then( | |||||
(response) => { onResponse(response, onSuccess, onFail); } | |||||
).catch(error => { | ).catch(error => { | ||||
return handleError(error,onError); | |||||
return handleError(error, onError); | |||||
}); | }); | ||||
}; | }; | ||||
export const post = ({url, params, onSuccess, onFail, onError, headers}) =>{ | |||||
headers = headers?headers:{ | |||||
"Content-Type":"application/json" | |||||
export const post = ({ url, params, onSuccess, onFail, onError, headers }) => { | |||||
headers = headers ? headers : { | |||||
"Content-Type": "application/json" | |||||
}; | }; | ||||
axios.post(url,params, | |||||
axios.post(url, params, | |||||
{ | { | ||||
headers:headers | |||||
headers: headers | |||||
}).then( | }).then( | ||||
(response)=>{onResponse(response, onSuccess, onFail);} | |||||
).catch(error => { | |||||
return handleError(error,onError); | |||||
}); | |||||
(response) => { onResponse(response, onSuccess, onFail); } | |||||
).catch(error => { | |||||
return handleError(error, onError); | |||||
}); | |||||
}; | }; | ||||
export const postWithFiles = ({url, params, files, onSuccess, onFail, onError}) =>{ | |||||
export const postWithFiles = ({ url, params, files, onSuccess, onFail, onError }) => { | |||||
var formData = new FormData(); | var formData = new FormData(); | ||||
for (let i = 0; i < files.length; i++){ | |||||
for (let i = 0; i < files.length; i++) { | |||||
const file = files[i] | const file = files[i] | ||||
formData.append("multipartFileList", file); | formData.append("multipartFileList", file); | ||||
} | } | ||||
for (var key in params) { | |||||
if(typeof(params[key]) ==='object'){ | |||||
formData.append(key, JSON.stringify(params[key])); | |||||
}else{ | |||||
formData.append(key, params[key]); | |||||
} | |||||
} | |||||
axios.post(url,formData, | |||||
{headers: {"Content-Type":"multipart/form-data"}}) | |||||
.then( | |||||
(response)=>{onResponse(response, onSuccess, onFail);} | |||||
).catch(error => { | |||||
return handleError(error,onError); | |||||
}); | |||||
if (params) | |||||
for (var key in params) { | |||||
if (typeof (params[key]) === 'object') { | |||||
formData.append(key, JSON.stringify(params[key])); | |||||
} else { | |||||
formData.append(key, params[key]); | |||||
} | |||||
} | |||||
axios.post(url, formData, | |||||
{ headers: { "Content-Type": "multipart/form-data" } }) | |||||
.then( | |||||
(response) => { onResponse(response, onSuccess, onFail); } | |||||
).catch(error => { | |||||
return handleError(error, onError); | |||||
}); | |||||
}; | }; | ||||
export const fileDownload = ({url, fileId, skey, filename, params, method, onResponse, onError}) =>{ | |||||
if(!url){ | |||||
url = FILE_DOWN_GET+"/"+fileId+"/"+skey+"/"+filename | |||||
export const fileDownload = ({ url, fileId, skey, filename, params, method, onResponse, onError }) => { | |||||
if (!url) { | |||||
url = FILE_DOWN_GET + "/" + fileId + "/" + skey + "/" + filename | |||||
} | } | ||||
if(method == 'post'){ | |||||
axios.post( url, params, | |||||
if (method == 'post') { | |||||
axios.post(url, params, | |||||
{ | { | ||||
responseType: 'blob', | responseType: 'blob', | ||||
headers:{ | |||||
"Content-Type":"application/json" | |||||
headers: { | |||||
"Content-Type": "application/json" | |||||
} | } | ||||
} | } | ||||
).then( | ).then( | ||||
(response)=>{ | |||||
(response) => { | |||||
fileDownloadResponse(response, onResponse) | fileDownloadResponse(response, onResponse) | ||||
} | } | ||||
).catch(error => { | ).catch(error => { | ||||
return handleError(error,onError); | |||||
return handleError(error, onError); | |||||
}); | }); | ||||
}else{ | |||||
axios.get( url, | |||||
} else { | |||||
axios.get(url, | |||||
{ | { | ||||
responseType: 'blob', | responseType: 'blob', | ||||
params:params | |||||
params: params | |||||
} | } | ||||
).then( | ).then( | ||||
(response)=>{ | |||||
(response) => { | |||||
fileDownloadResponse(response, onResponse) | fileDownloadResponse(response, onResponse) | ||||
} | } | ||||
).catch(error => { | ).catch(error => { | ||||
return handleError(error,onError); | |||||
return handleError(error, onError); | |||||
}); | }); | ||||
} | } | ||||
}; | }; | ||||
const fileDownloadResponse=(response, onResponse)=>{ | |||||
const fn = response.headers.get("content-disposition")?.split("filename=")[1]?.split('"')[1]?.trim()??filename; | |||||
const fileDownloadResponse = (response, onResponse) => { | |||||
const fn = response.headers.get("content-disposition")?.split("filename=")[1]?.split('"')[1]?.trim() ?? filename; | |||||
const url = URL.createObjectURL(response.data); | const url = URL.createObjectURL(response.data); | ||||
const a = document.createElement('a'); | const a = document.createElement('a'); | ||||
a.href = url; | a.href = url; | ||||
@@ -112,47 +113,47 @@ const fileDownloadResponse=(response, onResponse)=>{ | |||||
a.click(); | a.click(); | ||||
document.body.removeChild(a); | document.body.removeChild(a); | ||||
URL.revokeObjectURL(url); | URL.revokeObjectURL(url); | ||||
if(onResponse){ | |||||
if (onResponse) { | |||||
onResponse(); | onResponse(); | ||||
} | } | ||||
} | } | ||||
export const fileUpload = ({refType, refId, files, refCode, onSuccess, onFail, onError}) =>{ | |||||
export const fileUpload = ({ refType, refId, files, refCode, onSuccess, onFail, onError }) => { | |||||
postWithFiles({ | postWithFiles({ | ||||
url: FILE_UP_POST, | url: FILE_UP_POST, | ||||
params:{ | |||||
params: { | |||||
refType: refType, | refType: refType, | ||||
refId: refId, | refId: refId, | ||||
refCode: refCode | refCode: refCode | ||||
}, | }, | ||||
files: files, | files: files, | ||||
onSuccess: onSuccess, | onSuccess: onSuccess, | ||||
onFail:onFail, | |||||
onError:onError | |||||
onFail: onFail, | |||||
onError: onError | |||||
}); | }); | ||||
}; | }; | ||||
const onResponse= (response, onSuccess, onFail) =>{ | |||||
if (response.status >= 300 ||response.status < 200) { | |||||
const onResponse = (response, onSuccess, onFail) => { | |||||
if (response.status >= 300 || response.status < 200) { | |||||
console.log("onFail"); | console.log("onFail"); | ||||
if(onFail){ | |||||
if (onFail) { | |||||
onFail(response); | onFail(response); | ||||
}else{ | |||||
} else { | |||||
console.log(response); | console.log(response); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if(onSuccess){ | |||||
if (onSuccess) { | |||||
onSuccess(response?.data); | onSuccess(response?.data); | ||||
} | } | ||||
} | } | ||||
const handleError= (error, onError) =>{ | |||||
if(onError){ | |||||
const handleError = (error, onError) => { | |||||
if (onError) { | |||||
return onError(error); | return onError(error); | ||||
}else{ | |||||
} else { | |||||
console.log(error); | console.log(error); | ||||
return false; | return false; | ||||
} | } |