| @@ -26,7 +26,7 @@ | |||||
| text-decoration: none; | text-decoration: none; | ||||
| font-size: 1.2rem; | font-size: 1.2rem; | ||||
| font-weight: 600; | font-weight: 600; | ||||
| font-family: 微軟正黑體; | |||||
| /* font-family: 微軟正黑體; */ | |||||
| color: black; | color: black; | ||||
| transition: 0.3s ease-in-out; | transition: 0.3s ease-in-out; | ||||
| } | } | ||||
| @@ -76,7 +76,7 @@ | |||||
| font-weight: 600; | font-weight: 600; | ||||
| color: #0C489E; | color: #0C489E; | ||||
| transition: 0.3s ease-in-out; | transition: 0.3s ease-in-out; | ||||
| font-family: 微軟正黑體; | |||||
| /* font-family: 微軟正黑體; */ | |||||
| text-align: center; | text-align: center; | ||||
| } | } | ||||
| #mobileTitle{ | #mobileTitle{ | ||||
| @@ -85,13 +85,13 @@ | |||||
| font-weight: 600; | font-weight: 600; | ||||
| color: #0C489E; | color: #0C489E; | ||||
| transition: 0.3s ease-in-out; | transition: 0.3s ease-in-out; | ||||
| font-family: 微軟正黑體; | |||||
| /* font-family: 微軟正黑體; */ | |||||
| text-align: center; | text-align: center; | ||||
| } | } | ||||
| #sidebar{ | #sidebar{ | ||||
| font-size: 1.3rem; | font-size: 1.3rem; | ||||
| font-weight: 600; | font-weight: 600; | ||||
| font-family: 微軟正黑體; | |||||
| /* font-family: 微軟正黑體; */ | |||||
| } | } | ||||
| #sidebartop{ | #sidebartop{ | ||||
| align-items: center; | align-items: center; | ||||
| @@ -115,7 +115,7 @@ | |||||
| text-decoration: none; | text-decoration: none; | ||||
| font-size: 1.3rem; | font-size: 1.3rem; | ||||
| font-weight: 600; | font-weight: 600; | ||||
| font-family: 微軟正黑體; | |||||
| /* font-family: 微軟正黑體; */ | |||||
| color: black; | color: black; | ||||
| transition: 0.3s ease-in-out; | transition: 0.3s ease-in-out; | ||||
| } | } | ||||
| @@ -1,7 +1,20 @@ | |||||
| body{ | |||||
| @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+HK|Noto+Sans+SC&display=swap'); | |||||
| @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap'); | |||||
| html, | |||||
| body, | |||||
| #root, | |||||
| .app, | |||||
| .content { | |||||
| height: 100%; | |||||
| width: 100%; | |||||
| font-family: "Noto Sans HK", "Noto Sans SC"; | |||||
| } | |||||
| /* body{ | |||||
| padding-top: 53px; | padding-top: 53px; | ||||
| font-family: 微軟正黑體; | font-family: 微軟正黑體; | ||||
| } | |||||
| } */ | |||||
| /* main{ | /* main{ | ||||
| padding-top: 43px; | padding-top: 43px; | ||||
| } */ | } */ | ||||
| @@ -13,9 +13,38 @@ export const hostPath = `http://${hostname}:${hostPort}`; | |||||
| export const apiPath = `${hostPath}/api`; | export const apiPath = `${hostPath}/api`; | ||||
| // export const apiPath = `/api`; | // export const apiPath = `/api`; | ||||
| export const paymentPath = `http://pnspsdev.gld.gov.hk/payment`; | export const paymentPath = `http://pnspsdev.gld.gov.hk/payment`; | ||||
| export const iAmSmartPath = `https://apigw-isit.staging-eid.gov.hk`; | export const iAmSmartPath = `https://apigw-isit.staging-eid.gov.hk`; | ||||
| export const clientId = "cf61fa7c121e4869966f69c8694b1cd2"; | |||||
| export const getBowerType=()=>{ | |||||
| console.log(navigator.userAgent) | |||||
| // const regex = /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Mi|huawei|Opera Mini|SAMSUNG|Samsung|SGH-[I|N|T]|GT-[I|N]|SM-[A|N|P|T|Z]|SHV-E|SCH-[I|J|R|S]|SPH-L/i; | |||||
| // if(!regex.test(navigator.userAgent)) | |||||
| // clientId : cf61fa7c121e4869966f69c8694b1cd2 | |||||
| if (navigator.userAgent.indexOf("Edg") != -1) { | |||||
| if(navigator.userAgent.match(/Android/i)) return "Android_Edge" | |||||
| if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Edge" | |||||
| return "PC_Browser" | |||||
| }else if(navigator.userAgent.indexOf("Chrome") != -1){ | |||||
| if(navigator.userAgent.match(/Android/i)) return "Android_Chrome" | |||||
| if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Chrome" | |||||
| return "PC_Browser" | |||||
| }else if(navigator.userAgent.indexOf("Safari") != -1){ | |||||
| if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Safari" | |||||
| return "PC_Browser" | |||||
| }else if(navigator.userAgent.indexOf("Firefox") != -1){ | |||||
| if(navigator.userAgent.match(/Android/i)) return "Android_Firefox" | |||||
| if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Firefox" | |||||
| return "PC_Browser" | |||||
| }else if(navigator.userAgent.match(/SAMSUNG|Samsung|SGH-[I|N|T]|GT-[I|N]|SM-[A|N|P|T|Z]|SHV-E|SCH-[I|J|R|S]|SPH-L/i)){ | |||||
| return "Android_Samsung" | |||||
| }else if(navigator.userAgent.match(/huawei/i)){ | |||||
| return "Android_Huawei" | |||||
| }else if(navigator.userAgent.match(/Mi/i)){ | |||||
| return "Android_Xiaomi" | |||||
| } | |||||
| return "PC_Browser"; | |||||
| } | |||||
| @@ -1,6 +1,7 @@ | |||||
| import { StrictMode } from 'react'; | import { StrictMode } from 'react'; | ||||
| import { createRoot } from 'react-dom/client'; | import { createRoot } from 'react-dom/client'; | ||||
| import { BrowserRouter } from 'react-router-dom'; | import { BrowserRouter } from 'react-router-dom'; | ||||
| import "./assets/style/styles.css" | |||||
| // scroll bar | // scroll bar | ||||
| import 'simplebar/src/simplebar.css'; | import 'simplebar/src/simplebar.css'; | ||||
| @@ -109,7 +109,7 @@ const Profile = () => { | |||||
| > | > | ||||
| <Stack direction="row" alignItems="center" sx={{ p: 0.5 }}> | <Stack direction="row" alignItems="center" sx={{ p: 0.5 }}> | ||||
| <AccountCircleIcon style={{ color: 'black' }} alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} /> | <AccountCircleIcon style={{ color: 'black' }} alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} /> | ||||
| <Typography style={{ color: 'black',fontFamily: "微軟正黑體", fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||||
| <Typography style={{ color: 'black', fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||||
| </Stack> | </Stack> | ||||
| </ButtonBase> | </ButtonBase> | ||||
| <Popper | <Popper | ||||
| @@ -152,7 +152,7 @@ const Profile = () => { | |||||
| <Stack direction="row" spacing={1.25} alignItems="center"> | <Stack direction="row" spacing={1.25} alignItems="center"> | ||||
| <AccountCircleIcon style={{ color: 'black' }} alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} /> | <AccountCircleIcon style={{ color: 'black' }} alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} /> | ||||
| <Stack> | <Stack> | ||||
| <Typography style={{ color: 'black',fontFamily: "微軟正黑體", fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||||
| <Typography style={{ color: 'black', fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||||
| {/* <Typography variant="body2" color="textSecondary"> | {/* <Typography variant="body2" color="textSecondary"> | ||||
| {userData == null ? "" : userData.fullenName} | {userData == null ? "" : userData.fullenName} | ||||
| </Typography> */} | </Typography> */} | ||||
| @@ -10,6 +10,7 @@ import { | |||||
| FormLabel, | FormLabel, | ||||
| Button | Button | ||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import * as UrlUtils from "utils/ApiPathConst"; | import * as UrlUtils from "utils/ApiPathConst"; | ||||
| import * as HttpUtils from "utils/HttpUtils"; | import * as HttpUtils from "utils/HttpUtils"; | ||||
| import MainCard from "components/MainCard"; | import MainCard from "components/MainCard"; | ||||
| @@ -20,8 +21,6 @@ import { useNavigate } from "react-router-dom"; | |||||
| import Loadable from 'components/Loadable'; | import Loadable from 'components/Loadable'; | ||||
| import { notifySaveSuccess } from 'utils/CommonFunction'; | import { notifySaveSuccess } from 'utils/CommonFunction'; | ||||
| const UploadFileTable = Loadable(React.lazy(() => import('./UploadFileTable'))); | const UploadFileTable = Loadable(React.lazy(() => import('./UploadFileTable'))); | ||||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | |||||
| const FormPanel = ({ formData }) => { | const FormPanel = ({ formData }) => { | ||||
| @@ -239,12 +238,13 @@ const FormPanel = ({ formData }) => { | |||||
| size="small" | size="small" | ||||
| type="text" | type="text" | ||||
| onChange={(event) => { | onChange={(event) => { | ||||
| const value = event.target.value; | |||||
| formik.setFieldValue("length", value); | |||||
| formik.setFieldValue("fee", 6552 * value); | |||||
| const re = /^[0-9\b]+$/; | |||||
| if (event.target.value === '' || re.test(event.target.value)) { | |||||
| const value = event.target.value; | |||||
| formik.setFieldValue("length", value); | |||||
| formik.setFieldValue("fee", 6552 * value); | |||||
| } | |||||
| }} | }} | ||||
| name="noOfPages" | |||||
| value={formik.values["noOfPages"]} | |||||
| variant="outlined" | variant="outlined" | ||||
| sx={ | sx={ | ||||
| { | { | ||||
| @@ -275,9 +275,13 @@ const FormPanel = ({ formData }) => { | |||||
| size="small" | size="small" | ||||
| type="text" | type="text" | ||||
| onChange={(event) => { | onChange={(event) => { | ||||
| const value = event.target.value; | |||||
| formik.setFieldValue("length", value); | |||||
| formik.setFieldValue("fee", columnPrice.value * value); | |||||
| const re = /^[0-9\b]+$/; | |||||
| if (event.target.value === '' || re.test(event.target.value)) { | |||||
| const value = event.target.value; | |||||
| formik.setFieldValue("length", value); | |||||
| formik.setFieldValue("fee", columnPrice.value * value); | |||||
| } | |||||
| }} | }} | ||||
| name="length" | name="length" | ||||
| value={formik.values["length"]} | value={formik.values["length"]} | ||||
| @@ -204,19 +204,20 @@ const ApplicationDetailCard = ({ formData, }) => { | |||||
| <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">繳費及返稿最後限期:</Typography> | |||||
| <Typography variant="h5" display="inline"><Typography variant="h5" style={{color:'red'}} display="inline">繳費及</Typography>返稿最後限期:</Typography> | |||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | <Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | ||||
| <Typography variant="h5">{DateUtils.dateStr_Cht(data.returnBeforeDate)} 下午 2:00前</Typography> | |||||
| <Typography variant="h5"> {DateUtils.dateStr_Cht(data.returnBeforeDate)} 下午 2:00前</Typography> | |||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={3} lg={3} | <Grid item xs={12} md={3} lg={3} | ||||
| sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | ||||
| <Typography variant="h5">應繳費用:</Typography> | <Typography variant="h5">應繳費用:</Typography> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={9} lg={9} sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | <Grid item xs={12} md={9} lg={9} sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | ||||
| <Typography variant="h5" style={{ color: "blue", fontWeight: "bold", }}>{FormatUtils.currencyFormat(data.fee)}</Typography> | |||||
| <Typography variant="h2" style={{ color: "#0049B8", fontWeight: "bold", }}>{FormatUtils.currencyFormat(data.fee)}</Typography> | |||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | |||||
| <Grid item xs={0} md={3} lg={3} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}></Grid> | |||||
| <Grid item xs={12} md={9} lg={9} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | |||||
| { | { | ||||
| formik.values.groupType == "A" | formik.values.groupType == "A" | ||||
| ? | ? | ||||
| @@ -91,7 +91,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss | |||||
| > | > | ||||
| <form onSubmit={handleSubmit(onSubmit)}> | <form onSubmit={handleSubmit(onSubmit)}> | ||||
| <Grid container sx={{ backgroundColor: '#ffffff', ml: 2, mt: 3, mb: 3 }} width="98%"> | |||||
| <Grid container sx={{ backgroundColor: '#ffffff', ml: 2 }} width="98%"> | |||||
| {/*row 1*/} | {/*row 1*/} | ||||
| <CardContent sx={{ px: 2.5, pt: 3 }}> | <CardContent sx={{ px: 2.5, pt: 3 }}> | ||||
| @@ -282,7 +282,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss | |||||
| {/*last row*/} | {/*last row*/} | ||||
| <Grid container maxWidth justifyContent="flex-end"> | <Grid container maxWidth justifyContent="flex-end"> | ||||
| <Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}> | |||||
| <Grid item sx={{ ml: 3, mb: 3, mt: 3 }}> | |||||
| <Button | <Button | ||||
| size="large" | size="large" | ||||
| variant="contained" | variant="contained" | ||||
| @@ -295,7 +295,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss | |||||
| </Button> | </Button> | ||||
| </Grid> | </Grid> | ||||
| <Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}> | |||||
| <Grid item sx={{ ml: 3, mb: 3, mt: 3 }}> | |||||
| <Button | <Button | ||||
| size="large" | size="large" | ||||
| variant="contained" | variant="contained" | ||||
| @@ -37,7 +37,8 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||||
| navigate('/proof/reply/' + params.row.id); | navigate('/proof/reply/' + params.row.id); | ||||
| }; | }; | ||||
| const getGroupTitle = (title) => { | |||||
| /*eslint no-irregular-whitespace: ["error", { "skipComments": true }]*/ | |||||
| /*const getGroupTitle = (title) => { | |||||
| switch (title) { | switch (title) { | ||||
| case 'Private Bill': | case 'Private Bill': | ||||
| return "私人帳單"; | return "私人帳單"; | ||||
| @@ -52,9 +53,8 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||||
| default: | default: | ||||
| return title; | return title; | ||||
| } | } | ||||
| } | |||||
| }*/ | |||||
| const columns = [ | const columns = [ | ||||
| { | { | ||||
| field: 'actions', | field: 'actions', | ||||
| @@ -68,17 +68,17 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||||
| { | { | ||||
| id: 'appId', | id: 'appId', | ||||
| field: 'appId', | field: 'appId', | ||||
| headerName: '申請編號 / 憲報編號 / 憲報期數', | |||||
| headerName: '申請編號 / 憲報期數', | |||||
| flex: 1, | flex: 1, | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| let appNo = params.row.appNo; | let appNo = params.row.appNo; | ||||
| let code = params.row.groupNo; | |||||
| // let code = params.row.groupNo; | |||||
| let isssue = params.row.issueYear | let isssue = params.row.issueYear | ||||
| + " Vol. " + FormatUtils.zeroPad(params.row.issueVolume, 3) | + " Vol. " + FormatUtils.zeroPad(params.row.issueVolume, 3) | ||||
| + ", No. " + FormatUtils.zeroPad(params.row.issueNo, 2) | + ", No. " + FormatUtils.zeroPad(params.row.issueNo, 2) | ||||
| + ", " + DateUtils.dateFormat(params.row.issueDate, "D MMM YYYY (ddd)"); | + ", " + DateUtils.dateFormat(params.row.issueDate, "D MMM YYYY (ddd)"); | ||||
| return <div style={{ margin: 4 }}>{appNo}<br />{code}<br />{isssue}</div> | |||||
| return <div style={{ margin: 4 }}>{appNo}<br />{isssue}</div> | |||||
| }, | }, | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -110,15 +110,15 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||||
| return params?.value ? DateUtils.datetimeStr(params?.value) : ""; | return params?.value ? DateUtils.datetimeStr(params?.value) : ""; | ||||
| } | } | ||||
| }, | }, | ||||
| { | |||||
| id: 'groupTitle', | |||||
| field: 'groupTitle', | |||||
| headerName: '憲報類型', | |||||
| flex: 1, | |||||
| valueGetter: (params) => { | |||||
| return getGroupTitle(params?.value); | |||||
| } | |||||
| }, | |||||
| // { | |||||
| // id: 'groupTitle', | |||||
| // field: 'groupTitle', | |||||
| // headerName: '憲報類型', | |||||
| // flex: 1, | |||||
| // valueGetter: (params) => { | |||||
| // return getGroupTitle(params?.value); | |||||
| // } | |||||
| // }, | |||||
| { | { | ||||
| id: 'fee', | id: 'fee', | ||||
| field: 'fee', | field: 'fee', | ||||
| @@ -147,9 +147,9 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||||
| paginationModel: { page: 0, pageSize: 10 }, | paginationModel: { page: 0, pageSize: 10 }, | ||||
| }, | }, | ||||
| }} | }} | ||||
| getRowHeight={()=>"auto"} | |||||
| getRowHeight={() => "auto"} | |||||
| onRowDoubleClick={handleRowDoubleClick} | onRowDoubleClick={handleRowDoubleClick} | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| } | |||||
| } | |||||
| @@ -154,7 +154,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData | |||||
| /> | /> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | |||||
| {/* <Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | |||||
| <Autocomplete | <Autocomplete | ||||
| {...register("gazettGroup")} | {...register("gazettGroup")} | ||||
| disablePortal | disablePortal | ||||
| @@ -175,7 +175,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData | |||||
| /> | /> | ||||
| )} | )} | ||||
| /> | /> | ||||
| </Grid> | |||||
| </Grid> */} | |||||
| <Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | <Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | ||||
| <TextField | <TextField | ||||
| @@ -90,7 +90,7 @@ const PublicNoticeApplyForm = ({ loadedData, selections }) => { | |||||
| }, | }, | ||||
| files: [attachment], | files: [attachment], | ||||
| onSuccess: function () { | onSuccess: function () { | ||||
| notifyActionSuccess('申請成功!') | |||||
| notifyActionSuccess('申請提交成功!') | |||||
| navigate("/publicNotice"); | navigate("/publicNotice"); | ||||
| // location.reload(); | // location.reload(); | ||||
| } | } | ||||
| @@ -137,12 +137,13 @@ const ApplicationDetailCard = ( | |||||
| variant="contained" | variant="contained" | ||||
| onClick={cancelledClick()} | onClick={cancelledClick()} | ||||
| disabled={currentApplicationDetailData.status !== "submitted"} | disabled={currentApplicationDetailData.status !== "submitted"} | ||||
| title={"取消"} | |||||
| sx={{ | sx={{ | ||||
| textTransform: 'capitalize', | textTransform: 'capitalize', | ||||
| alignItems: 'end', | alignItems: 'end', | ||||
| backgroundColor: '#ffa733' | backgroundColor: '#ffa733' | ||||
| }}> | }}> | ||||
| <CloseIcon /> | |||||
| <CloseIcon sx={{mb:0.5}}/> | |||||
| <Typography ml={1} variant="h5"> 取消</Typography> | <Typography ml={1} variant="h5"> 取消</Typography> | ||||
| </Button> | </Button> | ||||
| </Stack> | </Stack> | ||||
| @@ -480,7 +481,7 @@ const ApplicationDetailCard = ( | |||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={9} lg={9} sx={{ display: 'flex', alignItems: 'center' }}> | <Grid item xs={12} md={9} lg={9} sx={{ display: 'flex', alignItems: 'center' }}> | ||||
| <Grid container direction="row" justifyContent="flex-start"> | <Grid container direction="row" justifyContent="flex-start"> | ||||
| <Grid item xs={12} md={5} lg={5} sx={{ display: 'flex', alignItems: 'center' }}> | |||||
| <Grid item xs={12} md={8} lg={8} sx={{ display: 'flex', alignItems: 'center' }}> | |||||
| <FormControl variant="outlined" fullWidth > | <FormControl variant="outlined" fullWidth > | ||||
| <Typography | <Typography | ||||
| fullWidth | fullWidth | ||||
| @@ -491,16 +492,18 @@ const ApplicationDetailCard = ( | |||||
| </Typography> | </Typography> | ||||
| </FormControl> | </FormControl> | ||||
| </Grid> | </Grid> | ||||
| <Grid item md={2} lg={2}> | |||||
| <Grid item md={4} lg={4}> | |||||
| <Button | <Button | ||||
| size="small" | |||||
| variant="contained" | variant="contained" | ||||
| onClick={onDownloadClick()} | onClick={onDownloadClick()} | ||||
| title="下載" | |||||
| style={{display:"flex-right"}} | |||||
| sx={{ | sx={{ | ||||
| textTransform: 'capitalize', | textTransform: 'capitalize', | ||||
| alignItems: 'end', | alignItems: 'end', | ||||
| }}> | }}> | ||||
| <DownloadIcon /> | |||||
| <DownloadIcon sx={{mb: 0.5}}/> | |||||
| <Typography sx={{ml: 1}} variant="h5">下載</Typography> | |||||
| </Button> | </Button> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| @@ -41,7 +41,7 @@ const UserSearchForm = ({ applySearch }) => { | |||||
| const temp = { | const temp = { | ||||
| username: data.userName, | username: data.userName, | ||||
| fullenName: data.fullenName, | |||||
| enName: data.fullenName, | |||||
| post: data.post, | post: data.post, | ||||
| email: data.email, | email: data.email, | ||||
| phone: data.phone, | phone: data.phone, | ||||
| @@ -29,7 +29,7 @@ const UserSearchForm_Individual = ({ applySearch }) => { | |||||
| const temp = { | const temp = { | ||||
| username: data.userName, | username: data.userName, | ||||
| fullenName: data.fullenName, | |||||
| fullName: data.fullenName, | |||||
| email: data.email, | email: data.email, | ||||
| phone: data.phone, | phone: data.phone, | ||||
| accountFilter: accountFilter, | accountFilter: accountFilter, | ||||
| @@ -44,8 +44,8 @@ const AuthWrapper = ({ children }) => ( | |||||
| alignItems="center" | alignItems="center" | ||||
| spacing={2}> | spacing={2}> | ||||
| <Grid item xs={12} md={8} lg={8} xl={9} sx={{ ml: 4, mt: 3 ,display: { xs: 'none', sm: 'block' }}}> | <Grid item xs={12} md={8} lg={8} xl={9} sx={{ ml: 4, mt: 3 ,display: { xs: 'none', sm: 'block' }}}> | ||||
| <Typography style={{textAlign: "center",fontFamily: "微軟正黑體",fontSize: "1.8rem"}}>香港特別行政區政府</Typography> | |||||
| <Typography style={{textAlign: "center",fontFamily: "微軟正黑體",fontSize: "1.8rem",fontWeight:"bold"}}>憲報</Typography> | |||||
| <Typography style={{textAlign: "center",fontSize: "1.8rem"}}>香港特別行政區政府</Typography> | |||||
| <Typography style={{textAlign: "center",fontSize: "1.8rem",fontWeight:"bold"}}>憲報</Typography> | |||||
| </Grid> | </Grid> | ||||
| <Grid | <Grid | ||||
| item | item | ||||
| @@ -2,13 +2,14 @@ | |||||
| // material-ui | // material-ui | ||||
| import { | import { | ||||
| Dialog, DialogTitle, DialogContent, DialogActions, | |||||
| Dialog, DialogTitle, DialogContent, | |||||
| Link, Button, Card, Box, Grid | Link, Button, Card, Box, Grid | ||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import Typography from '@mui/material/Typography'; | import Typography from '@mui/material/Typography'; | ||||
| import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png'; | import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png'; | ||||
| import banner from 'assets/images/bg_ml.jpg'; | import banner from 'assets/images/bg_ml.jpg'; | ||||
| import { Stack } from '../../../node_modules/@mui/material/index'; | import { Stack } from '../../../node_modules/@mui/material/index'; | ||||
| import { iAmSmartPath, clientId, getBowerType } from 'auth/utils' | |||||
| import * as React from 'react'; | import * as React from 'react'; | ||||
| @@ -23,6 +24,19 @@ const RegisterCustom = () => { | |||||
| setIsPopUp(true); | setIsPopUp(true); | ||||
| } | } | ||||
| const getQRWithIAmSmart = () => { | |||||
| let url = iAmSmartPath + "/api/v1/auth/getQR" | |||||
| + "?clientID=" + clientId | |||||
| + "&responseType=code" | |||||
| +"&source=" + getBowerType() | |||||
| +"&redirectURI=" | |||||
| +"&scope=eidapi_formFilling" | |||||
| +"&lang=zh-HK"//en-US, zh-HK, or zh-CN | |||||
| //+"&state=" | |||||
| +"&brokerPage=false" | |||||
| window.location.assign(url); | |||||
| } | |||||
| return ( | return ( | ||||
| <Stack justifyContent="center" sx={{ minHeight: '100vh', bgcolor: 'backgroundColor.default' }}> | <Stack justifyContent="center" sx={{ minHeight: '100vh', bgcolor: 'backgroundColor.default' }}> | ||||
| @@ -58,7 +72,7 @@ const RegisterCustom = () => { | |||||
| 你可點擊「智方便」按鈕,系統會自動輸入個人資料,或自行輸入個人資料,以即時啟動憲報刊登公告帳戶。 | 你可點擊「智方便」按鈕,系統會自動輸入個人資料,或自行輸入個人資料,以即時啟動憲報刊登公告帳戶。 | ||||
| <br />如欲使用「智方便」提供個人資料,請先下載「智方便」流動應用程式並登記成為「智方便」用戶。 | <br />如欲使用「智方便」提供個人資料,請先下載「智方便」流動應用程式並登記成為「智方便」用戶。 | ||||
| </Typography> | </Typography> | ||||
| <Link href="#">了解更多</Link> | |||||
| <Link href="https://www.iamsmart.gov.hk/tc/">了解更多</Link> | |||||
| </Box> | </Box> | ||||
| <Typography m={5}>或</Typography> | <Typography m={5}>或</Typography> | ||||
| @@ -105,29 +119,25 @@ const RegisterCustom = () => { | |||||
| <Typography style={{ padding: '4px' }}> | <Typography style={{ padding: '4px' }}> | ||||
| - 身份證號碼 | - 身份證號碼 | ||||
| </Typography> | </Typography> | ||||
| <Typography style={{ padding: '4px' }}> | |||||
| - 性別 | |||||
| </Typography> | |||||
| </Grid> | </Grid> | ||||
| <Grid item xs={6} > | <Grid item xs={6} > | ||||
| <Typography style={{ padding: '4px' }}> | <Typography style={{ padding: '4px' }}> | ||||
| - 中文姓名 | |||||
| </Typography> | |||||
| <Typography style={{ padding: '4px' }}> | |||||
| - 英文姓名 | |||||
| - 電郵地址 | |||||
| </Typography> | </Typography> | ||||
| <Typography style={{ padding: '4px' }}> | <Typography style={{ padding: '4px' }}> | ||||
| - 身份證號碼 | |||||
| - 手機號碼 | |||||
| </Typography> | </Typography> | ||||
| <Typography style={{ padding: '4px' }}> | <Typography style={{ padding: '4px' }}> | ||||
| - 性別 | |||||
| - 住宅地址 | |||||
| </Typography> | </Typography> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| </DialogContent> | </DialogContent> | ||||
| <DialogActions> | |||||
| <Button onClick={() => setIsPopUp(false)}>OK</Button> | |||||
| </DialogActions> | |||||
| <DialogContent align="right"> | |||||
| <Button variant="outlined" onClick={getQRWithIAmSmart} startIcon={<img src={iAmSmartICon} alt="iAM Smart" width="30" />}><Typography variant="h5">使用「智方便」自動填表</Typography></Button> | |||||
| <br /> | |||||
| <Link href="https://www.iamsmart.gov.hk/tc/">了解更多</Link> | |||||
| </DialogContent> | |||||
| </Dialog> | </Dialog> | ||||
| </Stack> | </Stack> | ||||
| ); | ); | ||||
| @@ -0,0 +1,74 @@ | |||||
| // material-ui | |||||
| import { Button, Grid } from '@mui/material'; | |||||
| import { Link } from 'react-router-dom'; | |||||
| import Typography from '@mui/material/Typography'; | |||||
| // import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png'; | |||||
| // import banner from 'assets/images/bg_ml.jpg'; | |||||
| import { Stack } from '../../../node_modules/@mui/material/index'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import { useParams } from 'react-router-dom'; | |||||
| import axios from 'axios'; | |||||
| import { GET_VERIFY_USER_ACCOUNT } from 'utils/ApiPathConst'; | |||||
| import Loadable from 'components/Loadable'; | |||||
| import { lazy } from 'react'; | |||||
| const LoadingComponent = Loadable(lazy(() => import('../extra-pages/LoadingComponent'))); | |||||
| const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); | |||||
| import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | |||||
| import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined'; | |||||
| export default function Verify() { | |||||
| const [isLoading, setIsLoading] = useState(true) | |||||
| const [verifyState, setVerifyState] = useState(null) | |||||
| const params = useParams() | |||||
| const handleVerify = async () => { | |||||
| const response = await axios.get(GET_VERIFY_USER_ACCOUNT, { | |||||
| params: { | |||||
| email: decodeURIComponent(params.email), | |||||
| emailVerifyHash: decodeURIComponent(params.verifyCode) | |||||
| } | |||||
| }) | |||||
| if (response.status === 200 && response.data) { | |||||
| setVerifyState(true) | |||||
| } else { | |||||
| setVerifyState(false) | |||||
| } | |||||
| setIsLoading(false) | |||||
| } | |||||
| let enterUseEffect = false | |||||
| useEffect(() => { | |||||
| if (enterUseEffect) handleVerify() | |||||
| enterUseEffect = true | |||||
| }, []) | |||||
| return ( | |||||
| <Stack sx={{ width: '100%', fontSize: '2rem', paddingTop: '65px' }} alignItems="center"> | |||||
| <AuthWrapper> | |||||
| {isLoading || verifyState == null ? | |||||
| <LoadingComponent /> : | |||||
| <Grid item xs={12}> | |||||
| {verifyState ? | |||||
| // SUCCESS page | |||||
| <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}> | |||||
| <CheckCircleOutlineIcon color="success" sx={{ width: "200px", height: "200px" }} /> | |||||
| <Typography display="inline" variant="h4">帳戶已成功驗證。</Typography> | |||||
| <Button variant="outlined" component={Link} to="/login" sx={{ fontSize: 20, height: '60px' }}><Typography variant="h5">返回登入頁面</Typography></Button> | |||||
| </Stack> | |||||
| : | |||||
| // ERROR page | |||||
| <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}> | |||||
| {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */} | |||||
| <CancelOutlinedIcon color="error" sx={{ width: "200px", height: "200px" }} /> | |||||
| <Typography display="inline" variant="h4">驗證失敗,請聯絡相關的系統管理員協助。</Typography> | |||||
| <Button color="error" variant="outlined" component={Link} to="/login" sx={{ fontSize: 20, height: '60px' }}><Typography variant="h5">返回登入頁面</Typography></Button> | |||||
| </Stack> | |||||
| } | |||||
| </Grid> | |||||
| } | |||||
| </AuthWrapper> | |||||
| </Stack> | |||||
| ) | |||||
| } | |||||
| @@ -19,41 +19,45 @@ import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined'; | |||||
| const PasswordAlertDialog = (props) => { | const PasswordAlertDialog = (props) => { | ||||
| return ( | return ( | ||||
| <Dialog | |||||
| <Dialog | |||||
| open={props.open} | open={props.open} | ||||
| onClose={props.handleClose} | onClose={props.handleClose} | ||||
| aria-labelledby="alert-dialog-title" | aria-labelledby="alert-dialog-title" | ||||
| aria-describedby="alert-dialog-description" | aria-describedby="alert-dialog-description" | ||||
| > | |||||
| <DialogTitle id="alert-dialog-title"> | |||||
| <Stack mt={1} mr={4} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}> | |||||
| <CancelOutlinedIcon color="error" sx={{width:"35px",height:"40px"}}/> | |||||
| {props.errorMassage==='ACCOUNT_LOCKED_ERROR'? | |||||
| <Stack direction="column"> | |||||
| <Typography display="inline"> | |||||
| 帳戶將被封鎖 | |||||
| </Typography> | |||||
| <Typography display="inline"> | |||||
| 帳戶連續五次登入錯誤,請與系統管理員聯絡 | |||||
| </Typography> | |||||
| </Stack>: | |||||
| <Typography display="inline"> | |||||
| 用戶名或密碼錯誤 | |||||
| </Typography> | |||||
| } | |||||
| </Stack> | |||||
| </DialogTitle> | |||||
| <DialogContent> | |||||
| <DialogContentText id="alert-dialog-description"> | |||||
| {""} | |||||
| </DialogContentText> | |||||
| </DialogContent> | |||||
| <DialogActions> | |||||
| <Button variant="contained" color="error" onClick={props.handleClose} autoFocus> | |||||
| 關閉 | |||||
| </Button> | |||||
| </DialogActions> | |||||
| </Dialog> | |||||
| > | |||||
| <DialogTitle id="alert-dialog-title"> | |||||
| <Stack mt={1} mr={4} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}> | |||||
| <CancelOutlinedIcon color="error" sx={{ width: "35px", height: "40px" }} /> | |||||
| {props.errorMassage === 'ACCOUNT_LOCKED_ERROR' ? | |||||
| <Stack direction="column"> | |||||
| <Typography display="inline"> | |||||
| 帳戶將被封鎖 | |||||
| </Typography> | |||||
| <Typography display="inline"> | |||||
| 帳戶連續五次登入錯誤,請與系統管理員聯絡 | |||||
| </Typography> | |||||
| </Stack> : | |||||
| props.errorMassage === 'ACCOUNT_VERIFIED_ERROR' ? | |||||
| <Typography display="inline"> | |||||
| 帳戶尚未驗證 | |||||
| </Typography> : | |||||
| <Typography display="inline"> | |||||
| 用戶名或密碼錯誤 | |||||
| </Typography> | |||||
| } | |||||
| </Stack> | |||||
| </DialogTitle> | |||||
| <DialogContent> | |||||
| <DialogContentText id="alert-dialog-description"> | |||||
| {""} | |||||
| </DialogContentText> | |||||
| </DialogContent> | |||||
| <DialogActions> | |||||
| <Button variant="contained" color="error" onClick={props.handleClose} autoFocus> | |||||
| 關閉 | |||||
| </Button> | |||||
| </DialogActions> | |||||
| </Dialog> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -16,6 +16,7 @@ const IAmSmart_SuccessCallback = Loadable(lazy(() => import('pages/iAmSmart/Succ | |||||
| //TODO: this page for testing only, please remove at prod | //TODO: this page for testing only, please remove at prod | ||||
| const TestMailPage = Loadable(lazy(() => import('pages/pnspsNotifyTest'))); | const TestMailPage = Loadable(lazy(() => import('pages/pnspsNotifyTest'))); | ||||
| const VerifyPage = Loadable(lazy(() => import('pages/authentication/Verify'))); | |||||
| // ==============================|| AUTH ROUTING ||============================== // | // ==============================|| AUTH ROUTING ||============================== // | ||||
| @@ -54,6 +55,14 @@ const LoginRoutes = { | |||||
| { | { | ||||
| path: 'iamsmart/logincallback', | path: 'iamsmart/logincallback', | ||||
| element: <IAmSmart_SuccessCallback/> | element: <IAmSmart_SuccessCallback/> | ||||
| }, | |||||
| { | |||||
| path: 'testMailPage', | |||||
| element: <TestMailPage/> | |||||
| }, | |||||
| { | |||||
| path: 'verify/:verifyCode/:email', | |||||
| element: <VerifyPage/> | |||||
| } | } | ||||
| ] | ] | ||||
| }; | }; | ||||
| @@ -17,7 +17,7 @@ export default function ThemeCustomization({ children }) { | |||||
| const theme = Palette('light', 'default'); | const theme = Palette('light', 'default'); | ||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | // eslint-disable-next-line react-hooks/exhaustive-deps | ||||
| const themeTypography = Typography(`微軟正黑體`); | |||||
| const themeTypography = Typography(``); | |||||
| const themeCustomShadows = useMemo(() => CustomShadows(theme), [theme]); | const themeCustomShadows = useMemo(() => CustomShadows(theme), [theme]); | ||||
| const themeOptions = useMemo( | const themeOptions = useMemo( | ||||
| @@ -45,6 +45,7 @@ export const POST_CAPTCHA = apiPath+'/captcha'; | |||||
| export const POST_PUBLIC_USER_REGISTER = apiPath+'/user/register'; | export const POST_PUBLIC_USER_REGISTER = apiPath+'/user/register'; | ||||
| export const GET_USERNAME = apiPath+'/user/username'; | export const GET_USERNAME = apiPath+'/user/username'; | ||||
| export const GET_USER_EMAIL = apiPath+'/user/email'; | export const GET_USER_EMAIL = apiPath+'/user/email'; | ||||
| export const GET_VERIFY_USER_ACCOUNT = apiPath+'/user/verifyEmail'; | |||||
| //Public | //Public | ||||
| export const GET_PUBLIC_ORG_USER_LIST = apiPath+'/user/listOrg'; | export const GET_PUBLIC_ORG_USER_LIST = apiPath+'/user/listOrg'; | ||||