@@ -207,7 +207,7 @@ const FormPanel = ({ formData }) => { | |||||
<Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
<Stack direction="row" sx={{ display: 'flex', alignItems: 'center' }}> | <Stack direction="row" sx={{ display: 'flex', alignItems: 'center' }}> | ||||
<FormLabel sx={{ paddingRight: 2, textAlign: "center" }}> | <FormLabel sx={{ paddingRight: 2, textAlign: "center" }}> | ||||
<Typography variant="h5">Deadline for proof with revison:</Typography> | |||||
<Typography variant="h5">Deadline for online proof with revison:</Typography> | |||||
</FormLabel> | </FormLabel> | ||||
<TextField | <TextField | ||||
fullWidth | fullWidth | ||||
@@ -234,7 +234,7 @@ const FormPanel = ({ formData }) => { | |||||
<Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
<Stack direction="row" sx={{ display: 'flex', alignItems: 'center' }}> | <Stack direction="row" sx={{ display: 'flex', alignItems: 'center' }}> | ||||
<FormLabel sx={{ paddingRight: 2, textAlign: "center" }}> | <FormLabel sx={{ paddingRight: 2, textAlign: "center" }}> | ||||
<Typography variant="h5">Deadline for confirm proof and payment:</Typography> | |||||
<Typography variant="h5">Deadline for online confirm proof:</Typography> | |||||
</FormLabel> | </FormLabel> | ||||
<TextField | <TextField | ||||
fullWidth | fullWidth | ||||
@@ -7,15 +7,12 @@ import { | |||||
Dialog, DialogTitle, DialogContent, DialogActions | Dialog, DialogTitle, DialogContent, DialogActions | ||||
} from '@mui/material'; | } from '@mui/material'; | ||||
import * as UrlUtils from "utils/ApiPathConst"; | import * as UrlUtils from "utils/ApiPathConst"; | ||||
import * as React from "react"; | |||||
import { useState } from "react"; | |||||
import * as HttpUtils from "utils/HttpUtils"; | import * as HttpUtils from "utils/HttpUtils"; | ||||
import { useParams } from "react-router-dom"; | |||||
import { useNavigate } from "react-router-dom"; | import { useNavigate } from "react-router-dom"; | ||||
import * as DateUtils from "utils/DateUtils" | import * as DateUtils from "utils/DateUtils" | ||||
import * as FormatUtils from "utils/FormatUtils"; | import * as FormatUtils from "utils/FormatUtils"; | ||||
import Loadable from 'components/Loadable'; | |||||
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent'))); | |||||
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | ||||
const BackgroundHead = { | const BackgroundHead = { | ||||
@@ -28,55 +25,20 @@ const BackgroundHead = { | |||||
backgroundPosition: 'right' | backgroundPosition: 'right' | ||||
} | } | ||||
import { | |||||
// useEffect, | |||||
useState | |||||
} from "react"; | |||||
import { PNSPS_BUTTON_THEME, PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst"; | import { PNSPS_BUTTON_THEME, PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst"; | ||||
import { ThemeProvider } from "@emotion/react"; | import { ThemeProvider } from "@emotion/react"; | ||||
import { FormattedMessage, useIntl } from "react-intl"; | import { FormattedMessage, useIntl } from "react-intl"; | ||||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | // ==============================|| DASHBOARD - DEFAULT ||============================== // | ||||
const Index = () => { | |||||
const params = useParams(); | |||||
const Index = ({ record }) => { | |||||
const navigate = useNavigate() | const navigate = useNavigate() | ||||
const [fee, setFee] = useState(0); | |||||
const [record, setRecord] = React.useState({}); | |||||
const [onReady, setOnReady] = React.useState(false); | |||||
const [isPopUp, setIsPopUp] = useState(false); | const [isPopUp, setIsPopUp] = useState(false); | ||||
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState(""); | |||||
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false); | |||||
const [paymentHoldedErrText, setPaymentHoldedErrText] = useState(""); | |||||
const [paymentHoldedErr, setPaymentHoldedErr] = useState(false); | |||||
const intl = useIntl(); | const intl = useIntl(); | ||||
React.useEffect(() => { | |||||
loadForm(); | |||||
}, []); | |||||
React.useEffect(() => { | |||||
setOnReady(true); | |||||
}, [record]); | |||||
const loadForm = () => { | |||||
if (params.id > 0) { | |||||
HttpUtils.get({ | |||||
url: UrlUtils.GET_PROOF_PAY + "/" + params.id, | |||||
onSuccess: (responseData) => { | |||||
// if (!responseData.data?.id) { | |||||
// navigate("/proof/search"); | |||||
// } | |||||
setRecord(responseData.data); | |||||
setFee(responseData.data.fee); | |||||
}, | |||||
onError: () => { | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
function doPayment() { | function doPayment() { | ||||
setIsPopUp(false); | setIsPopUp(false); | ||||
let appIdList = [record?.appId] | let appIdList = [record?.appId] | ||||
@@ -93,23 +55,23 @@ const Index = () => { | |||||
const latestData = {}; | const latestData = {}; | ||||
responseData.forEach(item => { | responseData.forEach(item => { | ||||
const { appId, timeDiff } = item; | |||||
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) { | |||||
latestData[appId] = item; | |||||
} | |||||
const { appId, timeDiff } = item; | |||||
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) { | |||||
latestData[appId] = item; | |||||
} | |||||
}); | }); | ||||
const latestDataObjects = Object.values(latestData); | const latestDataObjects = Object.values(latestData); | ||||
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 || item.status !== "APPR"); | const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 || item.status !== "APPR"); | ||||
const filteredAppIds = filteredData.map(item => item.appId); | const filteredAppIds = filteredData.map(item => item.appId); | ||||
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId)); | const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId)); | ||||
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds]; | const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds]; | ||||
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId)); | const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId)); | ||||
if (readyToPayment){ | |||||
navigate('/paymentPage', { state: { amount: fee, appIdList: appIdList } }); | |||||
}else{ | |||||
if (readyToPayment) { | |||||
navigate('/paymentPage', { state: { amount: record.fee, appIdList: appIdList } }); | |||||
} else { | |||||
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId)); | const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId)); | ||||
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId)); | const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId)); | ||||
const resultString = HoldingApplication.map(item => item.appNo).join(' , '); | const resultString = HoldingApplication.map(item => item.appNo).join(' , '); | ||||
@@ -122,156 +84,149 @@ const Index = () => { | |||||
}; | }; | ||||
return ( | return ( | ||||
!onReady ? | |||||
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||||
<Grid item> | |||||
<LoadingComponent /> | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px'> | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' }, pt: 2 }}> | |||||
<FormattedMessage id="proofRecord" /> | |||||
</Typography> | |||||
</Stack> | |||||
</div> | |||||
</Grid> | </Grid> | ||||
</Grid> | |||||
: | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px'> | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' }, pt: 2 }}> | |||||
<FormattedMessage id="proofRecord" /> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h3" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDoneAndPaid" /> | |||||
</Typography> | </Typography> | ||||
</Stack> | |||||
</div> | |||||
</Grid> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h3" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDoneAndPaid" /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.payMsg1' }, { appNo: record.appNo }) }} /> | |||||
<br /> | |||||
<FormattedMessage id="MSG.payMsg2_1" /> | |||||
<span style={{ color: "red" }}> | |||||
{DateUtils.datetimeStr(record?.proofPaymentDeadline)} | |||||
</span> | |||||
<FormattedMessage id="MSG.payMsg2_2" /> | |||||
<br /> | |||||
<br /> | |||||
<div dangerouslySetInnerHTML={{ | |||||
__html: intl.formatMessage({ id: 'MSG.payMsg3' }, | |||||
{ | |||||
issueYear: record?.issueYear, | |||||
issueVolume: record?.issueVolume, | |||||
issueNo: record?.issueNo, | |||||
}) | |||||
}} /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage id="pleaseClickToPay" />: | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, textAlign: "left" }}> | |||||
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { md: 4, lg: 4 }, mr: 4 }} | |||||
onClick={() => { setIsPopUp(true) }} | |||||
> | |||||
<FormattedMessage id="payInstantly" /> | |||||
</Button> | |||||
</ThemeProvider> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.payMsg1' }, { appNo: record.appNo }) }} /> | |||||
<br /> | |||||
<FormattedMessage id="MSG.payMsg2_1" /> | |||||
<span style={{ color: "red" }}> | |||||
{DateUtils.datetimeStr(record?.proofPaymentDeadline)} | |||||
</span> | |||||
<FormattedMessage id="MSG.payMsg2_2" /> | |||||
<br /> | |||||
<br /> | |||||
<div dangerouslySetInnerHTML={{ | |||||
__html: intl.formatMessage({ id: 'MSG.payMsg3' }, | |||||
{ | |||||
issueYear: record?.issueYear, | |||||
issueVolume: record?.issueVolume, | |||||
issueNo: record?.issueNo, | |||||
}) | |||||
}} /> | |||||
</Typography> | |||||
<FormattedMessage id="or" /> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage id="pleaseClickToPay" />: | |||||
</Typography> | |||||
<ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { sm: 4, md: 4, lg: 4 }, mr: 4, mt: { xs: 2, sm: 2 }, mb: { xs: 2, sm: 2 } }} | |||||
onClick={() => { | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="payLater" /> | |||||
</Button> | |||||
(<FormattedMessage id="backToNoticePage" />) | |||||
</ThemeProvider> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | |||||
<Typography variant="h4" sx={{ ml: 8, textAlign: "left" }}> | |||||
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { md: 4, lg: 4 }, mr: 4 }} | |||||
onClick={() => { setIsPopUp(true) }} | |||||
> | |||||
<FormattedMessage id="payInstantly" /> | |||||
</Button> | |||||
</ThemeProvider> | |||||
<FormattedMessage id="or" /> | |||||
<ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { sm: 4, md: 4, lg: 4 }, mr: 4, mt: { xs: 2, sm: 2 }, mb: { xs: 2, sm: 2 } }} | |||||
onClick={() => { | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="payLater" /> | |||||
</Button> | |||||
(<FormattedMessage id="backToNoticePage" />) | |||||
</ThemeProvider> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | </Grid> | ||||
<div> | |||||
<Dialog | |||||
open={isPopUp} | |||||
onClose={() => setIsPopUp(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '30vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '50vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle> | |||||
<Typography variant="h3" > | |||||
<FormattedMessage id="payConfirm" /> | |||||
</Grid> | |||||
<div> | |||||
<Dialog | |||||
open={isPopUp} | |||||
onClose={() => setIsPopUp(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '30vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '50vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle> | |||||
<Typography variant="h3" > | |||||
<FormattedMessage id="payConfirm" /> | |||||
</Typography> | |||||
</DialogTitle> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<Typography variant="h4"> | |||||
<FormattedMessage id="totalAmount" /> (HK$): {FormatUtils.currencyFormat(record.fee)} | |||||
</Typography> | </Typography> | ||||
</DialogTitle> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<Typography variant="h4"> | |||||
<FormattedMessage id="totalAmount" /> (HK$): {FormatUtils.currencyFormat(fee)} | |||||
</Typography> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setIsPopUp(false)}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
<Button onClick={() => doPayment()}><Typography variant="h5"> | |||||
<FormattedMessage id="confirm" /> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setIsPopUp(false)}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | </Typography></Button> | ||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
{/*row 2*/} | |||||
<div> | |||||
<Dialog | |||||
open={paymentHoldedErr} | |||||
onClose={() => setPaymentHoldedErr(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle></DialogTitle> | |||||
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} /> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
</Grid > | |||||
<Button onClick={() => doPayment()}><Typography variant="h5"> | |||||
<FormattedMessage id="confirm" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
{/*row 2*/} | |||||
<div> | |||||
<Dialog | |||||
open={paymentHoldedErr} | |||||
onClose={() => setPaymentHoldedErr(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle></DialogTitle> | |||||
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} /> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
</Grid > | |||||
) | |||||
) | |||||
); | ); | ||||
@@ -5,17 +5,10 @@ import { | |||||
Stack, | Stack, | ||||
Button, | Button, | ||||
} from '@mui/material'; | } from '@mui/material'; | ||||
import * as UrlUtils from "utils/ApiPathConst"; | |||||
import * as React from "react"; | |||||
import * as HttpUtils from "utils/HttpUtils"; | |||||
import { useParams } from "react-router-dom"; | |||||
import { useNavigate } from "react-router-dom"; | import { useNavigate } from "react-router-dom"; | ||||
import Loadable from 'components/Loadable'; | |||||
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent'))); | |||||
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | ||||
import {FormattedMessage} from "react-intl"; | |||||
import { FormattedMessage } from "react-intl"; | |||||
const BackgroundHead = { | const BackgroundHead = { | ||||
backgroundImage: `url(${titleBackgroundImg})`, | backgroundImage: `url(${titleBackgroundImg})`, | ||||
width: '100%', | width: '100%', | ||||
@@ -28,101 +21,67 @@ const BackgroundHead = { | |||||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | // ==============================|| DASHBOARD - DEFAULT ||============================== // | ||||
const Index = () => { | |||||
const params = useParams(); | |||||
const Index = ({ record }) => { | |||||
const navigate = useNavigate() | const navigate = useNavigate() | ||||
const [record, setRecord] = React.useState(); | |||||
const [onReady, setOnReady] = React.useState(false); | |||||
React.useEffect(() => { | |||||
loadForm(); | |||||
}, []); | |||||
React.useEffect(() => { | |||||
setOnReady(true); | |||||
}, [record]); | |||||
const loadForm = () => { | |||||
if (params.id > 0) { | |||||
HttpUtils.get({ | |||||
url: UrlUtils.GET_PROOF_PAY + "/" + params.id, | |||||
onSuccess: (responseData) => { | |||||
if (!responseData.data?.id) { | |||||
navigate("/proof/search"); | |||||
} | |||||
setRecord(responseData.data); | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
return ( | return ( | ||||
!onReady ? | |||||
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||||
<Grid item> | |||||
<LoadingComponent /> | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px' > | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' }, pt: 2 }} > | |||||
<FormattedMessage id="proofRecord" /> | |||||
</Typography> | |||||
</Stack> | |||||
</div> | |||||
</Grid> | </Grid> | ||||
</Grid> | |||||
: | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px' > | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }, pt:2}} > | |||||
<FormattedMessage id="proofRecord"/> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h2" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDone" /> | |||||
</Typography> | </Typography> | ||||
</Stack> | |||||
</div> | |||||
</Grid> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h2" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDone"/> | |||||
</Typography> | |||||
<Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage | |||||
<Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage | |||||
id='MSG.pay_credity1' | id='MSG.pay_credity1' | ||||
values={{ | values={{ | ||||
appNo: record?.appNo, | appNo: record?.appNo, | ||||
year: record?.issueYear, | year: record?.issueYear, | ||||
issueVolume: record?.issueVolume, | |||||
issueVolume: record?.issueVolume, | |||||
issueNo: record?.issueNo | issueNo: record?.issueNo | ||||
}} | }} | ||||
/> | /> | ||||
<br/><br/> | |||||
<FormattedMessage id="MSG.pay_credity2"/> | |||||
<br /><br /> | |||||
<FormattedMessage id="MSG.pay_credity2" /> | |||||
</Typography> | </Typography> | ||||
<Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
size="large" | |||||
sx={{ m: 4}} | |||||
onClick={()=>{ | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="backToNoticePage" /> | |||||
</Button> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | |||||
<Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
size="large" | |||||
sx={{ m: 4 }} | |||||
onClick={() => { | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="backToNoticePage" /> | |||||
</Button> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | </Grid> | ||||
{/*row 2*/} | |||||
</Grid > | |||||
</Grid> | |||||
{/*row 2*/} | |||||
</Grid > | |||||
) | |||||
) | |||||
); | ); | ||||
@@ -0,0 +1,280 @@ | |||||
// material-ui | |||||
import { | |||||
Grid, | |||||
Typography, | |||||
Stack, | |||||
Button, | |||||
Dialog, DialogTitle, DialogContent, DialogActions | |||||
} from '@mui/material'; | |||||
import * as UrlUtils from "utils/ApiPathConst"; | |||||
import * as React from "react"; | |||||
import * as HttpUtils from "utils/HttpUtils"; | |||||
import { useParams } from "react-router-dom"; | |||||
import { useNavigate } from "react-router-dom"; | |||||
import * as DateUtils from "utils/DateUtils" | |||||
import * as FormatUtils from "utils/FormatUtils"; | |||||
import Loadable from 'components/Loadable'; | |||||
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent'))); | |||||
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | |||||
const BackgroundHead = { | |||||
backgroundImage: `url(${titleBackgroundImg})`, | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundSize: 'contain', | |||||
backgroundRepeat: 'no-repeat', | |||||
backgroundColor: '#0C489E', | |||||
backgroundPosition: 'right' | |||||
} | |||||
import { | |||||
// useEffect, | |||||
useState | |||||
} from "react"; | |||||
import { PNSPS_BUTTON_THEME, PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst"; | |||||
import { ThemeProvider } from "@emotion/react"; | |||||
import { FormattedMessage, useIntl } from "react-intl"; | |||||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | |||||
const Index = () => { | |||||
const params = useParams(); | |||||
const navigate = useNavigate() | |||||
const [fee, setFee] = useState(0); | |||||
const [record, setRecord] = React.useState({}); | |||||
const [onReady, setOnReady] = React.useState(false); | |||||
const [isPopUp, setIsPopUp] = useState(false); | |||||
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState(""); | |||||
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false); | |||||
const intl = useIntl(); | |||||
React.useEffect(() => { | |||||
loadForm(); | |||||
}, []); | |||||
React.useEffect(() => { | |||||
setOnReady(true); | |||||
}, [record]); | |||||
const loadForm = () => { | |||||
if (params.id > 0) { | |||||
HttpUtils.get({ | |||||
url: UrlUtils.GET_PROOF_PAY + "/" + params.id, | |||||
onSuccess: (responseData) => { | |||||
// if (!responseData.data?.id) { | |||||
// navigate("/proof/search"); | |||||
// } | |||||
setRecord(responseData.data); | |||||
setFee(responseData.data.fee); | |||||
}, | |||||
onError: () => { | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
function doPayment() { | |||||
setIsPopUp(false); | |||||
let appIdList = [record?.appId] | |||||
handlePaymentCheck(appIdList) | |||||
} | |||||
const handlePaymentCheck = (appIdList) => { | |||||
HttpUtils.post({ | |||||
url: UrlUtils.PAYMENT_CHECK, | |||||
params: { | |||||
appIds: appIdList | |||||
}, | |||||
onSuccess: (responseData) => { | |||||
const latestData = {}; | |||||
responseData.forEach(item => { | |||||
const { appId, timeDiff } = item; | |||||
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) { | |||||
latestData[appId] = item; | |||||
} | |||||
}); | |||||
const latestDataObjects = Object.values(latestData); | |||||
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 || item.status !== "APPR"); | |||||
const filteredAppIds = filteredData.map(item => item.appId); | |||||
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId)); | |||||
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds]; | |||||
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId)); | |||||
if (readyToPayment){ | |||||
navigate('/paymentPage', { state: { amount: fee, appIdList: appIdList } }); | |||||
}else{ | |||||
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId)); | |||||
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId)); | |||||
const resultString = HoldingApplication.map(item => item.appNo).join(' , '); | |||||
setPaymentHoldedErrText(resultString); | |||||
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo })); | |||||
setPaymentHoldedErr(true); | |||||
} | |||||
} | |||||
}); | |||||
}; | |||||
return ( | |||||
!onReady ? | |||||
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||||
<Grid item> | |||||
<LoadingComponent /> | |||||
</Grid> | |||||
</Grid> | |||||
: | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px'> | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' }, pt: 2 }}> | |||||
<FormattedMessage id="proofRecord" /> | |||||
</Typography> | |||||
</Stack> | |||||
</div> | |||||
</Grid> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h3" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDoneAndPaid" /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.payMsg1' }, { appNo: record.appNo }) }} /> | |||||
<br /> | |||||
<FormattedMessage id="MSG.payMsg2_1" /> | |||||
<span style={{ color: "red" }}> | |||||
{DateUtils.datetimeStr(record?.proofPaymentDeadline)} | |||||
</span> | |||||
<FormattedMessage id="MSG.payMsg2_2" /> | |||||
<br /> | |||||
<br /> | |||||
<div dangerouslySetInnerHTML={{ | |||||
__html: intl.formatMessage({ id: 'MSG.payMsg3' }, | |||||
{ | |||||
issueYear: record?.issueYear, | |||||
issueVolume: record?.issueVolume, | |||||
issueNo: record?.issueNo, | |||||
}) | |||||
}} /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage id="pleaseClickToPay" />: | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, textAlign: "left" }}> | |||||
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { md: 4, lg: 4 }, mr: 4 }} | |||||
onClick={() => { setIsPopUp(true) }} | |||||
> | |||||
<FormattedMessage id="payInstantly" /> | |||||
</Button> | |||||
</ThemeProvider> | |||||
<FormattedMessage id="or" /> | |||||
<ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { sm: 4, md: 4, lg: 4 }, mr: 4, mt: { xs: 2, sm: 2 }, mb: { xs: 2, sm: 2 } }} | |||||
onClick={() => { | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="payLater" /> | |||||
</Button> | |||||
(<FormattedMessage id="backToNoticePage" />) | |||||
</ThemeProvider> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | |||||
</Grid> | |||||
<div> | |||||
<Dialog | |||||
open={isPopUp} | |||||
onClose={() => setIsPopUp(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '30vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '50vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle> | |||||
<Typography variant="h3" > | |||||
<FormattedMessage id="payConfirm" /> | |||||
</Typography> | |||||
</DialogTitle> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<Typography variant="h4"> | |||||
<FormattedMessage id="totalAmount" /> (HK$): {FormatUtils.currencyFormat(fee)} | |||||
</Typography> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setIsPopUp(false)}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
<Button onClick={() => doPayment()}><Typography variant="h5"> | |||||
<FormattedMessage id="confirm" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
{/*row 2*/} | |||||
<div> | |||||
<Dialog | |||||
open={paymentHoldedErr} | |||||
onClose={() => setPaymentHoldedErr(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle></DialogTitle> | |||||
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} /> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
</Grid > | |||||
) | |||||
); | |||||
}; | |||||
export default Index; |
@@ -0,0 +1,280 @@ | |||||
// material-ui | |||||
import { | |||||
Grid, | |||||
Typography, | |||||
Stack, | |||||
Button, | |||||
Dialog, DialogTitle, DialogContent, DialogActions | |||||
} from '@mui/material'; | |||||
import * as UrlUtils from "utils/ApiPathConst"; | |||||
import * as React from "react"; | |||||
import * as HttpUtils from "utils/HttpUtils"; | |||||
import { useParams } from "react-router-dom"; | |||||
import { useNavigate } from "react-router-dom"; | |||||
import * as DateUtils from "utils/DateUtils" | |||||
import * as FormatUtils from "utils/FormatUtils"; | |||||
import Loadable from 'components/Loadable'; | |||||
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent'))); | |||||
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | |||||
const BackgroundHead = { | |||||
backgroundImage: `url(${titleBackgroundImg})`, | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundSize: 'contain', | |||||
backgroundRepeat: 'no-repeat', | |||||
backgroundColor: '#0C489E', | |||||
backgroundPosition: 'right' | |||||
} | |||||
import { | |||||
// useEffect, | |||||
useState | |||||
} from "react"; | |||||
import { PNSPS_BUTTON_THEME, PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst"; | |||||
import { ThemeProvider } from "@emotion/react"; | |||||
import { FormattedMessage, useIntl } from "react-intl"; | |||||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | |||||
const Index = () => { | |||||
const params = useParams(); | |||||
const navigate = useNavigate() | |||||
const [fee, setFee] = useState(0); | |||||
const [record, setRecord] = React.useState({}); | |||||
const [onReady, setOnReady] = React.useState(false); | |||||
const [isPopUp, setIsPopUp] = useState(false); | |||||
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState(""); | |||||
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false); | |||||
const intl = useIntl(); | |||||
React.useEffect(() => { | |||||
loadForm(); | |||||
}, []); | |||||
React.useEffect(() => { | |||||
setOnReady(true); | |||||
}, [record]); | |||||
const loadForm = () => { | |||||
if (params.id > 0) { | |||||
HttpUtils.get({ | |||||
url: UrlUtils.GET_PROOF_PAY + "/" + params.id, | |||||
onSuccess: (responseData) => { | |||||
// if (!responseData.data?.id) { | |||||
// navigate("/proof/search"); | |||||
// } | |||||
setRecord(responseData.data); | |||||
setFee(responseData.data.fee); | |||||
}, | |||||
onError: () => { | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
function doPayment() { | |||||
setIsPopUp(false); | |||||
let appIdList = [record?.appId] | |||||
handlePaymentCheck(appIdList) | |||||
} | |||||
const handlePaymentCheck = (appIdList) => { | |||||
HttpUtils.post({ | |||||
url: UrlUtils.PAYMENT_CHECK, | |||||
params: { | |||||
appIds: appIdList | |||||
}, | |||||
onSuccess: (responseData) => { | |||||
const latestData = {}; | |||||
responseData.forEach(item => { | |||||
const { appId, timeDiff } = item; | |||||
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) { | |||||
latestData[appId] = item; | |||||
} | |||||
}); | |||||
const latestDataObjects = Object.values(latestData); | |||||
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 || item.status !== "APPR"); | |||||
const filteredAppIds = filteredData.map(item => item.appId); | |||||
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId)); | |||||
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds]; | |||||
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId)); | |||||
if (readyToPayment){ | |||||
navigate('/paymentPage', { state: { amount: fee, appIdList: appIdList } }); | |||||
}else{ | |||||
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId)); | |||||
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId)); | |||||
const resultString = HoldingApplication.map(item => item.appNo).join(' , '); | |||||
setPaymentHoldedErrText(resultString); | |||||
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo })); | |||||
setPaymentHoldedErr(true); | |||||
} | |||||
} | |||||
}); | |||||
}; | |||||
return ( | |||||
!onReady ? | |||||
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||||
<Grid item> | |||||
<LoadingComponent /> | |||||
</Grid> | |||||
</Grid> | |||||
: | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px'> | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' }, pt: 2 }}> | |||||
<FormattedMessage id="proofRecord" /> | |||||
</Typography> | |||||
</Stack> | |||||
</div> | |||||
</Grid> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h3" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDoneAndPaid" /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.payMsg1' }, { appNo: record.appNo }) }} /> | |||||
<br /> | |||||
<FormattedMessage id="MSG.payMsg2_1" /> | |||||
<span style={{ color: "red" }}> | |||||
{DateUtils.datetimeStr(record?.proofPaymentDeadline)} | |||||
</span> | |||||
<FormattedMessage id="MSG.payMsg2_2" /> | |||||
<br /> | |||||
<br /> | |||||
<div dangerouslySetInnerHTML={{ | |||||
__html: intl.formatMessage({ id: 'MSG.payMsg3' }, | |||||
{ | |||||
issueYear: record?.issueYear, | |||||
issueVolume: record?.issueVolume, | |||||
issueNo: record?.issueNo, | |||||
}) | |||||
}} /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage id="pleaseClickToPay" />: | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, textAlign: "left" }}> | |||||
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { md: 4, lg: 4 }, mr: 4 }} | |||||
onClick={() => { setIsPopUp(true) }} | |||||
> | |||||
<FormattedMessage id="payInstantly" /> | |||||
</Button> | |||||
</ThemeProvider> | |||||
<FormattedMessage id="or" /> | |||||
<ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { sm: 4, md: 4, lg: 4 }, mr: 4, mt: { xs: 2, sm: 2 }, mb: { xs: 2, sm: 2 } }} | |||||
onClick={() => { | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="payLater" /> | |||||
</Button> | |||||
(<FormattedMessage id="backToNoticePage" />) | |||||
</ThemeProvider> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | |||||
</Grid> | |||||
<div> | |||||
<Dialog | |||||
open={isPopUp} | |||||
onClose={() => setIsPopUp(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '30vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '50vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle> | |||||
<Typography variant="h3" > | |||||
<FormattedMessage id="payConfirm" /> | |||||
</Typography> | |||||
</DialogTitle> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<Typography variant="h4"> | |||||
<FormattedMessage id="totalAmount" /> (HK$): {FormatUtils.currencyFormat(fee)} | |||||
</Typography> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setIsPopUp(false)}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
<Button onClick={() => doPayment()}><Typography variant="h5"> | |||||
<FormattedMessage id="confirm" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
{/*row 2*/} | |||||
<div> | |||||
<Dialog | |||||
open={paymentHoldedErr} | |||||
onClose={() => setPaymentHoldedErr(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle></DialogTitle> | |||||
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} /> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
</Grid > | |||||
) | |||||
); | |||||
}; | |||||
export default Index; |
@@ -0,0 +1,280 @@ | |||||
// material-ui | |||||
import { | |||||
Grid, | |||||
Typography, | |||||
Stack, | |||||
Button, | |||||
Dialog, DialogTitle, DialogContent, DialogActions | |||||
} from '@mui/material'; | |||||
import * as UrlUtils from "utils/ApiPathConst"; | |||||
import * as React from "react"; | |||||
import * as HttpUtils from "utils/HttpUtils"; | |||||
import { useParams } from "react-router-dom"; | |||||
import { useNavigate } from "react-router-dom"; | |||||
import * as DateUtils from "utils/DateUtils" | |||||
import * as FormatUtils from "utils/FormatUtils"; | |||||
import Loadable from 'components/Loadable'; | |||||
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent'))); | |||||
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png' | |||||
const BackgroundHead = { | |||||
backgroundImage: `url(${titleBackgroundImg})`, | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundSize: 'contain', | |||||
backgroundRepeat: 'no-repeat', | |||||
backgroundColor: '#0C489E', | |||||
backgroundPosition: 'right' | |||||
} | |||||
import { | |||||
// useEffect, | |||||
useState | |||||
} from "react"; | |||||
import { PNSPS_BUTTON_THEME, PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst"; | |||||
import { ThemeProvider } from "@emotion/react"; | |||||
import { FormattedMessage, useIntl } from "react-intl"; | |||||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | |||||
const Index = () => { | |||||
const params = useParams(); | |||||
const navigate = useNavigate() | |||||
const [fee, setFee] = useState(0); | |||||
const [record, setRecord] = React.useState({}); | |||||
const [onReady, setOnReady] = React.useState(false); | |||||
const [isPopUp, setIsPopUp] = useState(false); | |||||
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState(""); | |||||
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false); | |||||
const intl = useIntl(); | |||||
React.useEffect(() => { | |||||
loadForm(); | |||||
}, []); | |||||
React.useEffect(() => { | |||||
setOnReady(true); | |||||
}, [record]); | |||||
const loadForm = () => { | |||||
if (params.id > 0) { | |||||
HttpUtils.get({ | |||||
url: UrlUtils.GET_PROOF_PAY + "/" + params.id, | |||||
onSuccess: (responseData) => { | |||||
// if (!responseData.data?.id) { | |||||
// navigate("/proof/search"); | |||||
// } | |||||
setRecord(responseData.data); | |||||
setFee(responseData.data.fee); | |||||
}, | |||||
onError: () => { | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
function doPayment() { | |||||
setIsPopUp(false); | |||||
let appIdList = [record?.appId] | |||||
handlePaymentCheck(appIdList) | |||||
} | |||||
const handlePaymentCheck = (appIdList) => { | |||||
HttpUtils.post({ | |||||
url: UrlUtils.PAYMENT_CHECK, | |||||
params: { | |||||
appIds: appIdList | |||||
}, | |||||
onSuccess: (responseData) => { | |||||
const latestData = {}; | |||||
responseData.forEach(item => { | |||||
const { appId, timeDiff } = item; | |||||
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) { | |||||
latestData[appId] = item; | |||||
} | |||||
}); | |||||
const latestDataObjects = Object.values(latestData); | |||||
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 || item.status !== "APPR"); | |||||
const filteredAppIds = filteredData.map(item => item.appId); | |||||
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId)); | |||||
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds]; | |||||
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId)); | |||||
if (readyToPayment){ | |||||
navigate('/paymentPage', { state: { amount: fee, appIdList: appIdList } }); | |||||
}else{ | |||||
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId)); | |||||
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId)); | |||||
const resultString = HoldingApplication.map(item => item.appNo).join(' , '); | |||||
setPaymentHoldedErrText(resultString); | |||||
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo })); | |||||
setPaymentHoldedErr(true); | |||||
} | |||||
} | |||||
}); | |||||
}; | |||||
return ( | |||||
!onReady ? | |||||
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||||
<Grid item> | |||||
<LoadingComponent /> | |||||
</Grid> | |||||
</Grid> | |||||
: | |||||
( | |||||
<Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" > | |||||
<Grid item xs={12} width="100%"> | |||||
<div style={BackgroundHead} width="100%" > | |||||
<Stack direction="row" height='70px'> | |||||
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' }, pt: 2 }}> | |||||
<FormattedMessage id="proofRecord" /> | |||||
</Typography> | |||||
</Stack> | |||||
</div> | |||||
</Grid> | |||||
{/*row 1*/} | |||||
<Grid item xs={12} md={12} > | |||||
<Grid container justifyContent="flex-start" alignItems="center" > | |||||
<center> | |||||
<Grid item xs={12} md={8} > | |||||
<Typography variant="h3" sx={{ textAlign: "left", ml: 4, mr: 4, mt: 4, borderBottom: "1px solid black" }}> | |||||
<FormattedMessage id="publicNoticePaymentProofDoneAndPaid" /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.payMsg1' }, { appNo: record.appNo }) }} /> | |||||
<br /> | |||||
<FormattedMessage id="MSG.payMsg2_1" /> | |||||
<span style={{ color: "red" }}> | |||||
{DateUtils.datetimeStr(record?.proofPaymentDeadline)} | |||||
</span> | |||||
<FormattedMessage id="MSG.payMsg2_2" /> | |||||
<br /> | |||||
<br /> | |||||
<div dangerouslySetInnerHTML={{ | |||||
__html: intl.formatMessage({ id: 'MSG.payMsg3' }, | |||||
{ | |||||
issueYear: record?.issueYear, | |||||
issueVolume: record?.issueVolume, | |||||
issueNo: record?.issueNo, | |||||
}) | |||||
}} /> | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "left" }}> | |||||
<FormattedMessage id="pleaseClickToPay" />: | |||||
</Typography> | |||||
<Typography variant="h4" sx={{ ml: 8, textAlign: "left" }}> | |||||
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { md: 4, lg: 4 }, mr: 4 }} | |||||
onClick={() => { setIsPopUp(true) }} | |||||
> | |||||
<FormattedMessage id="payInstantly" /> | |||||
</Button> | |||||
</ThemeProvider> | |||||
<FormattedMessage id="or" /> | |||||
<ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||||
<Button | |||||
component="span" | |||||
variant="contained" | |||||
sx={{ ml: { sm: 4, md: 4, lg: 4 }, mr: 4, mt: { xs: 2, sm: 2 }, mb: { xs: 2, sm: 2 } }} | |||||
onClick={() => { | |||||
navigate("/publicNotice"); | |||||
}} | |||||
> | |||||
<FormattedMessage id="payLater" /> | |||||
</Button> | |||||
(<FormattedMessage id="backToNoticePage" />) | |||||
</ThemeProvider> | |||||
</Typography> | |||||
</Grid> | |||||
</center> | |||||
</Grid> | |||||
</Grid> | |||||
<div> | |||||
<Dialog | |||||
open={isPopUp} | |||||
onClose={() => setIsPopUp(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '30vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '50vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle> | |||||
<Typography variant="h3" > | |||||
<FormattedMessage id="payConfirm" /> | |||||
</Typography> | |||||
</DialogTitle> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<Typography variant="h4"> | |||||
<FormattedMessage id="totalAmount" /> (HK$): {FormatUtils.currencyFormat(fee)} | |||||
</Typography> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setIsPopUp(false)}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
<Button onClick={() => doPayment()}><Typography variant="h5"> | |||||
<FormattedMessage id="confirm" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
{/*row 2*/} | |||||
<div> | |||||
<Dialog | |||||
open={paymentHoldedErr} | |||||
onClose={() => setPaymentHoldedErr(false)} | |||||
PaperProps={{ | |||||
sx: { | |||||
minWidth: '40vw', | |||||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' }, | |||||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' } | |||||
} | |||||
}} | |||||
> | |||||
<DialogTitle></DialogTitle> | |||||
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography> | |||||
<DialogContent style={{ display: 'flex', }}> | |||||
<Stack direction="column" justifyContent="space-between"> | |||||
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} /> | |||||
</Stack> | |||||
</DialogContent> | |||||
<DialogActions> | |||||
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}> | |||||
<Typography variant="h5"> | |||||
<FormattedMessage id="close" /> | |||||
</Typography></Button> | |||||
</DialogActions> | |||||
</Dialog> | |||||
</div> | |||||
</Grid > | |||||
) | |||||
); | |||||
}; | |||||
export default Index; |
@@ -1,16 +1,60 @@ | |||||
import * as React from "react"; | |||||
import { useState, useEffect, lazy } from "react"; | |||||
import Loadable from 'components/Loadable'; | import Loadable from 'components/Loadable'; | ||||
const Pay = Loadable(React.lazy(() => import('./Pay'))); | |||||
const Pay_Creditor = Loadable(React.lazy(() => import('./Pay_Creditor'))); | |||||
import { useParams } from "react-router-dom"; | |||||
//const Pay = Loadable(lazy(() => import('./Pay'))); | |||||
const Pay_Creditor = Loadable(lazy(() => import('./Pay_Creditor'))); | |||||
const Pay_Dn = Loadable(lazy(() => import('./Pay_DN'))); | |||||
const Pay_Office = Loadable(lazy(() => import('./Pay_Office'))); | |||||
const Pay_Online = Loadable(lazy(() => import('./Pay_Online'))); | |||||
const Index = () => { | const Index = () => { | ||||
const params = useParams(); | |||||
const [record, setRecord] = useState(); | |||||
useEffect(() => { | |||||
if (params.id > 0) { | |||||
HttpUtils.get({ | |||||
url: UrlUtils.GET_PROOF_PAY + "/" + params.id, | |||||
onSuccess: (responseData) => { | |||||
if (!responseData.data?.id) { | |||||
navigate("/proof/search"); | |||||
} | |||||
setRecord(responseData.data); | |||||
}, | |||||
onError: () => { | |||||
} | |||||
}); | |||||
} | |||||
}, []); | |||||
return ( | return ( | ||||
JSON.parse(localStorage.getItem('userData')).creditor? | |||||
<Pay_Creditor/> | |||||
: | |||||
<Pay/> | |||||
record.creditor ? | |||||
<Pay_Creditor | |||||
record={record} | |||||
/> | |||||
: ( | |||||
record.paymentMethod == "demandNote" ? | |||||
<Pay_Dn | |||||
record={record} | |||||
/> | |||||
: ( | |||||
record.paymentMethod == "online" ? | |||||
<Pay_Online | |||||
record={record} | |||||
/> | |||||
: | |||||
<Pay_Office | |||||
record={record} | |||||
/> | |||||
) | |||||
) | |||||
); | ); | ||||
} | } | ||||
export default Index; | export default Index; |
@@ -10,7 +10,7 @@ import { | |||||
import { useFormik } from 'formik'; | import { useFormik } from 'formik'; | ||||
import * as React from "react"; | import * as React from "react"; | ||||
//import * as DateUtils from "utils/DateUtils" | |||||
import * as DateUtils from "utils/DateUtils" | |||||
import * as FormatUtils from "utils/FormatUtils" | import * as FormatUtils from "utils/FormatUtils" | ||||
import { useParams } from "react-router-dom"; | import { useParams } from "react-router-dom"; | ||||
import Loadable from 'components/Loadable'; | import Loadable from 'components/Loadable'; | ||||
@@ -23,7 +23,7 @@ const ApplicationDetailCard = ({ formData, }) => { | |||||
const params = useParams(); | const params = useParams(); | ||||
const intl = useIntl(); | const intl = useIntl(); | ||||
//const { locale } = intl; | |||||
const { locale } = intl; | |||||
const [data, setData] = React.useState({}); | const [data, setData] = React.useState({}); | ||||
//const [proofId, setProofId] = React.useState(); | //const [proofId, setProofId] = React.useState(); | ||||
@@ -228,7 +228,7 @@ const ApplicationDetailCard = ({ formData, }) => { | |||||
<Grid item xs={12} md={5} lg={5} sx={{ mb: 1, }}> | <Grid item xs={12} md={5} lg={5} sx={{ mb: 1, }}> | ||||
<Grid container alignItems={"center"}> | <Grid container alignItems={"center"}> | ||||
{/* <Grid item xs={12} md={12} lg={12} | |||||
<Grid item xs={12} md={12} lg={12} | |||||
sx={{ display: 'flex', alignItems: 'center' }}> | sx={{ display: 'flex', alignItems: 'center' }}> | ||||
<Typography variant="h5" display="inline"> | <Typography variant="h5" display="inline"> | ||||
@@ -243,8 +243,8 @@ const ApplicationDetailCard = ({ formData, }) => { | |||||
`${DateUtils.datetimeStr_Cht(data.reviseDeadline)} ${intl.formatMessage({ id: 'before' })}` | `${DateUtils.datetimeStr_Cht(data.reviseDeadline)} ${intl.formatMessage({ id: 'before' })}` | ||||
} | } | ||||
</Typography> | </Typography> | ||||
</Grid> */} | |||||
{/* | |||||
</Grid> | |||||
<Grid item xs={12} md={12} lg={12} | <Grid item xs={12} md={12} lg={12} | ||||
sx={{ display: 'flex', alignItems: 'center' }}> | sx={{ display: 'flex', alignItems: 'center' }}> | ||||
<Typography variant="h5" display="inline"> | <Typography variant="h5" display="inline"> | ||||
@@ -259,7 +259,7 @@ const ApplicationDetailCard = ({ formData, }) => { | |||||
`${DateUtils.datetimeStr_Cht(data.proofPaymentDeadline)} ${intl.formatMessage({ id: 'before' })}` | `${DateUtils.datetimeStr_Cht(data.proofPaymentDeadline)} ${intl.formatMessage({ id: 'before' })}` | ||||
} | } | ||||
</Typography> | </Typography> | ||||
</Grid> */} | |||||
</Grid> | |||||
<Grid item xs={12} sm={3} md={3} lg={3} | <Grid item xs={12} sm={3} md={3} lg={3} | ||||
sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | ||||
@@ -283,7 +283,7 @@ const FormPanel = ({ formData }) => { | |||||
{ | { | ||||
actionValue ? | |||||
actionValue && formData.creditor==false ? | |||||
<Grid item xs={12} sx={{ mb: 1, }}> | <Grid item xs={12} sx={{ mb: 1, }}> | ||||
<table style={tabelStyle}> | <table style={tabelStyle}> | ||||
<tr style={tabelStyle}> | <tr style={tabelStyle}> | ||||
@@ -319,9 +319,9 @@ const FormPanel = ({ formData }) => { | |||||
<tr> | <tr> | ||||
<td style={tabelStyle}> | <td style={tabelStyle}> | ||||
<Checkbox | <Checkbox | ||||
checked={paymentMethod == "dn"} | |||||
checked={paymentMethod == "demandNote"} | |||||
onChange={() => { | onChange={() => { | ||||
set_paymentMethod("dn") | |||||
set_paymentMethod("demandNote") | |||||
}} | }} | ||||
/> | /> | ||||
</td> | </td> | ||||
@@ -353,9 +353,9 @@ const FormPanel = ({ formData }) => { | |||||
<tr> | <tr> | ||||
<td style={tabelStyle}> | <td style={tabelStyle}> | ||||
<Checkbox | <Checkbox | ||||
checked={paymentMethod == "npgo"} | |||||
checked={paymentMethod == "office"} | |||||
onChange={() => { | onChange={() => { | ||||
set_paymentMethod("npgo") | |||||
set_paymentMethod("office") | |||||
}} | }} | ||||
/> | /> | ||||
</td> | </td> | ||||
@@ -383,8 +383,8 @@ | |||||
"applicationPublishDate": "Publish Date", | "applicationPublishDate": "Publish Date", | ||||
"pleaseCheckReminder": "Please download the following printed manuscript file and proofread it carefully", | "pleaseCheckReminder": "Please download the following printed manuscript file and proofread it carefully", | ||||
"payAnd": "Pay and ", | "payAnd": "Pay and ", | ||||
"commentDeadline": "Deadline for proof with revison", | |||||
"paymentDeadline": "Deadline for confirm proof and payment", | |||||
"commentDeadline": "Deadline for online proof with revison", | |||||
"paymentDeadline": "Deadline for online confirm proof", | |||||
"confirmingDealine": "Deadline for Confirming Proof", | "confirmingDealine": "Deadline for Confirming Proof", | ||||
"PaymentCoonpletDealine": "Deadline for Payment Completeion", | "PaymentCoonpletDealine": "Deadline for Payment Completeion", | ||||
"payOnline":"Pay online via this system PNSPS", | "payOnline":"Pay online via this system PNSPS", | ||||
@@ -38,7 +38,7 @@ | |||||
"applyTickStr":"我确认上述提到的截止日期。", | "applyTickStr":"我确认上述提到的截止日期。", | ||||
"confirmingDealine": "确认校对的截止日期", | "confirmingDealine": "确认校对的截止日期", | ||||
"PaymentCoonpletDealine": "付款截止日期", | "PaymentCoonpletDealine": "付款截止日期", | ||||
"payOnline":"透过此系统 GPNSPS 线上支付", | |||||
"payOnline":"透过此系统 GPNSPS 网上支付", | |||||
"payDn":"透过发出一般缴款单付款", | "payDn":"透过发出一般缴款单付款", | ||||
"payNPGO":"在 NPGO 收款办公室付款", | "payNPGO":"在 NPGO 收款办公室付款", | ||||
"paymentMeans":"付款方式", | "paymentMeans":"付款方式", | ||||
@@ -397,8 +397,8 @@ | |||||
"applicationPublishDate": "刊出日期", | "applicationPublishDate": "刊出日期", | ||||
"pleaseCheckReminder": "请下载下列印刷稿档案,并仔细校对", | "pleaseCheckReminder": "请下载下列印刷稿档案,并仔细校对", | ||||
"payAnd": "缴费及", | "payAnd": "缴费及", | ||||
"commentDeadline": "返稿最后限期", | |||||
"paymentDeadline": "确定付印及缴费最后限期", | |||||
"commentDeadline": "网上返稿最后限期", | |||||
"paymentDeadline": "网上确定付印最后限期", | |||||
"before": "前", | "before": "前", | ||||
"page": "页", | "page": "页", | ||||
"proofReplyDate": "校对回复日期", | "proofReplyDate": "校对回复日期", | ||||
@@ -38,7 +38,7 @@ | |||||
"applyTickStr":"我確認上述提到的日期。", | "applyTickStr":"我確認上述提到的日期。", | ||||
"confirmingDealine": "確認校對的截止日期", | "confirmingDealine": "確認校對的截止日期", | ||||
"PaymentCoonpletDealine": "付款截止日期", | "PaymentCoonpletDealine": "付款截止日期", | ||||
"payOnline":"透過此系統 GPNSPS 線上支付", | |||||
"payOnline":"透過此系統 GPNSPS 網上支付", | |||||
"payDn":"透過發出一般繳款單付款", | "payDn":"透過發出一般繳款單付款", | ||||
"payNPGO":"在 NPGO 收款辦公室付款", | "payNPGO":"在 NPGO 收款辦公室付款", | ||||
"paymentMeans":"付款方式", | "paymentMeans":"付款方式", | ||||
@@ -400,8 +400,8 @@ | |||||
"applicationPublishDate": "刊出日期", | "applicationPublishDate": "刊出日期", | ||||
"pleaseCheckReminder": "請下載下列印刷稿檔案,並仔細校對", | "pleaseCheckReminder": "請下載下列印刷稿檔案,並仔細校對", | ||||
"payAnd": "繳費及", | "payAnd": "繳費及", | ||||
"commentDeadline": "返稿最後限期", | |||||
"paymentDeadline": "確定付印及繳費最後限期", | |||||
"commentDeadline": "網上返稿最後限期", | |||||
"paymentDeadline": "網上確定付印最後限期", | |||||
"before": "前", | "before": "前", | ||||
"page": "頁", | "page": "頁", | ||||
"proofReplyDate": "校對回覆日期", | "proofReplyDate": "校對回覆日期", | ||||