Alex Cheung 1 year ago
parent
commit
363fab795b
22 changed files with 1750 additions and 302 deletions
  1. +126
    -85
      src/components/FileList.js
  2. +1
    -1
      src/layout/MainLayout/Header/index.js
  3. +64
    -61
      src/pages/ManageOrgUserPage/index.js
  4. +91
    -27
      src/pages/ProofCreate_FromApp/ProofForm.js
  5. +246
    -0
      src/pages/ProofReply_Public/ApplicationDetails.js
  6. +302
    -0
      src/pages/ProofReply_Public/ProofForm.js
  7. +111
    -0
      src/pages/ProofReply_Public/UploadFileTable.js
  8. +133
    -0
      src/pages/ProofReply_Public/index.js
  9. +5
    -11
      src/pages/ProofSearch/SearchForm.js
  10. +144
    -0
      src/pages/ProofSearch_Public/DataGrid.js
  11. +280
    -0
      src/pages/ProofSearch_Public/SearchForm.js
  12. +113
    -0
      src/pages/ProofSearch_Public/index.js
  13. +2
    -1
      src/pages/PublicNotice/ListPanel/SearchPublicNoticeForm.js
  14. +26
    -5
      src/pages/PublicNoticeDetail_GLD/ApplicationDetailCard.js
  15. +12
    -7
      src/pages/PublicNoticeDetail_GLD/index.js
  16. +29
    -30
      src/pages/PublicNoticeDetail_GLD/tabTableDetail/ProofTab.js
  17. +9
    -12
      src/pages/PublicNoticeDetail_GLD/tabTableDetail/TabTable.js
  18. +7
    -11
      src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js
  19. +10
    -0
      src/routes/PublicUserRoutes.js
  20. +4
    -1
      src/utils/ApiPathConst.js
  21. +26
    -49
      src/utils/ComboData.js
  22. +9
    -1
      src/utils/DateUtils.js

+ 126
- 85
src/components/FileList.js View File

@@ -1,16 +1,16 @@
// material-ui
import * as React from 'react';
import {
DataGrid,
GridActionsCellItem,
} from "@mui/x-data-grid";
import * as Icon from '../utils/IconUtils';
import * as HttpUtils from "../utils/HttpUtils"
import * as UrlUtils from "../utils/ApiPathConst"
import * as DateUtils from "../utils/DateUtils"
import { FiDataGrid } from './FiDataGrid';
// ==============================|| EVENT TABLE ||============================== //

export default function FileList({refType, refId, allowDelete, sx}) {
export default function FileList({ refType, refId, allowDelete, sx, dateHideable,lang, ...props }) {
const [rows, setRows] = React.useState([]);
const [rowModesModel] = React.useState({});

@@ -22,12 +22,12 @@ export default function FileList({refType, refId, allowDelete, sx}) {
HttpUtils.get(
{
url: UrlUtils.GET_FILE_DELETE,
params:{
params: {
fileId: fileId,
skey:skey,
skey: skey,
filename: filename
},
onSuccess: function(){
onSuccess: function () {
loadData();
}
}
@@ -36,84 +36,124 @@ export default function FileList({refType, refId, allowDelete, sx}) {

const onDownloadClick = (fileId, skey, filename) => () => {
HttpUtils.fileDownload({
fileId:fileId,
skey:skey,
filename:filename,
fileId: fileId,
skey: skey,
filename: filename,
});
};


const loadData = ()=>{
HttpUtils.post(
{
url: UrlUtils.POST_FILE_LIST,
params:{
refType: refType,
refId: refId,
},
onSuccess: function(responseData){
setRows(responseData.records);
const loadData = () => {
HttpUtils.post(
{
url: UrlUtils.POST_FILE_LIST,
params: {
refType: refType,
refId:refId,
},
onSuccess: function (responseData) {
setRows(responseData.records);
}
}
}
);
);
};

const convertToStr=(bytes,decimals)=>{
if(bytes == 0) return '0 Bytes';
const convertToStr = (bytes, decimals) => {
if (bytes == 0) return '0 Bytes';
var dm = decimals || 2,
sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
let i = 0;
i = Math.floor(Math.log(bytes) / Math.log(1024));
let i = 0;
i = Math.floor(Math.log(bytes) / Math.log(1024));
return parseFloat((bytes / Math.pow(1024, i)).toFixed(dm)) + ' ' + sizes[i];
}

const columns = [
{
id: 'created',
field: 'created',
headerName: 'created',
flex: 1,
valueGetter:(params)=>{
return DateUtils.datetimeStr(params.value);
}
},
{
field: 'actions',
type: 'actions',
headerName: '',
width: 50,
cellClassName: 'actions',
getActions: (params) => {
return [
<GridActionsCellItem
key="OutSave"
icon={<Icon.Download/>}
label="Download"
className="textPrimary"
onClick={onDownloadClick(params.id, params.row.skey, params.row.filename)}
color="primary"
/>]
const columns = (dateHideable ?
[
{
field: 'actions',
type: 'actions',
headerName: '',
width: 50,
cellClassName: 'actions',
getActions: (params) => {
return [
<GridActionsCellItem
key="OutSave"
icon={<Icon.Download />}
label="Download"
className="textPrimary"
onClick={onDownloadClick(params.id, params.row.skey, params.row.filename)}
color="primary"
/>]
},
},
},{
id: 'filename',
field: 'filename',
headerName: 'filename',
flex: 3,
},
{
id: 'filesize',
field: 'filesize',
headerName: 'filesize',
flex: 1,
valueGetter:(params)=>{
return convertToStr(params.value);
{
id: 'filename',
field: 'filename',
headerName: lang=="ch"?"檔案名稱":'File Name',
flex: 3,
},
{
id: 'filesize',
field: 'filesize',
headerName: lang=="ch"?"檔案大小":'File Size',
flex: 1,
valueGetter: (params) => {
return convertToStr(params.value);
}
}
},
];
]
:
[
{
id: 'created',
field: 'created',
headerName: lang=="ch"?"日期":'Created',
flex: 1,
valueGetter: (params) => {
return DateUtils.datetimeStr(params.value);
}
},
{
field: 'actions',
type: 'actions',
headerName: '',
width: 50,
cellClassName: 'actions',
getActions: (params) => {
return [
<GridActionsCellItem
key="OutSave"
icon={<Icon.Download />}
label="Download"
className="textPrimary"
onClick={onDownloadClick(params.id, params.row.skey, params.row.filename)}
color="primary"
/>]
},
},
{
id: 'filename',
field: 'filename',
headerName: lang=="ch"?"檔案名稱":'File Name',
flex: 3,
},
{
id: 'filesize',
field: 'filesize',
headerName: lang=="ch"?"檔案大小":'File Size',
flex: 1,
valueGetter: (params) => {
return convertToStr(params.value);
}
},
]
);



if(allowDelete){
if (allowDelete) {
columns.push({
field: 'actions',
type: 'actions',
@@ -124,7 +164,7 @@ export default function FileList({refType, refId, allowDelete, sx}) {
return [
<GridActionsCellItem
key="OutSave"
icon={<Icon.Delete/>}
icon={<Icon.Delete />}
label="Delete"
className="textPrimary"
onClick={onDeleteClick(params.id, params.row.skey, params.row.filename)}
@@ -135,22 +175,23 @@ export default function FileList({refType, refId, allowDelete, sx}) {
}

return (
<div style={{height: 400, width: '100%'}}>
<DataGrid
hideFooterSelectedRowCount={true}
sx={sx}
rows={rows}
columns={columns}
editMode="row"
rowModesModel={rowModesModel}
initialState={{
pagination: {
paginationModel: {page: 0, pageSize: 5},
},
}}
pageSizeOptions={[5, 10]}
autoHeight = {true}
/>
</div>
// <div style={{height: 400, width: '100%'}}>
<FiDataGrid
{...props}
hideFooterSelectedRowCount={true}
sx={sx}
rows={rows}
columns={columns}
editMode="row"
rowModesModel={rowModesModel}
initialState={{
pagination: {
paginationModel: { page: 0, pageSize: 5 },
},
}}
pageSizeOptions={[5, 10]}
autoHeight={true}
/>
// </div>
);
}

+ 1
- 1
src/layout/MainLayout/Header/index.js View File

@@ -118,7 +118,7 @@ function Header(props) {
<Link className="myDocumet" to='/publicNotice'>我的公共啟事</Link>
</li>
<li>
<Link className="documentRecord" to='/dashboard'>校對記錄</Link>
<Link className="documentRecord" to='/proof/search'>校對記錄</Link>
</li>
<li>
<Link className="paymentRecord" to='/dashboard'>付款記錄</Link>


+ 64
- 61
src/pages/ManageOrgUserPage/index.js View File

@@ -1,13 +1,11 @@
// material-ui
import {
DataGrid,
//GridActionsCellItem
} from "@mui/x-data-grid";
import {FiDataGrid} from "components/FiDataGrid";

import {
Typography, Button, Grid
}from '@mui/material';
Typography, Button, Grid, Stack
} from '@mui/material';

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import Checkbox from '@mui/material/Checkbox';

import MainCard from "../../components/MainCard";
@@ -17,6 +15,15 @@ import * as HttpUtils from "../../utils/HttpUtils";
import * as UrlUtils from "../../utils/ApiPathConst";
import * as DateUtils from "../../utils/DateUtils";

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: '100%',
height: '100%',
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundColor: '#0C489E',
backgroundPosition: 'right'
}


// ==============================|| DASHBOARD - DEFAULT ||============================== //
@@ -24,65 +31,64 @@ import * as DateUtils from "../../utils/DateUtils";

const ManageOrgUserPage = () => {
const [rows, setRows] = React.useState([]);
const [rowModesModel] = React.useState({});

React.useEffect(() => {
loadData();
}, []);


function loadData(){
function loadData() {
HttpUtils.get(
{
url: UrlUtils.GET_PUBLIC_ORG_USER_LIST,
onSuccess: function(responseData){
onSuccess: function (responseData) {
setRows(responseData);
}
}
);
}

function onActiveClick(params){
function onActiveClick(params) {
HttpUtils.get({
url: UrlUtils.GET_USER_UNLOCK+"/"+params.row.id,
onSuccess:()=>{
loadData();
url: UrlUtils.GET_USER_UNLOCK + "/" + params.row.id,
onSuccess: () => {
loadData();
}
});
}

function getHeader(headerStr){
function getHeader(headerStr) {
return <Typography variant="h5" >{headerStr}</Typography>;
}

function getStatus(params){
if(params.row.locked){
function getStatus(params) {
if (params.row.locked) {
return (
<>
{getStatusTag({color:"#525150", text: "鎖定"})}
<Button variant="outlined" onClick={()=>onActiveClick(params)}>解鎖</Button>
{getStatusTag({ color: "#525150", text: "鎖定" })}
<Button variant="outlined" onClick={() => onActiveClick(params)}>解鎖</Button>
</>
)
}else if(!params.row.verifiedBy){
return getStatusTag({color:"#fca503", text: "待批核"})
}else if(params.row.status == "active"){
return getStatusTag({color:"#73AD21", text: "生效中"})
)
} else if (!params.row.verifiedBy) {
return getStatusTag({ color: "#fca503", text: "待批核" })
} else if (params.row.status == "active") {
return getStatusTag({ color: "#73AD21", text: "生效中" })
}
return getStatusTag({text: params.row.status})
return getStatusTag({ text: params.row.status })
}

function getStatusTag({color="#000", textColor="#FFF",text=""}){
return (
<div style={{borderRadius:"25px" ,"background": color, "color":textColor, "padding":"5px 10px 5px 10px"}}><b>{text}</b></div>
function getStatusTag({ color = "#000", textColor = "#FFF", text = "" }) {
return (
<div style={{ borderRadius: "25px", "background": color, "color": textColor, "padding": "5px 10px 5px 10px" }}><b>{text}</b></div>
)
}


const setPrimaryUser=(params)=>{
const setPrimaryUser = (params) => {
HttpUtils.get(
{
url: (!params.row.primaryUser?UrlUtils.GET_SET_PRIMARY_USER:UrlUtils.GET_SET_UN_PRIMARY_USER)+"/"+params.row.id,
onSuccess:function(){
url: (!params.row.primaryUser ? UrlUtils.GET_SET_PRIMARY_USER : UrlUtils.GET_SET_UN_PRIMARY_USER) + "/" + params.row.id,
onSuccess: function () {
loadData();
}
}
@@ -97,23 +103,23 @@ const ManageOrgUserPage = () => {
field: 'username',
headerName: getHeader('登錄名稱'),
flex: 1,
},
{
id: 'contactPerson',
field: 'contactPerson',
headerName: getHeader('用戶名稱'),
flex: 1,
},
{
id: 'contactTel',
field: 'contactTel',
headerName: getHeader('聯絡電話'),
flex: 1,
valueGetter:(params)=>{
valueGetter: (params) => {
let contactTel = JSON.parse(params.value)
return contactTel?.countryCode+" "+contactTel?.phoneNumber;
return contactTel?.countryCode + " " + contactTel?.phoneNumber;
}
},
{
@@ -127,7 +133,7 @@ const ManageOrgUserPage = () => {
field: 'lastLogin',
headerName: getHeader('最後登入日期'),
flex: 1,
valueGetter:(params)=>{
valueGetter: (params) => {
return DateUtils.datetimeStr(params.value);
}
},
@@ -136,7 +142,7 @@ const ManageOrgUserPage = () => {
field: 'lastApply',
headerName: getHeader('最後提交申請日期'),
flex: 1,
valueGetter:()=>{
valueGetter: () => {
return "--";
}
},
@@ -159,9 +165,9 @@ const ManageOrgUserPage = () => {
renderCell: (params) => {
console.log(params);
return (
<Checkbox
onClick={()=>{setPrimaryUser(params)}}
checked={params.row.primaryUser}
<Checkbox
onClick={() => { setPrimaryUser(params) }}
checked={params.row.primaryUser}
/>
);
},
@@ -169,30 +175,27 @@ const ManageOrgUserPage = () => {
];

return (
<MainCard elevation={0} border={false} content={false} >
<Grid container rowSpacing={4.5} columnSpacing={2.75}>
<Grid item lg={12} sx={{mb: -2.25}}>Setting</Grid>
<Grid item lg={12}>
<Typography variant="h5" sx={{mt: 3, ml: 3, mb: 1}}>
公司/機構用戶記錄
</Typography>
<MainCard elevation={0} border={false} content={false} >
<Grid container>
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4">公司/機構用戶記錄</Typography>
</Stack>
</div>
</Grid>

<Grid item lg={12}>
<DataGrid
rows={rows}
columns={columns}
editMode="row"
rowModesModel={rowModesModel}
initialState={{
pagination: {
paginationModel: {page: 0, pageSize: 10},
},
}}
pageSizeOptions={[5, 10]}
autoHeight
/>
</Grid>
<Grid item lg={12} sx={{padding:2}}>
<FiDataGrid
rows={rows}
columns={columns}
initialState={{
pagination: {
paginationModel: { page: 0, pageSize: 10 },
},
}}
/>
</Grid>
</Grid>
</MainCard>
);


+ 91
- 27
src/pages/ProofCreate_FromApp/ProofForm.js View File

@@ -16,7 +16,7 @@ import MainCard from "components/MainCard";
import * as ComboData from "utils/ComboData";
import * as React from "react";
import { useFormik } from 'formik';
import {useNavigate} from "react-router-dom";
import { useNavigate } from "react-router-dom";
import Loadable from 'components/Loadable';
const UploadFileTable = Loadable(React.lazy(() => import('./UploadFileTable')));
// ==============================|| DASHBOARD - DEFAULT ||============================== //
@@ -28,27 +28,80 @@ const FormPanel = ({ formData }) => {
const [columnPrice, setColumnPrice] = React.useState(ComboData.proofPrice[0]);
const [attachments, setAttachments] = React.useState([]);

const [wait, setWait] = React.useState(false);

const [isWarningPopUp, setIsWarningPopUp] = React.useState(false);
const [warningText, setWarningText] = React.useState("");

const navigate = useNavigate()

React.useEffect(() => {
if (formData){
if (formData) {
setData(formData);
if(formData.groupType == "A"){
if (formData.groupType == "A") {
setColumnPrice(ComboData.proofPrice[1])
formData['length'] = 18;
}
}
}, [formData]);


React.useEffect(() => {
if (!attachments || attachments.length <= 0) {
formik.setFieldValue("length", 0);
formik.setFieldValue("noOfPages", 0);
formik.setFieldValue("fee", 0);
return;
}

doCalculate();

}, [attachments]);

const doCalculate = () => {
setWait(true);
if (!attachments || attachments.length <= 0) {
setWarningText("Unable to calculate, please upload a valid document.");
setIsWarningPopUp(true);
setWait(false);
return;
}
HttpUtils.postWithFiles({
url: UrlUtils.PROOF_CHECK_PRICE,
params: {
appId: data.id,
},
files: attachments,
onSuccess: function (responseData) {
if (responseData.data.detail) {
setWarningText("Unable to calculate, please upload a valid document or input manually.");
setIsWarningPopUp(true);
return;
}
formik.setFieldValue("length", responseData.data.length);
let colValue = 0;
setColumnPrice(ComboData.proofPrice.find(obj => {
colValue = obj.value;
return obj.colCount === responseData.data.column
}));
formik.setFieldValue("noOfPages", responseData.data.no_of_page);
formik.setFieldValue("fee", (data.groupType == "A" ? 6552 * responseData.data.no_of_page : responseData.data.length * colValue));
setWait(false);
},
onError: function () {
setWarningText("Unable to calculate, please input manually.");
setIsWarningPopUp(true);
setWait(false);
}
});
}

const formik = useFormik({
enableReinitialize: true,
initialValues: data,
onSubmit: values => {
if (!attachments || attachments.length<=0) {
setWarningText("請選擇上傳檔案");
if (!attachments || attachments.length <= 0) {
setWarningText("Please upload file.");
setIsWarningPopUp(true);
return;
}
@@ -74,17 +127,17 @@ const FormPanel = ({ formData }) => {
let file = event.target.files[0];
if (file) {
if (!file.name.toLowerCase().substr(file.name.length - 4).includes(".pdf")) {
setWarningText("請上傳有效檔案 (檔案格式: .pdf)");
setWarningText("Please upload a valid file (File format: .pdf).");
setIsWarningPopUp(true);
document.getElementById("uploadFileBtn").value = "";
return;
}
if(file.size >= (10 * 1024 * 1034)){
setWarningText("上傳檔案大小應<10MB");
if (file.size >= (10 * 1024 * 1034)) {
setWarningText("The file size for uploading should be less than 10MB");
setIsWarningPopUp(true);
return;
}
file['id'] = attachments.length;
setAttachments([
...attachments,
@@ -96,6 +149,7 @@ const FormPanel = ({ formData }) => {




return (
<MainCard xs={12} md={12} lg={12}
border={false}
@@ -138,17 +192,27 @@ const FormPanel = ({ formData }) => {
<UploadFileTable key="uploadTable" recordList={attachments} setRecordList={setAttachments} />
</Grid>

<Grid item xs={12} md={12}>
<Button
size="large"
variant="contained"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}>
Calculate
</Button>
</Grid>
{
wait ?
<Grid item xs={12} md={12}>
Doing calculate, please wait ...
</Grid>
:
<Grid item xs={12} md={12}>
<Button
size="large"
variant="contained"
onClick={doCalculate}
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}>
Calculate
</Button>
</Grid>
}



{
formik.values.groupType == "A" ?
@@ -158,10 +222,10 @@ const FormPanel = ({ formData }) => {
fullWidth
size="small"
type="text"
onChange={(event)=>{
onChange={(event) => {
const value = event.target.value;
formik.setFieldValue("length", value);
formik.setFieldValue("fee", columnPrice.value*value);
formik.setFieldValue("fee", 6552 * value);
}}
name="noOfPages"
value={formik.values["noOfPages"]}
@@ -183,7 +247,7 @@ const FormPanel = ({ formData }) => {
x
</FormLabel>
<FormLabel sx={{ paddingLeft: 2, paddingRight: 2, textAlign: "center" }}>
${formik.values.price ? formik.values.price : 0}
${formik.values.price ? formik.values.price : "6,552"}
</FormLabel>
</Stack>
</Grid>
@@ -194,10 +258,10 @@ const FormPanel = ({ formData }) => {
fullWidth
size="small"
type="text"
onChange={(event)=>{
onChange={(event) => {
const value = event.target.value;
formik.setFieldValue("length", value);
formik.setFieldValue("fee", columnPrice.value*value);
formik.setFieldValue("fee", columnPrice.value * value);
}}
name="length"
value={formik.values["length"]}
@@ -232,7 +296,7 @@ const FormPanel = ({ formData }) => {
getOptionLabel={(option) => option.label ? option.label : ""}
onChange={(event, newValue) => {
setColumnPrice(newValue)
formik.values["fee"] = newValue.value*formik.values.length;
formik.values["fee"] = newValue.value * formik.values.length;
}}
renderInput={(params) => (
<TextField {...params}
@@ -304,7 +368,7 @@ const FormPanel = ({ formData }) => {
</form>
<div>
<Dialog open={isWarningPopUp} onClose={() => setIsWarningPopUp(false)} >
<DialogTitle>注意</DialogTitle>
<DialogTitle>Warning</DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h3" style={{ padding: '16px' }}>{warningText}</Typography>
</DialogContent>


+ 246
- 0
src/pages/ProofReply_Public/ApplicationDetails.js View File

@@ -0,0 +1,246 @@
// material-ui
import {
FormControl,
Grid,
Typography,
FormLabel,
TextField,
Stack
} from '@mui/material';

import { useFormik } from 'formik';
import * as React from "react";
import * as DateUtils from "utils/DateUtils"
import { useParams } from "react-router-dom";
import Loadable from 'components/Loadable';
const MainCard = Loadable(React.lazy(() => import('components/MainCard')));
import * as StatusUtils from "../PublicNotice/ListPanel/PublicNoteStatusUtils";
import FileList from "components/FileList"
// ==============================|| DASHBOARD - DEFAULT ||============================== //
const ApplicationDetailCard = ({ formData, }) => {

const params = useParams();

const [data, setData] = React.useState({});
//const [proofId, setProofId] = React.useState();

React.useEffect(() => {
if (formData) {
setData(formData);
//setProofId(formData.id);
}
}, [formData]);

const formik = useFormik({
enableReinitialize: true,
initialValues: data,
});

const DisplayField = ({ name, width }) => {
return <TextField
fullWidth
disabled
size="small"
onChange={formik.handleChange}
id={name}
name={name}
value={formik.values[name]}
variant="outlined"
sx={
{
"& .MuiInputBase-input.Mui-disabled": {
WebkitTextFillColor: "#000000",
background: "#f8f8f8",
},
width: width ? width : '100%'
}
}
/>;
}

function currencyFormat(num) {
let val = num ? num : 0;
return val.toLocaleString('en-US', {
minimumFractionDigits: 2
});
}


return (
<MainCard elevation={0}
border={false}
content={false}
>
<Typography variant="h5" sx={{ textAlign: "left", mb: 2, borderBottom: "1px solid black" }}>
公共啟事:校對資料
</Typography>
<form>
<Grid container direction="column">
<Grid item xs={12} md={12} lg={12}>
<Grid container direction="row" justifyContent="space-between"
alignItems="center">
<Grid item xs={12} md={6} lg={6} sx={{ mb: 1 }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>申請編號:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
<DisplayField name="appNo" />
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={5} lg={5} sx={{ mb: 1, ml: 1 }}>
<Grid container alignItems={"left"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>申請狀態:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9} sx={{ display: 'flex', alignItems: 'center' }}>
<FormControl variant="outlined">
{StatusUtils.getStatusByText(data.appStatus)}
</FormControl>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid container direction="row" justifyContent="space-between"
alignItems="center">
<Grid item xs={12} md={6} lg={6} sx={{ mb: 1 }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>申請人:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
<FormControl variant="outlined" fullWidth disabled >
{data.orgId === null ?
<DisplayField name="contactPerson" />
:
<DisplayField name="applicant" />
}
</FormControl>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={5} lg={5} sx={{ mb: 1, ml: 1 }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>憲報期數:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
<DisplayField name="issueNoStr" />
</Grid>
</Grid>
</Grid>
</Grid>
<Grid container direction="row" justifyContent="space-between"
alignItems="center">
<Grid item xs={12} md={6} lg={6} sx={{ mb: 1 }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>聯絡人:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
<DisplayField name="contactPerson" />

</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={5} lg={5} sx={{ mb: 1, ml: 1 }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>刊出日期:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
<DisplayField name="issueDateStr" />
</Grid>
</Grid>
</Grid>
</Grid>
<Grid container direction="row" justifyContent="space-between"
alignItems="center">
<Grid item xs={12} md={6} lg={6} sx={{ mb: 1, }}>
<Grid container alignItems="left">
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel>我的備注:</FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
<Stack direction="row">
<DisplayField name="appRemarks" />
</Stack>
</Grid>
</Grid>
</Grid>
</Grid>

<Grid container direction="row" justifyContent="space-between"
alignItems="center">

<Grid item xs={12} md={6} lg={6} sx={{ mb: 1, }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={12} lg={12} sx={{ display: 'flex', alignItems: 'center' }}>
<Typography>請下載下列印刷稿檔案,並仔細校對:</Typography>
</Grid>
</Grid>
<FileList
lang="ch"
refId={params.id}
refType={"proof"}
dateHideable={true}
disablePagination
disableSelectionOnClick
disableColumnMenu
disableColumnSelector
hideFooter
/>
</Grid>

<Grid item xs={12} md={4} lg={4} sx={{ mb: 1, }}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={12} lg={12}
sx={{ display: 'flex', alignItems: 'center' }}>
<Typography>繳費及返稿最後限期:</Typography>
</Grid>
<Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}>
<Typography>{DateUtils.dateStr_Cht(data.returnBeforeDate)} 下午 2:00前</Typography>
</Grid>
<Grid item xs={12} md={3} lg={3}
sx={{ mb: 1, display: 'flex', alignItems: 'center' }}>
<Typography>應繳費用:</Typography>
</Grid>
<Grid item xs={12} md={9} lg={9} sx={{ mb: 1, display: 'flex', alignItems: 'center' }}>
<Typography style={{ color: "blue", fontWeight: "bold", }}>{currencyFormat(data.fee)}</Typography>
</Grid>
<Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}>
{
formik.values.groupType == "A"
?
<Typography>( {data.noOfPages} 頁 x $6,552 )</Typography>
:
<Typography>( {data.length} cm x {data.colCount == 2 ? "$364 二格位" : "$182 一格位"} )</Typography>
}
</Grid>
</Grid>
</Grid>
</Grid>

</Grid>
</Grid>
</form>
</MainCard>
);
};

export default ApplicationDetailCard;

+ 302
- 0
src/pages/ProofReply_Public/ProofForm.js View File

@@ -0,0 +1,302 @@
// material-ui
import {
Dialog, DialogTitle, DialogContent, DialogActions,
Typography,
Grid,
Stack,
TextField,
FormLabel,
Button,
RadioGroup, Radio,
FormControlLabel
} from '@mui/material';
import * as UrlUtils from "utils/ApiPathConst";
import * as HttpUtils from "utils/HttpUtils";
import FileList from "components/FileList"
import MainCard from "components/MainCard";
import * as React from "react";
import * as yup from 'yup';
import { useParams } from "react-router-dom";
import { useFormik } from 'formik';
import { useNavigate } from "react-router-dom";
import * as DateUtils from "utils/DateUtils"
import Loadable from 'components/Loadable';
const UploadFileTable = Loadable(React.lazy(() => import('./UploadFileTable')));

// ==============================|| DASHBOARD - DEFAULT ||============================== //


const FormPanel = ({ formData }) => {

const [data, setData] = React.useState({});
const [attachments, setAttachments] = React.useState([]);

const [actionValue, setActionValue] = React.useState(true);

const [isWarningPopUp, setIsWarningPopUp] = React.useState(false);
const [warningText, setWarningText] = React.useState("");

const navigate = useNavigate()
const params = useParams();

React.useEffect(() => {
if (formData) {
setData(formData);
}
}, [formData]);

const formik = useFormik({
enableReinitialize: true,
initialValues: data,
validationSchema: yup.object().shape({
vaild: yup.string().max(255, "請輸入你的登入密碼").required('請輸入你的登入密碼'),
}),
onSubmit: values => {
if (!actionValue) {
if (!attachments || attachments.length <= 0) {
setWarningText("請選擇上傳檔案");
setIsWarningPopUp(true);
return;
}
}

if(isOverTime()){
setWarningText("回覆逾時,請重新申請。");
setIsWarningPopUp(true);
return;
}
// console.log(values);
HttpUtils.postWithFiles({
url: UrlUtils.REPLY_PROOF,
params: {
id: data.id,
action: actionValue,
vaild: values.vaild,
},
files: attachments ? attachments : [],
onSuccess: function () {
navigate("/proof/search");
},
onFail: function (response) {
setWarningText("行動失敗: 請檢查內容並再次提交回覆");
setIsWarningPopUp(true);
console.log(response);
},
onError: function (error) {
setWarningText("行動失敗: 請檢查內容並再次提交回覆");
setIsWarningPopUp(true);
console.log(error);
}
});
}
});

const readFile = (event) => {
let file = event.target.files[0];
if (file) {
if (!file.name.toLowerCase().substr(file.name.length - 4).includes(".pdf")) {
setWarningText("請上傳有效檔案 (檔案格式: .pdf)");
setIsWarningPopUp(true);
document.getElementById("uploadFileBtn").value = "";
return;
}
if (file.size >= (10 * 1024 * 1034)) {
setWarningText("上傳檔案大小應<10MB");
setIsWarningPopUp(true);
return;
}

file['id'] = attachments.length;
setAttachments([
...attachments,
file
]);
document.getElementById("uploadFileBtn").value = "";
}
}

const isOverTime = () => {
let returnBeforeDate = DateUtils.convertToDate(formik.values?.returnBeforeDate);
if (!returnBeforeDate) return true;
returnBeforeDate = returnBeforeDate.setHours(14, 0, 0, 0);

let current = new Date();
return current.getTime() > returnBeforeDate;
}



return (
<MainCard xs={12} md={12} lg={12}
border={false}
content={false}>

<Typography variant="h5" sx={{ textAlign: "left", mb: 2, borderBottom: "1px solid black" }}>
公共啟事:校對回覆
</Typography>

<form onSubmit={formik.handleSubmit}>

{
formik.values.replyDate ?
<Grid container direction="column" sx={{ paddingLeft: 4, paddingRight: 4 }} spacing={1}>
<Grid item xs={12} md={12} textAlign="left">
校對回覆日期: {DateUtils.datetimeStr_Cht(formik.values.replyDate)}
</Grid>
<Grid item xs={12} md={12} textAlign="left">
校對回覆: {formik.values.action ? "可以付印(稿件正確)" : "未能付印(需要修改)"}
</Grid>
{
formik.values.action ?
null
:
<Grid item xs={12} md={12} textAlign="left">
<FileList
lang="ch"
refId={params.id}
refType={"proofReply"}
dateHideable={true}
disablePagination
disableSelectionOnClick
disableColumnMenu
disableColumnSelector
hideFooter
/>
</Grid>
}

</Grid>
:
(
isOverTime() ?
<Grid container direction="column" sx={{ paddingLeft: 4, paddingRight: 4 }} spacing={1}>
<Grid item xs={12} md={12} textAlign="left">
回覆逾時,請重新申請。
</Grid>
</Grid>
:
<Grid container direction="column" sx={{ paddingLeft: 4, paddingRight: 4 }} spacing={1}>

<Grid item xs={12} md={12}>
<RadioGroup
aria-labelledby="demo-radio-buttons-group-label"
id="action"
name="action"
defaultValue={true}
onChange={(event)=>{
setActionValue(event.target.value=="true"?true:false);
}}
>
<FormControlLabel value={true} control={<Radio />} label="可以付印(稿件正確)" />
<FormControlLabel value={false} control={<Radio />} label="未能付印(需要修改)" />
</RadioGroup>
</Grid>


{
actionValue ?
null
:
<>
<Grid item xs={12} md={12} textAlign="left">
請上載稿件修改的檔案:
</Grid>

<Grid item xs={12} md={12} textAlign="left">
<input
id="uploadFileBtn"
name="file"
type="file"
accept=".pdf"
style={{ display: 'none' }}
disabled={attachments.length >= (formik.values.groupType == "A" ? 2 : 1)}
onChange={(event) => {
readFile(event)
}}
/>
<label htmlFor="uploadFileBtn">
<Button
component="span"
variant="contained"
size="large"
disabled={attachments.length >= (formik.values.groupType == "A" ? 2 : 1)}
>上載</Button>
</label>
</Grid>


<Grid item xs={12} md={12} textAlign="left">
<UploadFileTable key="uploadTable" recordList={attachments} setRecordList={setAttachments} />
</Grid>
</>
}

<Grid item xs={12} md={12} lg={12}>
<Stack direction="row" alignItems="center">
<FormLabel sx={{ paddingRight: 2, paddingBottom: 3, textAlign: "center" }}>
簽署:
</FormLabel>
<TextField
fullWidth
type="password"
onChange={formik.handleChange}
name="vaild"
variant="outlined"
error={Boolean(formik.errors["vaild"])}
helperText={formik.errors["vaild"] ? formik.errors["vaild"] : ' '}
placeholder="請輸入你的登入密碼"
sx={
{
"& .MuiInputBase-input.Mui-disabled": {
WebkitTextFillColor: "#000000",
background: "#f8f8f8",
},
width: '50%'
}
}
/>

</Stack>
</Grid>


<Grid item xs={12} md={12} textAlign="left">
<Button
size="large"
variant="contained"
color="success"
type="submit"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}>
提交回覆
</Button>
</Grid>

</Grid>

)


}



</form>
<div>
<Dialog open={isWarningPopUp} onClose={() => setIsWarningPopUp(false)} >
<DialogTitle>注意</DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h3" style={{ padding: '16px' }}>{warningText}</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setIsWarningPopUp(false)}>OK</Button>
</DialogActions>
</Dialog>
</div>
</MainCard>
);
};

export default FormPanel;

+ 111
- 0
src/pages/ProofReply_Public/UploadFileTable.js View File

@@ -0,0 +1,111 @@
// material-ui
import * as React from 'react';
import {
DataGrid,
GridActionsCellItem,
GridRowModes
} from "@mui/x-data-grid";
import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline';
import {useEffect} from "react";
// import {useNavigate} from "react-router-dom";
// import { useTheme } from '@mui/material/styles';
import {
Box,
Stack
} from '@mui/material';
// ==============================|| EVENT TABLE ||============================== //

export default function UploadFileTable({recordList, setRecordList,}) {
const [rows, setRows] = React.useState(recordList);
const [rowModesModel,setRowModesModel] = React.useState({});
// const theme = useTheme();

// const navigate = useNavigate()

useEffect(() => {
setRows(recordList);
// console.log(disableDelete);
}, [recordList]);

function NoRowsOverlay() {
return (
<Stack height="100%" alignItems="center" justifyContent="center">
No File Record
{/* <pre>(rows=&#123;[]&#125;)</pre> */}
</Stack>
);
}

const handleCancelClick = (id) => () => {
setRowModesModel({
...rowModesModel,
[id]: { mode: GridRowModes.View, ignoreModifications: true },
});
console.log("Starting Delete")
const editedRow = rows.find((row) => row.id === id);
console.log(editedRow)
console.log(editedRow.isNew)
setRecordList(rows.filter((row) => row.id !== id));
setRows(rows.filter((row) => row.id !== id));
}

const columns = [
{
field: 'actions',
type: 'actions',
headerName: '',
width: 30,
cellClassName: 'actions',
// hide:true,
getActions: ({id}) => {
return [
<GridActionsCellItem
key="OutSave"
icon={<RemoveCircleOutlineIcon/>}
label="delete"
className="textPrimary"
onClick={handleCancelClick(id)}
color="error"
/>]
},
},
{
id: 'name',
field: 'name',
headerName: '檔案名稱',
flex: 1,
},
{
id: 'size',
field: 'size',
headerName: '檔案大小',
valueGetter: (params) => {
// console.log(params)
return Math.ceil(params.value/1024)+" KB";
},
flex: 1,
},
];

return (
<Box
style={{ height: '200px', width: '75%' }}
>
<DataGrid
rows={rows}
columns={columns}
editMode="row"
sx={{border:1}}
rowModesModel={rowModesModel}
components={{ NoRowsOverlay, }}
// hideFooterPagination={true}
disablePagination
disableSelectionOnClick
disableColumnMenu
disableColumnSelector
hideFooter
/>
</Box>
);
}

+ 133
- 0
src/pages/ProofReply_Public/index.js View File

@@ -0,0 +1,133 @@
// material-ui
import {
Grid,
Typography,
Stack,
Box
} from '@mui/material';
import * as UrlUtils from "utils/ApiPathConst";
import * as React from "react";
import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";
import { useParams } 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')));
const ApplicationDetails = Loadable(React.lazy(() => import('./ApplicationDetails')));
const ProofForm = Loadable(React.lazy(() => import('./ProofForm')));
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'
}

// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
const params = useParams();
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 + "/" + params.id,
onSuccess: (responseData) => {
if(!responseData.data?.id){
navigate("/proof/search");
}
responseData.data["phoneNumber"] = JSON.parse(responseData.data.contactTelNo).phoneNumber;
responseData.data["tel_countryCode"] = JSON.parse(responseData.data.contactTelNo).countryCode;

responseData.data["faxNumber"] = JSON.parse(responseData.data.contactFaxNo).faxNumber;
responseData.data["fax_countryCode"] = JSON.parse(responseData.data.contactFaxNo).countryCode;

responseData.data["issueNoStr"] = responseData.data.issueYear
+ " Vol. " + zeroPad(responseData.data.issueVolume, 3)
+ ", No. " + zeroPad(responseData.data.issueNo, 2);

responseData.data["issueDateStr"] = DateUtils.dateFormat(responseData.data.issueDate, "D MMM YYYY (ddd)");

responseData.data["groupType"] = responseData.data.groupNo.charAt(0);
responseData.data["action"] = responseData.data.replyDate ? responseData.data.action : true;
setRecord(responseData.data);
}
});
}
}

function zeroPad(num, places) {
num = num ? num : 0;
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}


return (
!onReady ?
<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={{ pt: 2 }}>校對記錄</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={12} sx={{ pt: 2 }}>
<Box xs={12} md={12} sx={{ p: 4, border: '3px groove grey', borderRadius: '10px' }}>
<ApplicationDetails
formData={record}
style={{
display: "flex",
height: "100%",
flex: 1
}}
/>
</Box>
</Grid>
<Grid item xs={12} md={12} sx={{ pt: 1, pb: 2 }}>
<Box xs={12} md={12} sx={{ p: 4, border: '3px groove grey', borderRadius: '10px' }}>
<ProofForm
formData={record}
/>
</Box>
</Grid>
</center>
</Grid>
</Grid>
{/*row 2*/}
</Grid >

)


);
};

export default Index;

+ 5
- 11
src/pages/ProofSearch/SearchForm.js View File

@@ -17,7 +17,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria,issu
}) => {

const [type, setType] = React.useState([]);
const [status, setStatus] = React.useState({ key: 0, label: 'All', type: 'all' });
const [status, setStatus] = React.useState(ComboData.proofStatus[0]);
const [orgSelected, setOrgSelected] = React.useState({});
const [orgCombo, setOrgCombo] = React.useState();
const [issueSelected, setIssueSelected] = React.useState({});
@@ -66,7 +66,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria,issu

function resetForm() {
setType([]);
setStatus({ key: 0, label: 'All', type: 'all' });
setStatus(ComboData.proofStatus[0]);
setOrgSelected({});
setIssueSelected({});
setGroupSelected({});
@@ -138,9 +138,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria,issu
inputValue={(issueSelected?.id) ? getIssueLabel(issueSelected) : ""}
getOptionLabel={(option)=>getIssueLabel(option)}
onChange={(event, newValue) => {
if (newValue !== null) {
setIssueSelected(newValue);
}
setIssueSelected(newValue);
}}
renderInput={(params) => (
<TextField {...params}
@@ -163,9 +161,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria,issu
inputValue={(groupSelected?.label)?groupSelected?.label:""}
getOptionLabel={(option)=>option.label}
onChange={(event, newValue) => {
if (newValue !== null) {
setGroupSelected(newValue);
}
setGroupSelected(newValue);
}}
renderInput={(params) => (
<TextField {...params}
@@ -264,9 +260,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria,issu
value={orgSelected}
inputValue={(orgSelected?.label) ? orgSelected?.label : ""}
onChange={(event, newValue) => {
if (newValue !== null) {
setOrgSelected(newValue);
}
setOrgSelected(newValue);
}}
renderInput={(params) => (
<TextField {...params}


+ 144
- 0
src/pages/ProofSearch_Public/DataGrid.js View File

@@ -0,0 +1,144 @@
// material-ui
import * as React from 'react';
import {
Button
} from '@mui/material';
import * as DateUtils from "utils/DateUtils";
import { useNavigate } from "react-router-dom";
import { FiDataGrid } from "components/FiDataGrid";
// ==============================|| EVENT TABLE ||============================== //

export default function SearchPublicNoticeTable({ recordList }) {
const [rows, setRows] = React.useState(recordList);
const navigate = useNavigate()

React.useEffect(() => {
setRows(recordList);
}, [recordList]);

const handleEditClick = (params) => () => {
navigate('/proof/reply/' + params.row.id);
};

const getGroupTitle = (title) => {
switch (title) {
case 'Private Bill':
return "私人帳單";
case 'Companies Ordinance':
return "公司條例";
case 'High Court':
return "高等法院";
case 'Notices':
return "通知";
case 'Miscellaneous (Companies)':
return "其他";
default:
return title;
}
}


const columns = [
{
field: 'actions',
headerName: '校對編號',
width: 150,
cellClassName: 'actions',
renderCell: (params) => {
return <Button onClick={handleEditClick(params)}><u>{params.row.refNo}</u></Button>;
},
},
{
id: 'appId',
field: 'appId',
headerName: '申請編號/憲報編號/憲報期數',
flex: 1,
renderCell: (params) => {
let appNo = params.row.appNo;
let code = params.row.groupNo;
let isssue = params.row.issueYear
+ " Vol. " + zeroPad(params.row.issueVolume, 3)
+ ", No. " + zeroPad(params.row.issueNo, 2)
+ ", " + DateUtils.dateFormat(params.row.issueDate, "D MMM YYYY (ddd)");

return <div style={{ margin: 4 }}>申請編號: {appNo}<br />憲報編號: {code}<br />憲報期數: {isssue}</div>
},
},
{
id: 'returnBeforeDate',
field: 'returnBeforeDate',
headerName: '此日期前回覆',
flex: 1,
valueGetter: (params) => {
let returnBeforeDate = DateUtils.convertToDate(params?.value);
returnBeforeDate = returnBeforeDate.setHours(14, 0, 0, 0);
return DateUtils.datetimeStr_Cht(returnBeforeDate);
}
},
{
id: 'created',
field: 'created',
headerName: '校對日期',
flex: 1,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
},
{
id: 'replyDate',
field: 'replyDate',
headerName: '回覆日期',
flex: 1,
valueGetter: (params) => {
return params?.value ? DateUtils.datetimeStr(params?.value) : "";
}
},
{
id: 'groupTitle',
field: 'groupTitle',
headerName: '憲報類型',
flex: 1,
valueGetter: (params) => {
return getGroupTitle(params?.value);
}
},
{
id: 'fee',
field: 'fee',
headerName: '費用',
flex: 1,
valueGetter: (params) => {
return (params?.value) ? "$ " + currencyFormat(params?.value) : "";
}
},
];

function currencyFormat(num) {
return num.toLocaleString('en-US', {
minimumFractionDigits: 2
});
}


function zeroPad(num, places) {
num = num ? num : 0;
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}

return (
<div style={{ height: 400, width: '100%' }}>

<FiDataGrid
rowHeight={80}
rows={rows}
columns={columns}
initialState={{
pagination: {
paginationModel: { page: 0, pageSize: 5 },
},
}}
/>
</div>
);
}

+ 280
- 0
src/pages/ProofSearch_Public/SearchForm.js View File

@@ -0,0 +1,280 @@
// material-ui
import {
Button,
CardContent,
Grid, TextField,
Autocomplete
} from '@mui/material';
import MainCard from "components/MainCard";
import { useForm } from "react-hook-form";
import * as React from "react";
import * as ComboData from "utils/ComboData";
import * as DateUtils from "utils/DateUtils";
// ==============================|| DASHBOARD - DEFAULT ||============================== //


const SearchPublicNoticeForm = ({ applySearch, searchCriteria,issueComboData
}) => {

const [type, setType] = React.useState([]);
const [status, setStatus] = React.useState(ComboData.proofStatus[0]);
const [issueSelected, setIssueSelected] = React.useState({});
const [issueCombo, setIssueCombo] = React.useState([]);
const [groupSelected, setGroupSelected] = React.useState({});

const [minDate, setMinDate] = React.useState(searchCriteria.dateFrom);
const [maxDate, setMaxDate] = React.useState(searchCriteria.dateTo);


const { reset, register, handleSubmit } = useForm()
const onSubmit = (data) => {

let typeArray = [];

for (let i = 0; i < type.length; i++) {
typeArray.push(type[i].label);
}

const temp = {
refNo: data.refNo,
code: data.code,
issueId: issueSelected?.id,
gazettGroup: groupSelected?.type,
dateFrom: data.dateFrom,
dateTo: data.dateTo,
//contact: data.contact,
replyed: (status?.type && status?.type != 'all') ? status?.type : "",
};
applySearch(temp);
};


React.useEffect(() => {
if (issueComboData && issueComboData.length > 0) {
setIssueCombo(issueComboData);
}
}, [issueComboData]);

function resetForm() {
setType([]);
setStatus(ComboData.proofStatus[0]);
setIssueSelected({});
setGroupSelected({});
reset();
}

function getIssueLabel(data){
if(data=={}) return "";
return data.year
+" Vol. "+zeroPad(data.volume,3)
+", No. "+zeroPad(data.issueNo,2)
+", "+DateUtils.dateFormat(data.issueDate, "D MMM YYYY (ddd)");
}

function zeroPad(num, places) {
num=num?num:0;
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}

return (
<MainCard xs={12} md={12} lg={12}
border={false}
content={false}>

<form onSubmit={handleSubmit(onSubmit)}>
{/*row 1*/}
<CardContent sx={{ px: 2.5, pt: 3 }}>
<Grid item justifyContent="space-between" alignItems="center">
搜尋
</Grid>
</CardContent>

{/*row 2*/}
<Grid container alignItems={"center"}>
<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("refNo")}
id='refNo'
label="校對編號:"
defaultValue={searchCriteria.refNo}
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("code")}
id='code'
label="申請編號:"
defaultValue={searchCriteria.code}
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Autocomplete
{...register("issueId")}
disablePortal
id="issueId"
options={issueCombo}
value={issueSelected}
inputValue={(issueSelected?.id) ? getIssueLabel(issueSelected) : ""}
getOptionLabel={(option)=>getIssueLabel(option)}
onChange={(event, newValue) => {
setIssueSelected(newValue);
}}
renderInput={(params) => (
<TextField {...params}
label="憲報期數"
InputLabelProps={{
shrink: true
}}
/>
)}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Autocomplete
{...register("gazettGroup")}
disablePortal
id="gazettGroup"
options={ComboData.groupTitle}
value={groupSelected}
inputValue={(groupSelected?.labelCht)?groupSelected?.labelCht:""}
getOptionLabel={(option)=>option.labelCht}
onChange={(event, newValue) => {
setGroupSelected(newValue);
}}
renderInput={(params) => (
<TextField {...params}
label="憲報類型"
InputLabelProps={{
shrink: true
}}
/>
)}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("dateFrom")}
id="dateFrom"
type="date"
label="校對日期(從)"
defaultValue={searchCriteria.dateFrom}
InputProps={{ inputProps: { max: maxDate } }}
onChange={(newValue) => {
setMinDate(DateUtils.dateStr(newValue));
}}
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
InputLabelProps={{
shrink: true
}}
{...register("dateTo")}
InputProps={{ inputProps: { min: minDate } }}
onChange={(newValue) => {
setMaxDate(DateUtils.dateStr(newValue));
}}
id="dateTo"
type="date"
label="校對日期(到)"
defaultValue={searchCriteria.dateTo}
/>
</Grid>

{/* <Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("contact")}
id="contact"
label="聯絡人"
defaultValue={searchCriteria.contact}
InputLabelProps={{
shrink: true
}}
/>

</Grid> */}

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Autocomplete
{...register("status")}
disablePortal
id="status"
filterOptions={(options) => options}
options={ComboData.proofStatus}
value={status}
getOptionLabel={(option)=>option.labelCht}
inputValue={status?.labelCht?status?.labelCht:""}
onChange={(event, newValue) => {
if (newValue !== null) {
setStatus(newValue);
}
}}
renderInput={(params) => (
<TextField {...params}
label="狀態"
/>
)}
InputLabelProps={{
shrink: true
}}
/>
</Grid>

</Grid>


{/*last row*/}
<Grid container maxWidth justifyContent="flex-end">

<Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}>
<Button
size="large"
variant="contained"
onClick={resetForm}
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}>
重置
</Button>
</Grid>

<Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}>
<Button
size="large"
variant="contained"
type="submit"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}>
提交
</Button>
</Grid>
</Grid>
</form>
</MainCard>
);
};

export default SearchPublicNoticeForm;

+ 113
- 0
src/pages/ProofSearch_Public/index.js View File

@@ -0,0 +1,113 @@
// material-ui
import {
Grid,
Typography,
Stack
} from '@mui/material';
import MainCard from "components/MainCard";
import * as UrlUtils from "utils/ApiPathConst";
import * as React from "react";
import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";

import Loadable from 'components/Loadable';
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent')));
const SearchForm = Loadable(React.lazy(() => import('./SearchForm')));
const EventTable = Loadable(React.lazy(() => import('./DataGrid')));
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'
}

// ==============================|| DASHBOARD - DEFAULT ||============================== //

const UserSearchPage_Individual = () => {

const [record,setRecord] = React.useState([]);
const [issueCombo,setIssueCombo] = React.useState([]);
const [searchCriteria, setSearchCriteria] = React.useState({
dateTo: DateUtils.dateStr(new Date()),
dateFrom: DateUtils.dateStr(new Date().setDate(new Date().getDate()-14)),
});
const [onReady, setOnReady] = React.useState(false);

React.useEffect(() => {
getIssueCombo();
}, []);

React.useEffect(() => {
setOnReady(true);
}, [record]);

React.useEffect(() => {
loadGrid();
}, [searchCriteria]);

function loadGrid(){
HttpUtils.get({
url: UrlUtils.LIST_PROOF,
params: searchCriteria,
onSuccess: function(responseData){
setRecord(responseData);
}
});
}

function getIssueCombo(){
HttpUtils.get({
url: UrlUtils.GET_ISSUE_COMBO,
onSuccess: function(responseData){
let combo = responseData;
setIssueCombo(combo);
}
});
}

function applySearch(input) {
setSearchCriteria(input);
}

return (
!onReady ?
<LoadingComponent/>
:
<Grid container sx={{minHeight: '85vh',backgroundColor:'#ffffff'}} direction="column">
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4">校對記錄</Typography>
</Stack>
</div>
</Grid>
{/*row 1*/}
<Grid item xs={12} md={12} lg={12}>
<SearchForm
applySearch={applySearch}
issueComboData={issueCombo}
searchCriteria={searchCriteria}
/>
</Grid>
{/*row 2*/}
<Grid item xs={12} md={12} lg={12}>
<MainCard elevation={0}
border={false}
content={false}
>
<EventTable
recordList={record}
/>
</MainCard>
</Grid>
</Grid>
);
};

export default UserSearchPage_Individual;

+ 2
- 1
src/pages/PublicNotice/ListPanel/SearchPublicNoticeForm.js View File

@@ -135,7 +135,8 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria }) => {
ComboData.publicNoticeStatic
}
values={status}
inputValue={status?.label}
inputValue={status?.labelCht}
getOptionLabel={(option)=>option.labelCht}
onChange={(event, newValue) => {
if (newValue !== null) {
setStatus(newValue);


+ 26
- 5
src/pages/PublicNoticeDetail_GLD/ApplicationDetailCard.js View File

@@ -5,7 +5,8 @@ import {
Grid,
Typography, FormLabel,
OutlinedInput,
Stack
Stack,
Dialog, DialogTitle, DialogContent, DialogActions,
} from '@mui/material';
const MainCard = Loadable(lazy(() => import('components/MainCard')));
import { useForm } from "react-hook-form";
@@ -43,6 +44,9 @@ const ApplicationDetailCard = (

const { register } = useForm()

const [isWarningPopUp, setIsWarningPopUp] = useState(false);
const [warningText, setWarningText] = useState("");

useEffect(() => {
//if user data from parent are not null
// console.log(applicationDetailData)
@@ -94,8 +98,14 @@ const ApplicationDetailCard = (
};

const onProofClick = () => {
window.open("/proof/create/" + currentApplicationDetailData.id, "_blank", "noreferrer");
window.addEventListener("focus", onFocus)
if (applicationDetailData.data.groupNo) {
window.open("/proof/create/" + currentApplicationDetailData.id, "_blank", "noreferrer");
window.addEventListener("focus", onFocus)
}else{
setWarningText("Please generate Gazette Code before Create Proof.");
setIsWarningPopUp(true);
}

}

const onFocus = () => {
@@ -145,14 +155,14 @@ const ApplicationDetailCard = (
spacing={2}
mb={2}
>
{currentApplicationDetailData.status == "submitted"||currentApplicationDetailData.status == "reviewed" ?
{currentApplicationDetailData.status == "submitted" || currentApplicationDetailData.status == "reviewed" ?
<>
<Button
// size="large"
variant="contained"
onClick={reSubmitClick()}
color="orange"
>
>
<ReplayIcon />
<Typography ml={1}> Re-submit</Typography>
</Button>
@@ -481,6 +491,17 @@ const ApplicationDetailCard = (
</Grid>
</Grid>
</form>
<div>
<Dialog open={isWarningPopUp} onClose={() => setIsWarningPopUp(false)} >
<DialogTitle>Warning</DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h3" style={{ padding: '16px' }}>{warningText}</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setIsWarningPopUp(false)}>OK</Button>
</DialogActions>
</Dialog>
</div>
</MainCard>
);
};


+ 12
- 7
src/pages/PublicNoticeDetail_GLD/index.js View File

@@ -43,6 +43,7 @@ const PublicNoticeDetail_GLD = () => {
const params = useParams();
// const navigate = useNavigate()
const [applicationDetailData, setApplicationDetailData] = useState({});
const [proofList, setProofList] = useState([]);
// const [refApplicationDetailData, setRefApplicationDetailData] = React.useState({});
const [isLoading, setLoading] = useState(false);
const LoadingComponent = Loadable(lazy(() => import('../extra-pages/LoadingComponent')));
@@ -83,7 +84,7 @@ const PublicNoticeDetail_GLD = () => {
const title = groupNo != null ? ("Application / " + appNo + ", " + gazetteIssue + ", " + issueNum + " , " + groupNo) : ("Application / " + appNo + ", " + gazetteIssue + ", " + issueNum)

useEffect(() => {
loadApplicationDetail()
loadApplicationDetail();
}, []);

// useEffect(() => {
@@ -110,6 +111,7 @@ const PublicNoticeDetail_GLD = () => {
setIssueNum(" No. " + gazetteIssueDetail.issueNo);
setIssueDate(DateUtils.dateFormat(gazetteIssueDetail.issueDate, "D MMM YYYY (ddd)"));
setGroupNo(response.data.data.groupNo);
setProofList(response.data.proofList);
setLoading(false);
}
})
@@ -171,9 +173,9 @@ const PublicNoticeDetail_GLD = () => {
onComplatedClick()
} else if (getStatus == "withdraw") {
onWithdrawnClick()
} else if (getStatus == "notAccepted"){
} else if (getStatus == "notAccepted") {
onNotAcceptClick(getReason);
} else if (getStatus == "resubmit"){
} else if (getStatus == "resubmit") {
onReSubmitClick();
}
}
@@ -266,8 +268,8 @@ const PublicNoticeDetail_GLD = () => {
};

useEffect(() => {
const status = applicationDetailData.data!=undefined?applicationDetailData.data.status:""
if(status === "submitted" && params.id > 0 && getUploadStatus){
const status = applicationDetailData.data != undefined ? applicationDetailData.data.status : ""
if (status === "submitted" && params.id > 0 && getUploadStatus) {
axios.get(`${SET_PUBLIC_NOTICE_STATUS_REVIEWED}/${params.id}`)
.then((response) => {
if (response.status === 204) {
@@ -279,7 +281,7 @@ const PublicNoticeDetail_GLD = () => {
console.log(error);
return false;
});
}else{
} else {
setUploadStatus(false);
}
}, [getUploadStatus]);
@@ -346,7 +348,10 @@ const PublicNoticeDetail_GLD = () => {
</Grid>
<Grid item xs={12} md={10}>
<Box xs={12} ml={4} mt={3}>
<TabTableDetail applicationDetailData={applicationDetailData} />
<TabTableDetail
applicationDetailData={applicationDetailData}
proofList={proofList}
/>
</Box>
</Grid>
</Grid>


+ 29
- 30
src/pages/PublicNoticeDetail_GLD/tabTableDetail/ProofTab.js View File

@@ -1,54 +1,53 @@
// material-ui
import * as React from 'react';
import * as DateUtils from "utils/DateUtils";
import {FiDataGrid} from "components/FiDataGrid";
import {
Button
} from '@mui/material';
// ==============================|| EVENT TABLE ||============================== //

export default function ProofTab({rows}) {

function currencyFormat(num) {
return num.toLocaleString('en-US', {
minimumFractionDigits: 2
});
}


const columns = [
{
id: 'proofRef',
field: 'proofRef',
headerName: 'Proof Ref.',
id: 'refNo',
field: 'refNo',
headerName: 'Proof No.',
flex: 1,
},
{
id: 'proofSent',
field: 'proofSent',
headerName: 'Proof Return',
id: 'created',
field: 'created',
headerName: 'Proof Date',
flex: 1,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
},
{
id: 'proofReturn',
field: 'proofReturn',
headerName: 'Proof Return',
flex: 1,
},
{
id: 'status',
field: 'status',
headerName: 'Status',
id: 'replyDate',
field: 'replyDate',
headerName: 'Confirmed/Return Date',
flex: 1,
valueGetter: (params) => {
return params?.value?DateUtils.datetimeStr(params?.value):"";
}
},
{
id: 'fee',
field: 'fee',
headerName: 'Fee (HKD)',
flex: 2,
headerName: 'Fee',
flex: 1,
valueGetter: (params) => {
return (params?.value)?"$ "+currencyFormat(params?.value):"";
}
},
{
field: 'detail',
type: 'actions',
headerName: '',
width: 50,
cellClassName: 'actions',
renderCell: () => {
return <Button onClick={()=>{}}>查看詳細</Button>;
},
}
];

return (


+ 9
- 12
src/pages/PublicNoticeDetail_GLD/tabTableDetail/TabTable.js View File

@@ -21,31 +21,28 @@ const ProofTab = Loadable(lazy(() => import('./ProofTab')));

// ==============================|| DASHBOARD - DEFAULT ||============================== //

const PublicNotice = ({applicationDetailData}) => {
const [submittedList, ] = React.useState([]);
const [inProgressList, ] = React.useState([]);
const PublicNotice = ({applicationDetailData, proofList}) => {
const [_proofList, setProofList] = React.useState([]);
const [inProgressList,] = React.useState([]);
const [onReady,setOnReady] = React.useState(false);
const [selectedTab, setSelectedTab] = React.useState("1");
// const navigate = useNavigate();
const [statusHistoryList, setStatusHistoryList] = React.useState([]);


// useEffect(() => {
// loadData();
// }, []);

const reloadPage = () => {
window.location.reload(false);
}

React.useEffect(() => {
//if user data from parent are not null
// console.log(applicationDetailData)
if (Object.keys(applicationDetailData).length > 0) {
setStatusHistoryList(applicationDetailData.statusHistoryList);
}
}, [applicationDetailData]);

React.useEffect(() => {
setProofList(proofList);
}, [proofList]);

React.useEffect(() => {
//if state data are ready and assign to different field
if (statusHistoryList.length > 0) {
@@ -75,14 +72,14 @@ const PublicNotice = ({applicationDetailData}) => {
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<Tab label={"Proof(" + submittedList.length + ")"} value="1" />
<Tab label={"Proof(" + (_proofList?.length?_proofList?.length:0) + ")"} value="1" />
<Tab label={"Payment(" + inProgressList.length + ")"} value="2" />
<Tab label={"Status History(" + statusHistoryList.length + ")"} value="3" />
</TabList>
</Box>
<TabPanel value="1">
<ProofTab
rows={submittedList}
rows={_proofList}
reloadFunction={reloadPage}
/>
</TabPanel>


+ 7
- 11
src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js View File

@@ -32,7 +32,7 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
setOnReady(true);
}
}, [currentUserData]);
const formik = useFormik({
enableReinitialize: true,
initialValues: currentUserData,
@@ -134,9 +134,9 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
border={false}
content={false}
>
{!onReady?
<LoadingComponent />
:
{!onReady ?
<LoadingComponent />
:
<form onSubmit={formik.handleSubmit} style={{ padding: 24 }}>

{/*top button*/}
@@ -293,14 +293,14 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {

<Grid item lg={4}>
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3} sx={{ display: 'flex', alignItems: 'center' }}>
<Grid item xs={12} md={3} lg={3} sx={{ display: 'flex', alignItems: 'center' }}>
Verified:
</Grid>


{
currentUserData.verifiedBy || editMode ?
<Grid item xs={12} md={6} lg={6}>
<Grid item xs={12} md={6} lg={6}>
{FieldUtils.initField({
valueName: "verifiedStatus",
disabled: true,
@@ -341,7 +341,7 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
ID No.:
</Grid>

<Grid item xs={12} md={6} lg={6}>
<Grid item xs={12} md={6} lg={6}>
<Grid container>
{formik.values.idDocType == "HKID" ?
<>
@@ -502,12 +502,8 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
form: formik
})}
</Grid>


</Grid>



</form>
}
</MainCard>


+ 10
- 0
src/routes/PublicUserRoutes.js View File

@@ -11,6 +11,8 @@ const ManageOrgUser = Loadable(lazy(() => import('pages/ManageOrgUserPage')));
const PublicNotice = Loadable(lazy(() => import('pages/PublicNotice/ListPanel')));
const PublicNoticeApplyForm = Loadable(lazy(() => import('pages/PublicNotice/ApplyForm')));
const PublicNoticeDetail = Loadable(lazy(() => import('pages/PublicNoticeDetail')));
const ProofReply = Loadable(lazy(() => import('pages/ProofReply_Public')));
const ProofSearch = Loadable(lazy(() => import('pages/ProofSearch_Public')));

// ==============================|| MAIN ROUTING ||============================== //

@@ -45,6 +47,14 @@ const PublicDashboard = {
path: 'publicNotice/:id',
element: <PublicNoticeDetail/>
},
{
path: 'proof/reply/:id',
element: <ProofReply/>
},
{
path: 'proof/search',
element: <ProofSearch/>
},
]
},
]


+ 4
- 1
src/utils/ApiPathConst.js View File

@@ -71,8 +71,11 @@ export const UPDATE_PUBLIC_NOTICE_APPLY_DETAIL = apiPath+'/application/save';
export const GET_ISSUE_COMBO = apiPath+'/gazette-issue/combo';

export const LIST_PROOF = apiPath+'/proof/list';//GET
export const GET_PROOF_APP = apiPath+'/proof/create-from-app';//GET
export const GET_PROOF_APP = apiPath+'/proof/create-from-app';//GLD
export const CREATE_PROOF = apiPath+'/proof/create';//POST
export const GET_PROOF = apiPath+'/proof/details';//GET
export const REPLY_PROOF = apiPath+'/proof/reply';//GET
export const PROOF_CHECK_PRICE = apiPath+'/proof/check-price';//GET

//User Group
export const POST_AND_UPDATE_USER_GROUP = apiPath+'/group/save';

+ 26
- 49
src/utils/ComboData.js View File

@@ -12,52 +12,29 @@ export const country = ["香港","內地","澳門"];
export const accountFilter = [{ id: 1, key: 1, label: 'Active', type: 'active' }, { id: 2, key: 2, label: 'Locked', type: 'locked' }, { id: 3, key: 3, label: 'Not verified', type: 'notVerified' }];

export const publicNoticeStatic = [
{ key: 0, label: '全部', type: 'all' },
{ key: 1, label: '處理中', type: 'processing' }, // submitted and reviewed
{ key: 2, label: '待付款', type: 'confirmed' },
{ key: 3, label: '待發布', type: 'paid' },
{ key: 4, label: '已完成', type: 'completed' },
{ key: 5, label: '不接受', type: 'notAccepted' },
{ key: 6, label: '需重新提交', type: 'resubmit' },
{ key: 7, label: '已取消', type: 'cancelled' },
{ key: 8, label: '已撤銷', type: 'withdrawn' },
{ key: 0, labelCht: '全部', label: 'All', type: 'all' },
{ key: 1, labelCht: '處理中', label: 'Processing', type: 'processing' }, // submitted and reviewed
{ key: 2, labelCht: '待付款', label: 'Pending Payment', type: 'confirmed' },
{ key: 3, labelCht: '待發布', label: 'To be published', type: 'paid' },
{ key: 4, labelCht: '已完成', label: 'Completed', type: 'completed' },
{ key: 5, labelCht: '不接受', label: 'Not accepted', type: 'notAccepted' },
{ key: 6, labelCht: '需重新提交', label: 'Re-submit Required', type: 'resubmit' },
{ key: 7, labelCht: '已取消', label: 'Cancelled', type: 'cancelled' },
{ key: 8, labelCht: '已撤銷', label: 'Withdrawn', type: 'withdrawn' },
];

export const publicNoticeStatic_Creditor = [
{ key: 0, label: '全部', type: 'all' },
{ key: 1, label: '處理中', type: 'processing' }, // submitted and reviewed
{ key: 2, label: '待發布', type: 'confirmed' },
{ key: 3, label: '待付款', type: 'published' },
{ key: 4, label: '已完成', type: 'completed' },
{ key: 5, label: '不接受', type: 'notAccepted' },
{ key: 6, label: '需重新提交', type: 'resubmit' },
{ key: 7, label: '已取消', type: 'cancelled' },
{ key: 8, label: '已撤銷', type: 'withdrawn' },
{ key: 0, labelCht: '全部', label: 'All', type: 'all' },
{ key: 1, labelCht: '處理中', label: 'Processing', type: 'processing' }, // submitted and reviewed
{ key: 2, labelCht: '待發布', label: 'To be published', type: 'confirmed' },
{ key: 3, labelCht: '待付款', label: 'Pending Payment', type: 'published' },
{ key: 4, labelCht: '已完成', label: 'Completed', type: 'completed' },
{ key: 5, labelCht: '不接受', label: 'Not accepted', type: 'notAccepted' },
{ key: 6, labelCht: '需重新提交', label: 'Re-submit Required', type: 'resubmit' },
{ key: 7, labelCht: '已取消', label: 'Cancelled', type: 'cancelled' },
{ key: 8, labelCht: '已撤銷', label: 'Withdrawn', type: 'withdrawn' },
];

export const publicNoticeStaticEng = [
{ key: 0, label: 'All', type: 'all' },
{ key: 1, label: 'Processing', type: 'processing' }, // submitted and reviewed
{ key: 2, label: 'Pending Payment', type: 'confirmed' },
{ key: 3, label: 'To be published', type: 'paid' },
{ key: 4, label: 'Completed', type: 'completed' },
{ key: 5, label: 'Not accepted', type: 'notAccepted' },
{ key: 6, label: 'Re-submit Required', type: 'resubmit' },
{ key: 7, label: 'Cancelled', type: 'cancelled' },
{ key: 8, label: 'Withdrawn', type: 'withdrawn' },
];

export const publicNoticeStaticEng_Creditor = [
{ key: 0, label: 'All', type: 'all' },
{ key: 1, label: 'Processing', type: 'processing' }, // submitted and reviewed
{ key: 2, label: 'To be published', type: 'confirmed' },
{ key: 3, label: 'Pending Payment', type: 'published' },
{ key: 4, label: 'Completed', type: 'completed' },
{ key: 5, label: 'Not accepted', type: 'notAccepted' },
{ key: 6, label: 'Re-submit Required', type: 'resubmit' },
{ key: 7, label: 'Cancelled', type: 'cancelled' },
{ key: 8, label: 'Withdrawn', type: 'withdrawn' },
];

export const publicNoticeStatic_GLD = [
{ key: 0, label: 'All', type: 'all' },
@@ -75,11 +52,11 @@ export const publicNoticeStatic_GLD = [


export const groupTitle = [
{ key: 1, label: 'A - Private Bill', title: 'Private Bill', type: 'A'},
{ key: 2, label: 'B - Companies Ordinance', title: 'Companies Ordinance', type: 'B' },
{ key: 3, label: 'C - High Court', title: 'High Court', type: 'C' },
{ key: 4, label: 'D - Notices', title: 'Notices', type: 'D' },
{ key: 5, label: 'E - Miscellaneous (Companies)', title: 'Miscellaneous  (Companies)', type: 'E' },
{ key: 1, labelCht: 'A - 私人帳單', label: 'A - Private Bill', title: 'Private Bill', type: 'A'},
{ key: 2, labelCht: 'B - 公司條例', label: 'B - Companies Ordinance', title: 'Companies Ordinance', type: 'B' },
{ key: 3, labelCht: 'C - 高等法院', label: 'C - High Court', title: 'High Court', type: 'C' },
{ key: 4, labelCht: 'D - 通知', label: 'D - Notices', title: 'Notices', type: 'D' },
{ key: 5, labelCht: 'E - 其他', label: 'E - Miscellaneous (Companies)', title: 'Miscellaneous  (Companies)', type: 'E' },
];

export const proofPrice = [
@@ -88,7 +65,7 @@ export const proofPrice = [
];

export const proofStatus = [
{ key: 0, label: 'All', type: 'all' },
{ key: 1, label: 'Replyed', type: 'T' }, // submitted and reviewed
{ key: 2, label: 'Not reply yet', type: 'F' },
{ key: 0, labelCht: '全部', label: 'All', type: 'all' },
{ key: 1, labelCht: '已回覆', label:'Replyed', type: 'T' }, // submitted and reviewed
{ key: 2, labelCht: '未回覆', label:'Not reply yet', type: 'F' },
];

+ 9
- 1
src/utils/DateUtils.js View File

@@ -9,9 +9,17 @@ export const dateStr = (date) =>{
return dateFormat(date,"YYYY-MM-DD")
};

export const datetimeStr_Cht = (date) =>{
return dateFormat(date,"YYYY年MM月DD日 HH:mm:ss")
};

export const dateStr_Cht = (date) =>{
return dateFormat(date,"YYYY年MM月DD日")
};

export const convertToDate = (date)=>{
if(typeof date == 'number'){
return dayjs(date);
return dayjs(date).toDate();
}else if(Array.isArray(date)){
if(date.length==3){
return new Date(date[0],date[1]-1,date[2],0,0,0);


Loading…
Cancel
Save