Преглед изворни кода

update login log in user detail page

master
Alex Cheung пре 1 година
родитељ
комит
712762ed36
9 измењених фајлова са 633 додато и 38 уклоњено
  1. +198
    -0
      src/pages/AuditLog/UserSearchForm.js
  2. +142
    -0
      src/pages/AuditLog/UserTable.js
  3. +110
    -0
      src/pages/AuditLog/index.js
  4. +14
    -4
      src/pages/User/DetailsPage_Individual/LoginGrid.js
  5. +17
    -3
      src/pages/User/DetailsPage_Individual/index.js
  6. +81
    -0
      src/pages/User/DetailsPage_Organization/LoginGrid.js
  7. +65
    -31
      src/pages/User/DetailsPage_Organization/index.js
  8. +5
    -0
      src/routes/GLDUserRoutes.js
  9. +1
    -0
      src/utils/ApiPathConst.js

+ 198
- 0
src/pages/AuditLog/UserSearchForm.js Прегледај датотеку

@@ -0,0 +1,198 @@
// material-uisubDivision
import {
Button,
FormControlLabel,
Grid, TextField,
Typography
} from '@mui/material';
import MainCard from "components/MainCard";
import { useForm } from "react-hook-form";

import {
// useEffect,
useState
} from "react";

import Checkbox from "@mui/material/Checkbox";
import * as React from "react";
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import { useNavigate } from "react-router";
import axios from "axios";
import { GET_EMAIL_LIST } from 'utils/ApiPathConst';
import {PNSPS_BUTTON_THEME} from "themes/buttonConst";
import {ThemeProvider} from "@emotion/react";

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


const UserSearchForm = ({ applySearch }) => {
const navigate = useNavigate();

const [type, setType] = useState([]);
const [locked, setLocked] = useState(false);


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 = {
username: data.userName,
enName: data.fullenName,
post: data.post,
email: data.email,
locked: locked,
};
applySearch(temp);
};


function resetForm() {
setType([]);
setLocked(false);
reset();
axios.get(`${GET_EMAIL_LIST}`)
.then(r => {
console.log(r)
})
.catch(err => {
console.log(err)
})
}

const handleNewUserClick = () => {
// console.log(id)
navigate('/user/-1');
// navigate('/user/' + id);
};

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

<form onSubmit={handleSubmit(onSubmit)}>
<Grid container sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1}} width="98%">
{/*row 1*/}
<Grid item justifyContent="space-between" alignItems="center" sx={{mt:1,ml:3,mb:2.5}}>
<Typography variant="pnspsFormHeader" >
Search
</Typography>
</Grid>
{/*row 2*/}

<Grid container display="flex" alignItems={"center"}>
<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("userName")}
id='userName'
label="Username"
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("fullenName")}
id="fullenName"
label="Full Name"
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("post")}
id="post"
label="Post"
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<TextField
fullWidth
{...register("email")}
id="email"
label="Email"
InputLabelProps={{
shrink: true
}}
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<FormControlLabel
control={
<Checkbox
checked={locked}
onChange={(event) => setLocked(event.target.checked)}
name="checked"
color="primary"
size="small"
/>
}
label={<Typography variant="h6">Locked</Typography>}
/>
</Grid>
</Grid>

{/*last row*/}
<Grid container direction="row"
justifyContent="space-between"
alignItems="center">
<ThemeProvider theme={PNSPS_BUTTON_THEME}>

<Grid item xs={3} md={3} sx={{ ml: 3,mb: 3 }}>
<Button
variant="contained"
onClick={handleNewUserClick}
startIcon={<AddCircleOutlineIcon/>}
>
New User
</Button>
</Grid>
<Grid item xs={8} md={8}>
<Grid container maxWidth justifyContent="flex-end">
<Grid item sx={{ ml: 3, mr: 3, mb: 3,}}>
<Button
variant="contained"
onClick={resetForm}
>
Clear
</Button>
</Grid>

<Grid item sx={{ mb: 3 }}>
<Button
variant="contained"
type="submit"
>
Search
</Button>
</Grid>
</Grid>
</Grid>
</ThemeProvider>
</Grid>
</Grid>
</form>
</MainCard>
);
};

export default UserSearchForm;

+ 142
- 0
src/pages/AuditLog/UserTable.js Прегледај датотеку

@@ -0,0 +1,142 @@
// material-ui
import * as React from 'react';
import { GridActionsCellItem,} from "@mui/x-data-grid";
import {FiDataGrid} from "components/FiDataGrid";
import EditIcon from '@mui/icons-material/Edit';
import {useEffect} from "react";
import {useNavigate} from "react-router-dom";
import { useTheme } from '@mui/material/styles';
import Checkbox from '@mui/material/Checkbox';
import * as UrlUtils from "utils/ApiPathConst";
import * as HttpUtils from 'utils/HttpUtils';
import { notifyLockSuccess, notifyUnlockSuccess } from 'utils/CommonFunction';

// ==============================|| EVENT TABLE ||============================== //

export default function UserTable({recordList,setChangeLocked}) {
const [rows, setRows] = React.useState(recordList);
const theme = useTheme();

const navigate = useNavigate()

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

const handleEditClick = (id) => () => {
navigate('/user/'+ id);
};

const handleLock = (params) => () => {
setChangeLocked(false)
if (params.row.locked==true){
doUnlock(params.id)
}else{
doLock(params.id)
setRows(recordList);
}
}

const doLock = (id) => {
HttpUtils.get({
url: UrlUtils.GET_USER_LOCK+"/"+id,
onSuccess: function(){
setRows(recordList);
setChangeLocked(true)
notifyLockSuccess()
}
});
};

const doUnlock = (id) => {
HttpUtils.get({
url: UrlUtils.GET_USER_UNLOCK+"/"+id,
onSuccess: function(){
setRows(recordList);
setChangeLocked(true)
notifyUnlockSuccess()
}
});
};

const columns = [
{
field: 'actions',
type: 'actions',
headerName: 'Actions',
width: 100,
cellClassName: 'actions',
getActions: ({id}) => {
return [
<GridActionsCellItem
key="OutSave"
icon={<EditIcon/>}
label="Edit"
className="textPrimary"
onClick={handleEditClick(id)}
color="primary"
/>]
},
},
{
id: 'username',
field: 'username',
headerName: 'User Name',
flex: 1,
},
{
id: 'enName',
field: 'enName',
headerName: 'Full Name',
flex: 1,
},
{
id: 'post',
field: 'post',
headerName: 'Post',
flex: 1,
},
{
id: 'emailAddress',
field: 'emailAddress',
headerName: 'Email',
flex: 1,
},

{
id: 'locked',
field: 'locked',
type: 'bool',
headerName: 'Locked',
flex: 1,
renderCell: (params) => {
return (
<Checkbox
theme={theme}
key="locked"
checked={params.row.locked}
color="primary"
size="small"
onClick={handleLock(params)}
/>
);
},
},
];

function handleRowDoubleClick(params) {
navigate('/user/'+ params.id);
}

return (
<div style={{height: "fit-content", width: '100%'}}>
<FiDataGrid
rows={rows}
columns={columns}
customPageSize={5}
onRowDoubleClick={handleRowDoubleClick}
getRowHeight={() => 'auto'}
/>
</div>
);
}

+ 110
- 0
src/pages/AuditLog/index.js Прегледај датотеку

@@ -0,0 +1,110 @@
// material-ui
import {
Grid,
Typography,
Stack,
// Button
} from '@mui/material';
import MainCard from "components/MainCard";
import { useEffect, useState } from "react";
import axios from "axios";
import { GLD_USER_PATH } from "utils/ApiPathConst";
import * as React from "react";

import Loadable from 'components/Loadable';
import { lazy } from 'react';
const LoadingComponent = Loadable(lazy(() => import('../extra-pages/LoadingComponent')));
const SearchForm = Loadable(lazy(() => import('./UserSearchForm')));
const EventTable = Loadable(lazy(() => import('./UserTable')));
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 AuditLogPage = () => {
const [record, setRecord] = useState([]);
const [searchCriteria, setSearchCriteria] = useState({});
const [onReady, setOnReady] = useState(false);
const [changelocked, setChangeLocked] = React.useState(false);

React.useLayoutEffect(() => {
getUserList();
}, [changelocked]);

useEffect(() => {
if (record.length > 0) {
setOnReady(true);
}
}, [record]);

React.useLayoutEffect(() => {
getUserList();
}, [searchCriteria]);

function getUserList() {
axios.get(`${GLD_USER_PATH}`,
{ params: searchCriteria }
)
.then((response) => {
if (response.status === 200) {
setRecord(response.data);
}
})
.catch(error => {
console.log(error);
return false;
});
}

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

return (
!onReady ?
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center">
<Grid item>
<LoadingComponent />
</Grid>
</Grid>
:
<Grid container sx={{ minHeight: '87vh', backgroundColor: "backgroundColor.default" }} 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">View GLD User</Typography>
</Stack>
</div>
</Grid>

{/*row 1*/}
<Grid item xs={12} md={12} lg={12} sx={{mb:-1}}>
<SearchForm applySearch={applySearch} />
</Grid>
{/*row 2*/}
<Grid item xs={12} md={12} lg={12}>
<MainCard elevation={0}
border={false}
content={false}
>
<EventTable
recordList={record}
setChangeLocked={setChangeLocked}
/>
</MainCard>
</Grid>

</Grid>

);
};

export default AuditLogPage;

+ 14
- 4
src/pages/User/DetailsPage_Individual/LoginGrid.js Прегледај датотеку

@@ -46,10 +46,20 @@ export default function LoginGrid({rows}) {
field: 'result',
headerName: 'Result',
width: isMdOrLg ? 'auto' : 300,
flex: isMdOrLg ? 1 : undefined,
// valueGetter:(params)=>{
// return DateUtils.datetimeStr(params?.value);
// }
flex: isMdOrLg ? 2 : undefined,
valueGetter:(params)=>{
let resultMessage = "";
if (params.row.success>0){
resultMessage="Success"
}
if (params.row.success==0){
resultMessage="Fail"
}
if (params.row.success<0){
resultMessage= params.row.actionType + " by " + params.row.modifiedBy
}
return resultMessage;
}
},
];


+ 17
- 3
src/pages/User/DetailsPage_Individual/index.js Прегледај датотеку

@@ -43,6 +43,7 @@ const UserMaintainPage_Individual = () => {
const params = useParams();
const navigate = useNavigate();
const [formData, setFormData] = React.useState({})
const [loginLogData, setLoginLogData] = React.useState([])
const [isLoading, setLoding] = React.useState(true);
const [selectedTab, setSelectedTab] = React.useState("1");

@@ -90,6 +91,7 @@ const UserMaintainPage_Individual = () => {
response.data["preferLocale"] = getObjectByType(ComboData.Locale, "type", response.data?.preferLocale);
setFormData(response.data);
getLoginLogList()
}
});
}
@@ -121,10 +123,23 @@ const UserMaintainPage_Individual = () => {
}
};

const getLoginLogList = () => {
HttpUtils.get({
url: `${UrlUtils.GET_Login_Log_List}`,
params:{
userId:params.id
},
onSuccess: function (response) {
// console.log(response)
setLoginLogData(response);
}
});
}


React.useEffect(() => {
setLoding(false);
}, [formData]);
}, [loginLogData]);

return (
isLoading ?
@@ -195,8 +210,7 @@ const UserMaintainPage_Individual = () => {
</TabPanel>
<TabPanel value="2">
<LoginGrid
// refId={params.id}
// row={}
rows = {loginLogData}
/>
</TabPanel>
</TabContext>


+ 81
- 0
src/pages/User/DetailsPage_Organization/LoginGrid.js Прегледај датотеку

@@ -0,0 +1,81 @@
// material-ui
import * as React from 'react';
import {FiDataGrid} from "components/FiDataGrid";
import {
// Button,
// Typography,
useMediaQuery
} from '@mui/material';
import * as DateUtils from "utils/DateUtils"
// import {useNavigate} from "react-router-dom";
// import {
// isORGLoggedIn,
// } from "utils/Utils";
import {useTheme} from "@emotion/react";
// import {getStatusIntl} from "utils/statusUtils/PublicNoteStatusUtils";
// import {
// FormattedMessage,
// useIntl} from "react-intl";
// ==============================|| EVENT TABLE ||============================== //

export default function LoginGrid({rows}) {
// const navigate = useNavigate()
const theme = useTheme();
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));
// const intl = useIntl();

// const handleDetailClick = (params) => () => {
// navigate('/publicNotice/'+ params.id);
// };

// const remarkHeadername = rows.orgId===null?"我的備註":"Care Of / 我的備註"

const columns = [
{
id: 'loginTime',
field: 'loginTime',
headerName: "Date Time",
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
valueGetter:(params)=>{
return DateUtils.datetimeStr(params?.value);
}
},
{
id: 'result',
field: 'result',
headerName: 'Result',
width: isMdOrLg ? 'auto' : 300,
flex: isMdOrLg ? 2 : undefined,
valueGetter:(params)=>{
let resultMessage = "";
if (params.row.success>0){
resultMessage="Success"
}
if (params.row.success==0){
resultMessage="Fail"
}
if (params.row.success<0){
resultMessage= params.row.actionType + " by " + params.row.modifiedBy
}
return resultMessage;
}
},
];
// function handleRowDoubleClick(params) {
// navigate('/publicNotice/'+ params.id);
// }

return (
<div style={{minHeight: 200, height:"100%", width: '100%', padding: 4}}>
<FiDataGrid
rows={rows}
columns={columns}
customPageSize={10}
// onRowDoubleClick={handleRowDoubleClick}
getRowHeight={() => 'auto'}
/>
</div>
);
}

+ 65
- 31
src/pages/User/DetailsPage_Organization/index.js Прегледај датотеку

@@ -1,5 +1,7 @@
// material-ui
import { Grid, Typography, Stack, Box, Button } from '@mui/material';
import { Grid, Typography, Stack, Box, Button, Tab } from '@mui/material';
import { TabPanel, TabContext, TabList } from '@mui/lab';

import { useEffect, useState } from "react";
import * as React from "react";
//import axios from "axios";
@@ -20,6 +22,7 @@ import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import { useNavigate } from 'react-router-dom';
import * as ComboData from "utils/ComboData";
import {getObjectByValue,getObjectByType} from "utils/CommonFunction";
const LoginGrid = Loadable(React.lazy(() => import('./LoginGrid')));

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
@@ -45,32 +48,38 @@ const UserMaintainPage_Organization = () => {
const params = useParams();
const navigate = useNavigate();
const [userData, setUserData] = useState({})
const [loginLogData, setLoginLogData] = React.useState([])
const [orgData, setOrgData] = useState({})
const [isLoading, setLoding] = useState(true);
const intl = useIntl();
const { locale } = intl;
const [selectedTab, setSelectedTab] = React.useState("1");

const isPrimaryLocale = locale === 'en' ?"Yes":locale === 'zh-HK' ?"是":"是";
const notPrimaryLocale = locale === 'en' ?"No":locale === 'zh-HK' ?"否":"否";

const _sx = {
ml: 3,
mb: 3,
mt: 3,
mr: 6,
padding: "4 2 4 2",
boxShadow: 1,
border: 1,
borderColor: '#DDD',
'& .MuiDataGrid-cell': {
borderTop: 1,
borderBottom: 1,
borderColor: "#EEE"
},
'& .MuiDataGrid-footerContainer': {
border: 1,
borderColor: "#EEE"
}
// const _sx = {
// ml: 3,
// mb: 3,
// mt: 3,
// mr: 6,
// padding: "4 2 4 2",
// boxShadow: 1,
// border: 1,
// borderColor: '#DDD',
// '& .MuiDataGrid-cell': {
// borderTop: 1,
// borderBottom: 1,
// borderColor: "#EEE"
// },
// '& .MuiDataGrid-footerContainer': {
// border: 1,
// borderColor: "#EEE"
// }
// }

const handleChange = (event, newValue) => {
setSelectedTab(newValue);
}

useEffect(() => {
@@ -148,6 +157,7 @@ const UserMaintainPage_Organization = () => {
// console.log(response.data)
setUserData(response.data);
setOrgData(response.orgList);
getLoginLogList()
}
});
}
@@ -175,10 +185,24 @@ const UserMaintainPage_Organization = () => {
}
};

const getLoginLogList = () => {
HttpUtils.get({
url: `${UrlUtils.GET_Login_Log_List}`,
params:{
userId:params.id
},
onSuccess: function (response) {
// console.log(response)
setLoginLogData(response);
}
});
}



useEffect(() => {
setLoding(false);
}, [userData]);
}, [loginLogData]);

return (
isLoading ?
@@ -236,17 +260,27 @@ const UserMaintainPage_Organization = () => {
}
{isGLDLoggedIn()?
<Grid item xs={12} md={12} lg={12}>
<Box xs={12} ml={0} mt={-3} mr={11.5} sx={{ p: 1, borderRadius: '10px' }}>
<MainCard elevation={0} border={false} content={false}>
<Typography variant="h4" sx={{ ml: 3, mt: 3, mb: 2, mr: 6, borderBottom: "1px solid black" }}>
Files
</Typography>
<FileList sx={_sx}
refId={params.id}
refType={"identification"}
/>
</MainCard>
</Box>
<MainCard elevation={0} border={false} content={false} sx={{maxWidth: '100%', mr:2, width: "-webkit-fill-available"}}>
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList variant="scrollable" onChange={handleChange} aria-label="lab API tabs example">
<Tab label="Files" value="1" />
<Tab label="Login" value="2" />
</TabList>
</Box>
<TabPanel value="1">
<FileList
refId={params.id}
refType={"identification"}
/>
</TabPanel>
<TabPanel value="2">
<LoginGrid
rows = {loginLogData}
/>
</TabPanel>
</TabContext>
</MainCard>
<br />
</Grid>
:null


+ 5
- 0
src/routes/GLDUserRoutes.js Прегледај датотеку

@@ -27,6 +27,7 @@ const EmailTemplateDetailPage = Loadable(lazy(() => import('pages/EmailTemplate/
const HolidayPage = Loadable(lazy(() => import('pages/Holiday')));
const GazetteIssuePage = Loadable(lazy(() => import('pages/GazetteIssue/index')));
const DrImport = Loadable(lazy(() => import('pages/Setting/DrImport')));
const AuditLogPage = Loadable(lazy(() => import('pages/AuditLog/index')));

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

@@ -125,6 +126,10 @@ const GLDUserRoutes = {
path: '/setting/drImport',
element: <DrImport />
},
{
path: '/setting/auditLog',
element: <AuditLogPage />
},
]
},
]


+ 1
- 0
src/utils/ApiPathConst.js Прегледај датотеку

@@ -105,6 +105,7 @@ export const POST_CHECK_APP_EXPRITY_DATE = apiPath+'/application/checkExprityDat
//GLD User
export const POST_ADMIN_USER_REGISTER = apiPath+'/user/registry';
export const DELETE_USER = apiPath+'/user';
export const GET_Login_Log_List = apiPath+'/user/loginLogList';
export const GET_PUBLIC_NOTICE_APPLY_DETAIL = apiPath+'/application/application-detail';
export const SET_PUBLIC_NOTICE_GROUP_DETAIL = apiPath+'/application/application-group-detail';
export const SET_PUBLIC_NOTICE_STATUS_NOT_ACCEPT = apiPath+'/application/application-detail-status-not-accept';


Loading…
Откажи
Сачувај