From 6ad59b245cce6269f9f7dc3d66f3367a4db0c0c4 Mon Sep 17 00:00:00 2001 From: huyt Date: Fri, 14 Jan 2022 12:00:02 +0700 Subject: [PATCH] update man hinh user --- app/package.json | 2 + app/public/img/BI_Logo.png | Bin 0 -> 17371 bytes app/src/App.css | 107 ++++++ app/src/App.js | 23 +- app/src/actions/isLogin/index.js | 15 + app/src/actions/role/index.js | 9 + app/src/components/Login/Login.js | 269 ++++++++------ app/src/components/Modal/ModaEditLabel.js | 92 +++-- app/src/components/Modal/ModalEdit.js | 94 +++-- app/src/components/Modal/ModalPassword.js | 117 ++++++ app/src/components/Modal/ModalRole.js | 0 app/src/components/Modal/ModalUser.js | 298 +++++++++++++++ app/src/components/User/User.js | 432 ++++++++++++++++++++++ app/src/components/layouts/Header.js | 97 +++-- app/src/components/layouts/MenuBar.js | 22 ++ app/src/reducers/index.js | 7 + app/src/reducers/isLogin/index.js | 23 ++ app/src/reducers/role/index.js | 15 + app/src/store/index.js | 3 + app/yarn.lock | 50 ++- 20 files changed, 1457 insertions(+), 218 deletions(-) create mode 100644 app/public/img/BI_Logo.png create mode 100644 app/src/actions/isLogin/index.js create mode 100644 app/src/actions/role/index.js create mode 100644 app/src/components/Modal/ModalPassword.js create mode 100644 app/src/components/Modal/ModalRole.js create mode 100644 app/src/components/Modal/ModalUser.js create mode 100644 app/src/components/User/User.js create mode 100644 app/src/reducers/index.js create mode 100644 app/src/reducers/isLogin/index.js create mode 100644 app/src/reducers/role/index.js create mode 100644 app/src/store/index.js diff --git a/app/package.json b/app/package.json index eba885a..666c029 100644 --- a/app/package.json +++ b/app/package.json @@ -21,10 +21,12 @@ "react-file-reader": "^1.1.4", "react-js-pagination": "^3.0.3", "react-loading-overlay": "^1.0.1", + "react-redux": "^7.2.6", "react-router-dom": "5.2.0", "react-scripts": "5.0.0", "react-select": "^5.2.1", "react-spinners": "^0.11.0", + "react-switch": "^6.0.0", "sweetalert": "^2.1.2", "web-vitals": "^2.1.2" }, diff --git a/app/public/img/BI_Logo.png b/app/public/img/BI_Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4a5f4f2a3293bb03734f0d3f7b341774295d11d8 GIT binary patch literal 17371 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

+VSxqmYtK5NgUJeKf`#qJ|C_-g; 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 literal 0 HcmV?d00001 diff --git a/app/src/App.css b/app/src/App.css index 611c57d..72768df 100644 --- a/app/src/App.css +++ b/app/src/App.css @@ -365,4 +365,111 @@ button.close:hover { height: 60px; } +} + +.login-block { + /* background-image: url("/img/Bg_login.jpg"); */ + background-repeat: no-repeat; + background-size: cover; + float: left; + width: 100%; + padding: 50px 0; + margin-top: 150px; +} +.login-sec { + padding: 50px 30px 10px; + position: relative; +} +.login-sec .copy-text { + position: absolute; + width: 80%; + bottom: 20px; + font-size: 13px; + text-align: center; +} +.login-sec .copy-text i { + color: #feb58a; +} +.login-sec .copy-text a { + color: #e36262; +} +.login-sec h2 { + margin-bottom: 30px; + font-weight: 800; + font-size: 30px; + color: #0695e2; +} +.login-sec h2:after { + content: " "; + width: 100px; + height: 5px; + background: #0695e2; + display: block; + border-radius: 3px; + margin-top: 20px; + margin-left: auto; + margin-right: auto; +} +.login-sec ul li a { + padding: 8px !important; + border-top-right-radius: 3px !important; + border-top-left-radius: 3px !important; +} +.login-sec ul li a.active { + color: white !important; +} + +.banner-sec { + background-size: cover; + min-height: 300px; + border-radius: 0 10px 10px 0; + padding: 0; +} +.banner-text { + width: 70%; + position: absolute; + bottom: 0px; + padding-left: 20px; +} +.banner-text h2 { + color: #fff; + font-weight: 600; +} +.banner-text h2:after { + content: " "; + width: 100px; + height: 5px; + background: #fff; + display: block; + margin-top: 20px; + border-radius: 3px; +} +.banner-text p { + color: #fff; +} + +.container { + box-shadow: 0 1px 15px 1px rgba(69, 65, 78, 0.08); + background-color: #fff; + border-radius: 10px; +} +.container_form_infor { + box-shadow: 0 1px 15px 1px rgba(69, 65, 78, 0.08); + background-color: #fff; + border-radius: 10px; +} + +.carousel-inner { + border-radius: 0 10px 10px 0; +} +.carousel-caption { + text-align: left; + left: 5%; +} + +.btn-login { + background: #0695e2; + color: #fff; + font-weight: 600; + font-family: inherit !important; } \ No newline at end of file diff --git a/app/src/App.js b/app/src/App.js index a85cc1a..511cda2 100644 --- a/app/src/App.js +++ b/app/src/App.js @@ -3,38 +3,41 @@ import ListItem from './components/List/ListItem'; import Login from './components/Login/Login'; import LabelImage from './components/LabelImg/LabelImage'; import SearchImage from './components/SearchImg/SearchImage'; +import User from './components/User/User'; import ImportImage from './components/ImportImg/ImportImage'; import Test from './components/Test/Test'; import MenuBar from './components/layouts/MenuBar' import Header from './components/layouts/Header' import 'antd/dist/antd.css'; import "./App.css"; -import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import store from './store'; +import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; function App() { return ( -

+ ); } diff --git a/app/src/actions/isLogin/index.js b/app/src/actions/isLogin/index.js new file mode 100644 index 0000000..a78075a --- /dev/null +++ b/app/src/actions/isLogin/index.js @@ -0,0 +1,15 @@ +export const LOGIN = 'LOGIN'; +export const LOGOUT = 'LOGOUT'; +export function login(access_token){ + return { + type: LOGIN, + payload:{ + access_token: access_token + } + } +} +export function logout(){ + return { + type: LOGOUT + } +} diff --git a/app/src/actions/role/index.js b/app/src/actions/role/index.js new file mode 100644 index 0000000..aaa42f5 --- /dev/null +++ b/app/src/actions/role/index.js @@ -0,0 +1,9 @@ +export const ROLE = 'ROLE'; +export function role(role){ + return { + type: ROLE, + payload:{ + role: role + } + } +} diff --git a/app/src/components/Login/Login.js b/app/src/components/Login/Login.js index c18c8ac..e4b109d 100644 --- a/app/src/components/Login/Login.js +++ b/app/src/components/Login/Login.js @@ -1,128 +1,157 @@ -import { LockOutlined, UserOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Typography } from 'antd'; -import axios from 'axios'; -// import { dispatchBox, dispatchToken } from 'features/Login/loginSlice'; -import React, { useState } from 'react'; -// import { useDispatch } from 'react-redux'; -// import { useHistory } from "react-router-dom"; -import { HOST } from '../../config/index'; +import React, { Component } from 'react'; +import { Row, Col } from 'react-bootstrap'; +import swal from 'sweetalert'; +import $ from 'jquery'; +import { HOST } from '../../config'; +import Store from '../../store'; +import { login } from '../../actions/isLogin'; -const { Text } = Typography; - -const Login = () => { - - const [error, setError] = useState(''); - const [loading, setLoading] = useState(false); - - // const dispatch = useDispatch(); - - // let history = useHistory(); - - const onFinish = async (values) => { - setLoading(true); - const dataReq = { - email: values.email, - password: values.password, - } - - await axios({ - method: 'POST', - url: `${HOST}/api/login`, - headers: {}, - data: dataReq - }).then((res) => { - if (res.data.status === 10000) { - // dispatch(dispatchToken({ token: 'Bearer ' + res.data.access_token })); - // dispatch(dispatchBox({ rule: res.data.user_info.rule })) - setError(''); - localStorage.setItem('refresh_token', 'Bearer ' + res.data.refresh_token); - localStorage.setItem('access_token', 'Bearer ' + res.data.access_token); - localStorage.setItem('rule', res.data.user_info.rule); - - // history.push('/preferential-management') - } else { - setError('Sai tài khoản hoặc mật khẩu'); +class Login extends Component { + constructor(props) { + super(props); + this.state = { + error: 0, + loadingbtn: false, + datalogin: { + email: "", + password: "", } - }) - .catch(err => { - setError('Vui lòng kiểm tra lại đường truyền mạng') - console.error(err); + } + localStorage.clear(); + } + + CheckLogin = async (event) => { + var form = $("#formLoginCheck") + if (form[0].checkValidity() === false) { + event.preventDefault() + event.stopPropagation() + form.addClass('was-validated') + } else { + event.preventDefault() + event.stopPropagation() + this.setState({ + loadingbtn: true + }, () => { + if (this.state.datalogin.password.length < 6) { + this.setState({ + error: 1, + loadingbtn: false + }) + } else { + fetch(`${HOST}/api/login`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.state.datalogin) + }).then((response) => { + if (response.status === 500) { + this.setState({ + error: 0, + loadingbtn: false + }) + swal("Cảnh báo!", "Hiện tại hệ thống của chúng tôi đang nâng cấp, vui lòng đăng nhập lại sau 30 phút", "info"); + return; + } + return response.json() + }).then((data) => { + if (data.status === 10000) { + this.setState({ + error: 0, + loadingbtn: false + }) + localStorage.setItem("access_token", "Bearer " + data.access_token); + Store.dispatch(login("Bearer " + data.access_token)); + localStorage.setItem("api_url", data.api_url); + localStorage.setItem("api2_url", data.api2_url); + window.location.href = "/"; + // return; + } else if (data.status === 10003) { + this.setState({ + loadingbtn: false + }) + swal("Cảnh báo!", "Tài khoản không tồn tại", "warning"); + } else if (data.status === 10005) { + this.setState({ + loadingbtn: false + }) + swal("Cảnh báo", "Tài khoản của bạn đã bị khóa, vui lòng chờ 30 phút rồi đăng nhập lại hoặc liên hệ admin", "warning"); + } else { + this.setState({ + error: 1, + loadingbtn: false + }) + } + }).catch((error) => { + if (error) { + this.setState({ + loadingbtn: false + }) + swal("Lỗi!", "Vui lòng kiểm tra lại đường truyền", "error"); + } + }) + } }) - setLoading(false); - }; + + } + } - const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - }; + onEnterPress = (e) => { + if (e.keyCode === 13 && e.shiftKey === false) { + e.preventDefault(); + this.CheckLogin(e); + } + } + HandleLogin = (e) => { + var datalogin = this.state.datalogin; + datalogin[e.target.name] = e.target.value.trim(); + this.setState({ datalogin: datalogin }); + } - return ( -
-
-
-

Đăng nhập

-
- - } - placeholder="Email" /> - - - } - type="password" - placeholder="Password" - /> - -
- {error && * Sai tài khoản mật khẩu } -
- - - -
+ render() { + return ( +
+
+ + + +
+ +
+ + < div className="form-group"> + + { + this.HandleLogin(e) + }} /> +
+
+ + { + this.HandleLogin(e) + }} /> +
+
+ +
+
+ + + +
- -
- -
- ); + + ) + } } - -export default Login; \ No newline at end of file +export default Login; diff --git a/app/src/components/Modal/ModaEditLabel.js b/app/src/components/Modal/ModaEditLabel.js index 9cc403f..9f4e9c0 100644 --- a/app/src/components/Modal/ModaEditLabel.js +++ b/app/src/components/Modal/ModaEditLabel.js @@ -30,6 +30,8 @@ const ModalEditLabel = (props) => { const [dateImage, setDateImg] = useState("") + const [dataUpload, setDataUpload] = useState([]) + const [hostImg, setHostImg] = useState(''); useEffect(() => { @@ -124,7 +126,7 @@ const ModalEditLabel = (props) => {
{ checkDeleteMulti === false ? - { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> + { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> : } @@ -143,13 +145,16 @@ const ModalEditLabel = (props) => { ) }) + const checkLength= (file,fileList) => { + if (crrImages.length + fileList.length > 3) { + swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); + return false + } + } + const uploadImage = async (options) => { - if (crrImages.length >= 3) { - swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); - return - } else { const { file } = options; const base64 = await convertBase64(file) @@ -158,32 +163,54 @@ const ModalEditLabel = (props) => { base64_image_list: [base64.split(',')[1]] } - fetch(`${HOST}/api/face_images/famous_person`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - // 'Authorization': token - }, - body: JSON.stringify(dataUploadImg) - }) - .then(res => res.json()) - .then(data => { - if (data.status === 10000) { - setHostImg(data.image_host) - let listImg = [...crrImages] - listImg.unshift(data.data.toString()) - setCrrImages(listImg) - setCheckDeleteMulti(false) - } else if (data.status === 10003) { - if (data.message === "Too many face in image") { - swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); - } else { - swal("Thất bại", "Ảnh không hợp lệ", "error"); + let promises = []; + promises.push( + axios + .post(`${HOST}/api/face_images/famous_person`, dataUploadImg, { + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', } - } + }) + ) + await Promise.all(promises) + .then((data) => { + let success = false + let manyFace = false + let noFace = false + for (let i = 0; i < data.length; i++) { + const element = data[i]; + if (element.data.status === 10000) { + let listImg = dataUpload + setHostImg(element.data.image_host) + listImg.unshift(element.data.data.toString()) + setDataUpload(...dataUpload) + success = true + } else if (element.data.status === 10003 && element.data.message === "Too many face in image") { + manyFace = true + } else if (element.data.status === 10003 && element.data.message === "No face in image") { + noFace = true + } else { + success = false + } + } + if (success) { + let originData = crrImages + originData.unshift(dataUpload[0].toString()) + let arrSet = [...new Set(originData)] + setCrrImages(arrSet) + setCheckDeleteMulti(false) + } else if (manyFace) { + swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); + } else if (noFace) { + swal("Thất bại", "Ảnh không có khuôn mặt!", "error"); + } else { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } }) - } + .catch((err) => { + console.log(err) + }); }; @@ -260,7 +287,7 @@ const ModalEditLabel = (props) => {
{ crrImages[crrIdx] ? - } /> : + } /> : } /> } @@ -323,11 +350,14 @@ const ModalEditLabel = (props) => { }>Tải ảnh lên + {!disableBtn &&
* Giới hạn 3 ảnh
}
diff --git a/app/src/components/Modal/ModalEdit.js b/app/src/components/Modal/ModalEdit.js index 2bb8b0b..1cba733 100644 --- a/app/src/components/Modal/ModalEdit.js +++ b/app/src/components/Modal/ModalEdit.js @@ -32,6 +32,8 @@ const Modaledit = (props) => { const [hostImg, setHostImg] = useState(''); + const [dataUpload, setDataUpload] = useState([]) + useEffect(() => { setCrrData(data); setCrrImages(data.sample_images) @@ -124,7 +126,7 @@ const Modaledit = (props) => {
{ checkDeleteMulti === false ? - { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> + { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> : } @@ -143,13 +145,14 @@ const Modaledit = (props) => { ) }) - + const checkLength= (file,fileList) => { + if (crrImages.length + fileList.length > 3) { + swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); + return false + } + } const uploadImage = async (options) => { - if (crrImages.length >= 3) { - swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); - return - } else { const { file } = options; const base64 = await convertBase64(file) @@ -158,32 +161,54 @@ const Modaledit = (props) => { base64_image_list: [base64.split(',')[1]] } - fetch(`${HOST}/api/face_images/famous_person`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - // 'Authorization': token - }, - body: JSON.stringify(dataUploadImg) - }) - .then(res => res.json()) - .then(data => { - if (data.status === 10000) { - setHostImg(data.image_host) - let listImg = [...crrImages] - listImg.unshift(data.data.toString()) - setCrrImages(listImg) - setCheckDeleteMulti(false) - } else if (data.status === 10003) { - if (data.message === "Too many face in image") { - swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); - } else { - swal("Thất bại", "Ảnh không hợp lệ", "error"); + let promises = []; + promises.push( + axios + .post(`${HOST}/api/face_images/famous_person`, dataUploadImg, { + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', } - } + }) + ) + await Promise.all(promises) + .then((data) => { + let success = false + let manyFace = false + let noFace = false + for (let i = 0; i < data.length; i++) { + const element = data[i]; + if (element.data.status === 10000) { + let listImg = dataUpload + setHostImg(element.data.image_host) + listImg.unshift(element.data.data.toString()) + setDataUpload(...dataUpload) + success = true + } else if (element.data.status === 10003 && element.data.message === "Too many face in image") { + manyFace = true + } else if (element.data.status === 10003 && element.data.message === "No face in image") { + noFace = true + } else { + success = false + } + } + if (success) { + let originData = crrImages + originData.unshift(dataUpload[0].toString()) + let arrSet = [...new Set(originData)] + setCrrImages(arrSet) + setCheckDeleteMulti(false) + } else if (manyFace) { + swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); + } else if (noFace) { + swal("Thất bại", "Ảnh không có khuôn mặt!", "error"); + } else { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } }) - } + .catch((err) => { + console.log(err) + }); }; @@ -260,8 +285,8 @@ const Modaledit = (props) => {
{ crrImages[crrIdx] ? - } /> : - } /> + } /> : + } /> }
@@ -323,11 +348,14 @@ const Modaledit = (props) => { }>Tải ảnh lên + {!disableBtn &&
* Giới hạn 3 ảnh
}
diff --git a/app/src/components/Modal/ModalPassword.js b/app/src/components/Modal/ModalPassword.js new file mode 100644 index 0000000..12d05bf --- /dev/null +++ b/app/src/components/Modal/ModalPassword.js @@ -0,0 +1,117 @@ +import { Form, Input } from 'antd'; +import axios from 'axios'; +import 'moment/locale/vi'; +import React from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import swal from 'sweetalert'; +import { HOST } from '../../config/index'; + +const ModalPassword = (props) => { + const { show, onHide, obj_id } = props; + + const [form] = Form.useForm() + + const click_handle = async () => { + let dataPost = {password: form.getFieldValue('password')} + console.log(dataPost, obj_id) + const result = await axios.patch(`${HOST}/api/users/${obj_id}/password`, { password: form.getFieldValue('password') }) + if (result.data.status === 10000) { + swal({ + icon: 'success', + title: 'Thành công', + text: 'Thay đổi mật khẩu thành công', + timer: 1500, + buttons: false, + }) + onHide() + } else if (result.data.status === 10002) { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } else { + swal("Thất bại", "Thay đổi mật khẩu thất bại!", "error"); + } + } + + + return ( + = 1920 ? "modal-size-res" : "modal-size"}`} + aria-labelledby="contained-modal-title-vcenter" + > + + Đổi mật khẩu + + + + +
+
+
+
+
click_handle()} + autoComplete="off" + initialValues={{ + + }} + > + + + + + ({ + validator(_, value) { + if (!value || getFieldValue('password') === value) { + return Promise.resolve(); + } + return Promise.reject(new Error('Mật khẩu không khớp')); + }, + }), + ]} + > + + +
+
+
+
+
+
+ + + + +
+ ); +} + +export default ModalPassword; diff --git a/app/src/components/Modal/ModalRole.js b/app/src/components/Modal/ModalRole.js new file mode 100644 index 0000000..e69de29 diff --git a/app/src/components/Modal/ModalUser.js b/app/src/components/Modal/ModalUser.js new file mode 100644 index 0000000..adf1e3b --- /dev/null +++ b/app/src/components/Modal/ModalUser.js @@ -0,0 +1,298 @@ +import { UploadOutlined, UserOutlined } from '@ant-design/icons'; +import { Avatar, Button as ButtonAntd, DatePicker, Form, Input, Radio, Upload, Select,Switch } from 'antd'; +import { useLocation } from 'react-router-dom'; +import viVN from 'antd/lib/locale/vi_VN'; +import axios from 'axios'; +import moment from 'moment'; +import 'moment/locale/vi'; +import React, { useEffect, useRef, useState } from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import swal from 'sweetalert'; +import { HOST } from '../../config/index'; + +const { Option } = Select; + + +const ModalUser = (props) => { + const { show, onHide, data } = props; + const [crrImages, setCrrImages] = useState([]); + + const [form] = Form.useForm() + + + const [birthday, setBirthday] = useState(moment()) + const [crrData, setCrrData] = useState(null); + + const [selectedRole, setSelectedRole] = useState([]) + const [active, setActive] = useState(false) + + const [checkDeleteMulti, setCheckDeleteMulti] = useState(false); + const [crrIdx, setCrrIdx] = useState(0) + const [listChecked, setListChecked] = useState({ url: [] }); + + const [disableBtn, setDisableBtn] = useState(true); + + const [dateImage, setDateImg] = useState("") + + const [dataUpload, setDataUpload] = useState([]) + + const [hostImg, setHostImg] = useState(''); + + useEffect(() => { + setCrrData(data); + console.log(data) + // setCrrImages(data.sample_images) + // setBirthday(data.birthday !== "" ? moment(data.birthday) : null) + // setDisableBtn(data._id ? false : true) + // setHostImg(data.image_host) + // return () => { + // setCrrData(null); + // } + }, [data]); + + + // const handleCheckedImg = (event, value) => { + // let newListChecked = { ...listChecked } + // if (newListChecked.url.indexOf(event.target.value) === -1) { + // newListChecked.url.push(event.target.value) + // } else { + // var i = newListChecked.url.indexOf(event.target.value); + // if (i !== -1) { + // newListChecked.url.splice(i, 1); + // } + // } + // setListChecked(newListChecked) + + // } + + // useEffect(() => { + // if (crrImages.length > 0) { + // let crrDateImg = crrImages[crrIdx] + // let getDateImg = crrDateImg !== "" && crrDateImg.split("_") + // let dataImg = getDateImg.length > 0 && getDateImg[1].slice(0,6) + // setDateImg(dataImg) + // } + // },[crrImages,crrIdx]) + + const click_handle = async () => { + let dataPost = { + obj_id: crrData?._id ? crrData._id : "", + username: crrData.username, + full_name: crrData.full_name, + password: crrData.password, + is_deleted: 0, + birthday: crrData.birthday, + gender: crrData?.gender ? crrData.gender : "", + phone_number: crrData?.phone_number ? crrData?.phone_number : "", + role_id_list: selectedRole + } + const result = await axios({ + method: 'POST', + url: `${HOST}/api/users/insert_or_update`, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // 'Authorization': token, + }, + data: dataPost, + }) + if (result.data.status === 10000) { + if (crrData._id) { + swal({ + icon: 'success', + title: 'Thành công', + text: 'Sửa thông tin thành công', + timer: 1500, + buttons: false, + }) + } else { + swal({ + icon: 'success', + title: 'Thành công', + text: 'Thêm mới thành công', + timer: 1500, + buttons: false, + }) + onHide() + } + } else if (result.data.status === 10002) { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } else if (result.data.status === 10004) { + swal("Thất bại", "Tài khoản đã tồn tại!", "error"); + } else if (result.data.status === 10003) { + swal("Thất bại", "Tài khoản không được để trống!", "error"); + } else { + if (crrData._id) { + swal("Thất bại", "Sửa thông tin thất bại!", "error"); + } else { + swal("Thất bại", "Thêm mới thất bại!", "error"); + } + } + } + + + const UserHandle = (e) => { + setCrrData({ ...crrData, [e.target.name]: e.target.value }) + } + + const onChangeBirthday = (date) => { + setBirthday(date) + setCrrData({ ...crrData, birthday: moment(date).format("YYYY-MM-DD") }) + } + + const listOptions = []; + for (let i = 10; i < 36; i++) { + listOptions.push(); + } + + const handleChangeSelect = (value) => { + setSelectedRole(value) + } + + const onChangeActive = (value) => { + setActive(value) + } + + if (!crrData) return <>; + + return ( + = 1920 ? "modal-size-res" : "modal-size"}`} + aria-labelledby="contained-modal-title-vcenter" + > + + {crrData?._id ? "Sửa thông tin" : "Thêm mới"} + + + + +
+
+
+
+
click_handle()} + // onFinishFailed={onFinishFailed} + autoComplete="off" + initialValues={{ + full_name: crrData?.full_name, + gender: crrData?.gender, + username: crrData?.username, + role_id_list: crrData?.role_id_list, + phone_number: crrData?.phone_number + }} + > + + UserHandle(e)} name='username' /> + + {!crrData?._id && + + UserHandle(e)} name='password' /> + + } + + + UserHandle(e)} name='full_name' /> + + + UserHandle(e)} name='phone_number' /> + + + + UserHandle(e)} defaultValue={crrData?.gender}> + Nam + Nữ + Giới tính khác + + + + + onChangeBirthday(e)} + placeholder="Ngày sinh" + /> + + + {/* + + */} + + + + + +
+ {/*
+ +
*/} +
+
+
+
+
+ + + + +
+ ); +} + +export default ModalUser; diff --git a/app/src/components/User/User.js b/app/src/components/User/User.js new file mode 100644 index 0000000..23e2711 --- /dev/null +++ b/app/src/components/User/User.js @@ -0,0 +1,432 @@ +import { UserOutlined } from '@ant-design/icons'; +import { Avatar, Tooltip } from 'antd'; +import axios from 'axios'; +import ModalUser from '../Modal/ModalUser'; +import ModalPassword from '../Modal/ModalPassword'; +import momment from 'moment'; +import React, { useEffect, useState } from 'react'; +import Pagination from "react-js-pagination"; +import { PulseLoader } from 'react-spinners'; +import { HOST } from '../../config/index'; +import swal from 'sweetalert'; +import { useLocation } from 'react-router-dom'; +import Switch from "react-switch"; +import Select from "react-select"; + +const initialDataPost = { + index: 1, + item_per_page: 5, + search_data: "", + is_deleted: -1, +} + +export default function User() { + + const [data, setData] = useState(null) + const [showModal, setShowModal] = useState(false) + const [showModalPassword, setShowModalPassword] = useState(false) + const [dataEdit, setDataEdit] = useState(null) + + + const [optionSelect, setOptionSelect] = useState([ + {value: -1, label: "Tất cả"}, + {value: 0, label:"Hoạt động"}, + {value: 1, label: "Không hoạt động"}, + ]) + + const [valueSelected, setValueSelected] = useState({value: -1, label:"Tất cả"}) + + const [loading, setLoading] = useState(true) + + const [activePage, setActivePage] = useState(1) + const [totalItems, setTotalItems] = useState(0) + + const [offset, setOffset] = useState(0) + + const [dataPost, setDataPost] = useState(initialDataPost) + const itemsPerPage = 5 + + const [token, setToken] = useState(''); + + const location = useLocation(); + + useEffect(() => { + if (location.search) { + let path = location.search.replace('?', '').split('&'); + let obj = {} + path.forEach(value => { + let arr = value.split('='); + obj[arr[0]] = arr[1] + }) + setToken(decodeURIComponent(obj.token)) + setToken((obj.token)) + } + }, [location]) + + useEffect(() => { + getData() + }, []) + + const onClickEdit = (data) => { + setDataEdit(data) + setShowModal(true) + } + + const onClickPassword = (data) => { + setDataEdit(data._id) + setShowModalPassword(true) + } + + const onDelete = async (value) => { + try { + const result = await axios({ + method: 'DELETE', + url: `${HOST}/api/users/${value._id}`, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // 'Authorization': token, + }, + }) + if (result.data.status === 10000) { + if (data.length === 1) { + setActivePage(activePage - 1) + setDataPost({ ...dataPost, index: activePage - 1 }) + } + swal({ + icon: 'success', + title: 'Thành công', + text: 'Xoá thành công', + timer: 1500, + buttons: false, + }) + getData(dataPost) + } else { + swal("Thất bại", "Xoá thất bại!", "error"); + } + } catch (error) { + setLoading(false) + console.log(error); + } + } + + useEffect(() => { + FilterItem() + }, [activePage]) + + const FilterItem = () => { + const offset = (activePage - 1) * itemsPerPage; + setOffset(offset) + } + + const handlePageChange = (pageNumber) => { + setActivePage(pageNumber); + const data = { + ...dataPost, + index: pageNumber, + } + getData(data); + } + + const getData = async (data) => { + try { + const result = await axios({ + method: 'POST', + url: `${HOST}/api/users/search`, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // 'Authorization': token + }, + data: data ? data : dataPost, + }) + if (result.data.status === 10000) { + setData(result.data.data) + setTotalItems(result.data.count) + setLoading(false) + + } + } catch (error) { + setLoading(false) + console.log(error); + } + } + + const handleOnKeyDown = e => { + if (e.key === 'Enter') { + setActivePage(1) + getData(dataPost); + } + } + + const tableRows = (dataAll) => dataAll.map((value, index) => { + var gender = "" + if (value.gender === "1") { + gender = "Nam" + } else if (value.gender === "2") { + gender = "Nữ" + } else if (value.gender === "3") { + gender = "Giới tính khác" + } else { + gender = "" + } + + var checked = true; + if (value.is_deteted === 1) { + checked = true + + } + if (value.is_deteted === 0) { + checked = false + + } + + + return ( + + {(index + offset + 1)} + {value.username} + {value.full_name} + {gender} + {value.birthday !== "" ? momment(value.birthday).format("DD-MM-YYYY") : ""} + {value.phone_number} + + { + value.is_deleted === 1 + ? + Không hoạt động + : + Hoạt động + } + + + + + + + + + + + + + + ) + }) + + + const onCloseModal = () => { + setShowModal(false) + // setActivePage(activePage) + const data = { + ...dataPost, + index: activePage, + } + getData(data); + } + + const changeHandleFilter = (e) => { + setDataPost({ ...dataPost, is_deleted: e.value }) + setValueSelected(e) + } + const onCloseModalPassword = () => { + setShowModalPassword(false) + const data = { + ...dataPost, + index: activePage, + } + getData(data); + } + + const reset = () => { + setActivePage(1) + setDataPost({ ...dataPost, search_data: "" }) + getData(initialDataPost) + setValueSelected({ value: -1, label: "Tất cả" }) + } + + return ( +
+
+
+
+
+
+

+ Quản lí người dùng +

+
+
+
+
    +
  • + {/* { + this.state.dataRole.indexOf(this.state.type + '/' + nameTab + ':insert_or_update') !== -1 + ? */} + + {/* : + "" + } */} +
  • +
+
+
+
+
+
+
+
+
+ handleOnKeyDown(e)} + onChange={(e) => { + setDataPost({ ...dataPost, search_data: e.target.value }) + }} + value={dataPost.search_data} + id="inputSearch" + className="form-control m-input" + placeholder="Tên đăng nhập..." + data-col-index={0} /> +
+
+