update nhan anh
This commit is contained in:
parent
2b8ec4f708
commit
121aab8463
|
@ -23,6 +23,7 @@
|
|||
"react-loading-overlay": "^1.0.1",
|
||||
"react-router-dom": "5.2.0",
|
||||
"react-scripts": "5.0.0",
|
||||
"react-select": "^5.2.1",
|
||||
"react-spinners": "^0.11.0",
|
||||
"sweetalert": "^2.1.2",
|
||||
"web-vitals": "^2.1.2"
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react'
|
||||
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 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';
|
||||
|
@ -19,10 +21,12 @@ function App() {
|
|||
<Header />
|
||||
<MenuBar />
|
||||
<div>
|
||||
{/* <Redirect exact from='/' to='/search-image' /> */}
|
||||
<Redirect exact from='/' to='/search-image' />
|
||||
<Route path='/login' component={Login} />
|
||||
<Route path='/import-image' component={ImportImage} />
|
||||
<Route path='/search-image' component={SearchImage} />
|
||||
<Route path='/label-image' component={LabelImage} />
|
||||
<Route path='/test' component={Test} />
|
||||
<Route path="/list-famous" component={ListItem} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,9 +8,10 @@ import { PulseLoader } from 'react-spinners';
|
|||
import Modalupload from '../Modal/ModalUpload';
|
||||
import ModalEditImg from '../Modal/ModalEditImg';
|
||||
import axios from 'axios';
|
||||
import { Avatar, Tooltip } from 'antd';
|
||||
import { Avatar, Tooltip, Image } from 'antd';
|
||||
import {UserOutlined} from '@ant-design/icons';
|
||||
import momment from 'moment';
|
||||
import Select from "react-select";
|
||||
class ImportImage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -28,7 +29,9 @@ class ImportImage extends Component {
|
|||
modalShow: false,
|
||||
dataEdit: null,
|
||||
modalUploadShow: false,
|
||||
dataSearch: ""
|
||||
dataSearch: "",
|
||||
optionSelect: [{value: 1, label:"Facebook"}, {value: 2, label: "Tải lên"}],
|
||||
valueSelected: {value: 2, label:"Tải lên"},
|
||||
}
|
||||
this.itemsPerPage = 5;
|
||||
}
|
||||
|
@ -52,7 +55,8 @@ class ImportImage extends Component {
|
|||
data: {
|
||||
index: page,
|
||||
item_per_page: this.itemsPerPage,
|
||||
search_data: this.state.dataSearch
|
||||
search_data: this.state.dataSearch,
|
||||
import_type: this.state.valueSelected.value
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -149,11 +153,20 @@ class ImportImage extends Component {
|
|||
this.setState({
|
||||
activePage: 1,
|
||||
dataSearch: "",
|
||||
valueSelected: {value: 2, label:"Tải lên"},
|
||||
}, () => {
|
||||
this.getListImg(1);
|
||||
})
|
||||
}
|
||||
|
||||
changeHandleFilter = (e) => {
|
||||
this.setState({
|
||||
valueSelected: e,
|
||||
activePage: 1
|
||||
}, () => {
|
||||
this.getListImg(1);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
// if (this.state.isLogin == false) {
|
||||
|
@ -162,9 +175,9 @@ class ImportImage extends Component {
|
|||
// )
|
||||
// }
|
||||
let bulletedListImg = this.state.listImgImport.map((value, index) => {
|
||||
|
||||
|
||||
var listImg
|
||||
listImg = <img key={index} style={{ width: "80px", height: "80px" }} alt="" src={`${value.image_host}`} />
|
||||
listImg = <Image style={{ width: "80px", height: "auto", objectFit: "contain"}} alt="" src={`${value.image_host}`} />
|
||||
|
||||
|
||||
return (
|
||||
|
@ -172,6 +185,7 @@ class ImportImage extends Component {
|
|||
<td>{(index + this.state.offset + 1)}</td>
|
||||
<td>{listImg}</td>
|
||||
<td>{value.origin_name}</td>
|
||||
<td>{value.import_type === 1 ? "Facebook" : "Tải lên"}</td>
|
||||
<td>{momment(value.created_time).format("DD-MM-YYYY")}</td>
|
||||
<td>
|
||||
<Tooltip placement="top" title={"Sửa"}>
|
||||
|
@ -235,6 +249,14 @@ class ImportImage extends Component {
|
|||
data-col-index={0}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group m-form__group col-xl-2">
|
||||
<Select
|
||||
placeholder={'Loại ảnh'}
|
||||
value={this.state.valueSelected}
|
||||
onChange={this.changeHandleFilter}
|
||||
options={this.state.optionSelect}
|
||||
/>
|
||||
</div>
|
||||
<div className="pl-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
|
@ -285,6 +307,7 @@ class ImportImage extends Component {
|
|||
<th style={{width: "50px"}}>STT</th>
|
||||
<th>Ảnh</th>
|
||||
<th>Tên ảnh</th>
|
||||
<th>Loại ảnh</th>
|
||||
<th>Ngày tải lên</th>
|
||||
<th>Thao tác</th>
|
||||
</tr>
|
||||
|
|
334
app/src/components/LabelImg/LabelImage.js
Normal file
334
app/src/components/LabelImg/LabelImage.js
Normal file
|
@ -0,0 +1,334 @@
|
|||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Tooltip } from 'antd';
|
||||
import axios from 'axios';
|
||||
import ModalEditLabel from '../Modal/ModaEditLabel';
|
||||
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';
|
||||
|
||||
const initialDataPost = {
|
||||
index: 1,
|
||||
item_per_page: 5,
|
||||
search_data: "",
|
||||
person_type: 4,
|
||||
}
|
||||
|
||||
export default function LabelImage() {
|
||||
|
||||
const [data, setData] = useState(null)
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [dataEdit, setDataEdit] = useState(null)
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const [activePage, setActivePage] = useState(1)
|
||||
const [totalItems, setTotalItems] = 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 onDelete = async (value) => {
|
||||
let dataDel = {
|
||||
obj_id: value._id,
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
birthday: value.birthday,
|
||||
gender: value.gender,
|
||||
is_deleted : 1
|
||||
}
|
||||
try {
|
||||
const result = await axios({
|
||||
method: 'POST',
|
||||
url: `${HOST}/api/famous_persons/insert_or_update`,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
// 'Authorization': token,
|
||||
},
|
||||
data: dataDel,
|
||||
})
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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/famous_persons/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 listImg
|
||||
if (value.sample_images.length > 0) {
|
||||
let getDateImg = value.sample_images[0].split("_")
|
||||
let dataImg = getDateImg.length > 0 && getDateImg[1].slice(0,6)
|
||||
listImg = <img key={index} style={{ width: "80px", height: "80px" }} alt="" src={`${value.sample_images.length > 0 && value.image_host +dataImg+ "/" +value.sample_images[0]}`} />
|
||||
} else {
|
||||
listImg = <Avatar shape="square" size={80} icon={<UserOutlined />} />
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td>{listImg}</td>
|
||||
<td>{value.name}</td>
|
||||
<td>{value.id}</td>
|
||||
<td>{gender}</td>
|
||||
<td>{value.birthday !== "" ? momment(value.birthday).format("DD-MM-YYYY") : ""}</td>
|
||||
<td>
|
||||
<Tooltip placement="top" title={"Sửa"}>
|
||||
<button
|
||||
onClick={() => onClickEdit(value)}
|
||||
className="m-portlet__nav-link btn m-btn m-btn--hover-warning m-btn--icon m-btn--icon-only m-btn--pill" data-tip data-for="Edit" >
|
||||
<i className="la la-edit" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={"Xoá"}>
|
||||
<button
|
||||
onClick={f => {
|
||||
f.preventDefault();
|
||||
swal({
|
||||
// title: "Are you sure?",
|
||||
text: "Bạn có chắc muốn xoá " + value.name,
|
||||
icon: "warning",
|
||||
buttons: ["Huỷ", "Xoá"],
|
||||
dangerMode: true,
|
||||
})
|
||||
.then(willDelete => {
|
||||
if (willDelete) {
|
||||
onDelete(value);
|
||||
}
|
||||
});
|
||||
}}
|
||||
className="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill" data-tip data-for="Edit" >
|
||||
<i className="la la-trash" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
const onCloseModal = () => {
|
||||
setShowModal(false)
|
||||
// setActivePage(activePage)
|
||||
const data = {
|
||||
...dataPost,
|
||||
index: activePage,
|
||||
}
|
||||
getData(data);
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
setActivePage(1)
|
||||
setDataPost({...dataPost, search_data: ""})
|
||||
getData(initialDataPost)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{showModal && <ModalEditLabel data={dataEdit} onHide={onCloseModal} show={showModal} />}
|
||||
<div className="m-portlet m-portlet--mobile pb-3">
|
||||
<div className="m-portlet__head">
|
||||
<div className="m-portlet__head-caption">
|
||||
<div className="m-portlet__head-title">
|
||||
<h3 className="m-portlet__head-text">
|
||||
Gán nhãn
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="m-portlet__body pt-2">
|
||||
<div className="row pl-4">
|
||||
<div className="row p-3 col-xl-11">
|
||||
<div className="col-lg-2 p-0 m--margin-bottom-10-tablet-and-mobile">
|
||||
<input type="text"
|
||||
onKeyPress={(e) => handleOnKeyDown(e)}
|
||||
onChange={(e) => {
|
||||
setDataPost({ ...dataPost, search_data: e.target.value })
|
||||
}}
|
||||
value={dataPost.search_data}
|
||||
id="inputSearch" className="form-control m-input"
|
||||
placeholder="Họ tên..."
|
||||
data-col-index={0}
|
||||
/>
|
||||
</div>
|
||||
<div className="pl-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
setActivePage(1)
|
||||
getData(dataPost)
|
||||
}}
|
||||
className="btn btn-accent m-btn m-btn--icon" id="m_search">
|
||||
<span>
|
||||
<i className="la la-search" />
|
||||
<span>Tìm kiếm</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="pl-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
reset()
|
||||
}}
|
||||
className="btn btn-secondary m-btn m-btn--icon" id="m_reset">
|
||||
<span>
|
||||
<i className="la la-rotate-left" />
|
||||
<span>Tải lại</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="m-portlet__head-tools col-xl-1 d-flex align-items-center">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
let dataEdit = {
|
||||
obj_id: "",
|
||||
id: "",
|
||||
name: "",
|
||||
birthday: "",
|
||||
gender: "",
|
||||
sample_images: [],
|
||||
image_host: ""
|
||||
};
|
||||
setDataEdit(dataEdit)
|
||||
setShowModal(true)
|
||||
}}
|
||||
className="btn btn-accent m-btn m-btn--custom m-btn--icon m-btn--pill m-btn--air">
|
||||
<span>
|
||||
<i className="la la-plus" />
|
||||
<span>Thêm mới</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/*begin: Datatable */}
|
||||
<table className="table table-striped- table-bordered table-hover table-checkable" id="m_table_1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ảnh</th>
|
||||
<th>Họ tên</th>
|
||||
<th>FacebookID</th>
|
||||
<th>Giới tính</th>
|
||||
<th>Ngày sinh</th>
|
||||
<th>Thao tác</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{data && tableRows(data)}</tbody>
|
||||
</table>
|
||||
<PulseLoader
|
||||
// css={override}
|
||||
sizeUnit={"px"}
|
||||
size={12}
|
||||
margin={'2px'}
|
||||
color={'#36D7B7'}
|
||||
loading={loading}
|
||||
/>
|
||||
<Pagination
|
||||
prevPageText='Trang trước'
|
||||
nextPageText='Trang sau'
|
||||
firstPageText='Trang đầu'
|
||||
lastPageText='Trang cuối'
|
||||
activePage={activePage}
|
||||
itemsCountPerPage={itemsPerPage}
|
||||
totalItemsCount={totalItems}
|
||||
pageRangeDisplayed={5}
|
||||
onChange={handlePageChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -13,7 +13,8 @@ import { useLocation } from 'react-router-dom';
|
|||
const initialDataPost = {
|
||||
index: 1,
|
||||
item_per_page: 5,
|
||||
search_data: ""
|
||||
search_data: "",
|
||||
person_type: 2,
|
||||
}
|
||||
|
||||
export default function ListItem() {
|
||||
|
|
406
app/src/components/Modal/ModaEditLabel.js
Normal file
406
app/src/components/Modal/ModaEditLabel.js
Normal file
|
@ -0,0 +1,406 @@
|
|||
import { UploadOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Button as ButtonAntd, DatePicker, Form, Input, Radio, Upload } 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 ModalEditLabel = (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 [checkDeleteMulti, setCheckDeleteMulti] = useState(false);
|
||||
const [crrIdx, setCrrIdx] = useState(0)
|
||||
const [listChecked, setListChecked] = useState({ url: [] });
|
||||
|
||||
const [disableBtn, setDisableBtn] = useState(true);
|
||||
|
||||
const [dateImage, setDateImg] = useState("")
|
||||
|
||||
const [hostImg, setHostImg] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
setCrrData(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 : "",
|
||||
name: crrData.name,
|
||||
birthday: crrData.birthday,
|
||||
gender: crrData.gender ? crrData.gender : "",
|
||||
id: crrData.id ? crrData.id : "",
|
||||
person_type: 4
|
||||
}
|
||||
const result = await axios({
|
||||
method: 'POST',
|
||||
url: `${HOST}/api/famous_persons/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,
|
||||
})
|
||||
setCrrData({...crrData, _id: result.data.data})
|
||||
setDisableBtn(false)
|
||||
}
|
||||
} else if (result.data.status === 10002) {
|
||||
swal("Thất bại", "Lỗi hệ thống!", "error");
|
||||
} else {
|
||||
swal("Thất bại", "Sửa thông tin thất bại!", "error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const bulletedImg = crrImages.map((value, index) => {
|
||||
let getDateImg = value.split("_")
|
||||
let dataImg = getDateImg.length > 0 && getDateImg[1].slice(0,6)
|
||||
|
||||
let renderImg = value.includes("data:image") ? value : hostImg +dataImg+ "/" + value
|
||||
return (
|
||||
<div className="img-res col-md-4 pl-0 mb-3" key={index + 1}>
|
||||
<div style={{ 'height': 80 }}>
|
||||
{
|
||||
checkDeleteMulti === false ?
|
||||
<img alt="" src={renderImg} onClick={() => { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} />
|
||||
:
|
||||
<label className="m-checkbox img-checkbox m-checkbox-day pl-0 mb-0" style={{ 'width': '100%' }}>
|
||||
<input type="checkbox"
|
||||
defaultValue={value}
|
||||
name="img_checked"
|
||||
checked={listChecked.url.indexOf(value) === -1 ? false : true}
|
||||
onClick={e => {
|
||||
handleCheckedImg(e, value)
|
||||
}} readOnly />
|
||||
<img alt="" src={renderImg} className="opacity_img img_check" />
|
||||
<span />
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
|
||||
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)
|
||||
|
||||
let dataUploadImg = {
|
||||
obj_id: crrData._id ? crrData._id : "",
|
||||
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");
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const convertBase64 = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.readAsDataURL(file)
|
||||
fileReader.onload = () => {
|
||||
resolve(fileReader.result);
|
||||
}
|
||||
fileReader.onerror = (error) => {
|
||||
reject(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const deleteFaceMulti = () => {
|
||||
let listDelImg = listChecked.url
|
||||
fetch(`${HOST}/api/face_images/ignore_face`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
// 'Authorization': token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
person_obj_id: crrData._id ? crrData._id : "",
|
||||
images: listDelImg
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 10000) {
|
||||
let listDetele = crrImages.filter(item => !listDelImg.includes(item));
|
||||
if (crrIdx >= 1) {
|
||||
setCrrIdx(crrIdx - 1)
|
||||
}
|
||||
setCrrImages(listDetele)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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") })
|
||||
}
|
||||
|
||||
if (!crrData) return <></>;
|
||||
return (
|
||||
<Modal
|
||||
{...props}
|
||||
animation={false}
|
||||
size="lg"
|
||||
// keyboard={false}
|
||||
dialogClassName={`${window.innerWidth >= 1920 ? "modal-size-res" : "modal-size"}`}
|
||||
aria-labelledby="contained-modal-title-vcenter"
|
||||
>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title id="contained-modal-title-vcenter">{crrData._id ? "Sửa thông tin" : "Thêm mới"}
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
{crrData &&
|
||||
<Modal.Body>
|
||||
<div id="formUpdateMeeting">
|
||||
<div className="m-widget14 p-0">
|
||||
<div className="row">
|
||||
<div className="col-md-7 boder-right d-flex flex-column justify-content-between ">
|
||||
<div className="row justify-content-center pb-3">
|
||||
{
|
||||
crrImages[crrIdx] ?
|
||||
<Avatar shape="square" src={crrImages[crrIdx].includes("data:image") ? crrImages[crrIdx] : hostImg +dateImage+"/"+ crrImages[crrIdx]} size={180} icon={<UserOutlined />} /> :
|
||||
<Avatar shape="square" size={180} icon={<UserOutlined />} />
|
||||
}
|
||||
|
||||
</div>
|
||||
<div className="row mr-4 ml-4">
|
||||
{
|
||||
crrImages.length > 0
|
||||
?
|
||||
<div className="col-md-12 mt-2 mb-2 p-0">
|
||||
<label className="m-checkbox m-checkbox--success mt-3 ml-1">
|
||||
<input type="checkbox"
|
||||
onClick={(e) => {
|
||||
setCheckDeleteMulti(!checkDeleteMulti)
|
||||
setListChecked({
|
||||
url: [],
|
||||
})
|
||||
}}
|
||||
checked={checkDeleteMulti} /> <div style={{ 'paddingTop': '2px' }}>Chọn</div>
|
||||
<span />
|
||||
</label>
|
||||
{
|
||||
checkDeleteMulti === true
|
||||
?
|
||||
<div style={{ 'display': 'inline-flex' }} className="pull-right">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
if (listChecked.url.length > 0) {
|
||||
swal({
|
||||
title: "Bạn chắc chắn muốn xóa ảnh này",
|
||||
icon: "warning",
|
||||
buttons: ["Huỷ", "Oke!"],
|
||||
dangerMode: false,
|
||||
})
|
||||
.then((willDelete) => {
|
||||
if (!willDelete) throw null;
|
||||
deleteFaceMulti();
|
||||
})
|
||||
} else {
|
||||
swal("Cảnh báo!", "Bạn chưa chọn ảnh để xóa", "warning");
|
||||
}
|
||||
}}
|
||||
className="btn btn-sm btn-danger width-mobie--100 m-loader--light m-loader--right" id="btn_deleteMulti">
|
||||
Xóa ảnh đã chọn
|
||||
</button>
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
<div className="row col-md-12 pr-0 image_capture_small pull-left">
|
||||
{
|
||||
bulletedImg
|
||||
}
|
||||
|
||||
</div>
|
||||
<Upload
|
||||
customRequest = {uploadImage}
|
||||
accept="image/*"
|
||||
showUploadList={false}
|
||||
disabled={disableBtn}
|
||||
>
|
||||
<ButtonAntd className={`${disableBtn ? "disable-btn-upload" : ""}`} icon={<UploadOutlined />}>Tải ảnh lên</ButtonAntd>
|
||||
</Upload>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-5 d-flex flex-column justify-content-between">
|
||||
<Form
|
||||
id="formEdit"
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={() => click_handle()}
|
||||
// onFinishFailed={onFinishFailed}
|
||||
autoComplete="off"
|
||||
initialValues={{
|
||||
name: crrData.name,
|
||||
id: crrData.id,
|
||||
}}
|
||||
>
|
||||
<Form.Item
|
||||
label="Họ tên"
|
||||
name="name"
|
||||
rules={[{ required: true, message: '' }]}
|
||||
>
|
||||
<Input placeholder="Họ tên" value={crrData.name} onChange={e => UserHandle(e)} name='name' />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="FacebookID"
|
||||
name="id"
|
||||
>
|
||||
<Input placeholder="FacebookID" value={crrData.id} onChange={e => UserHandle(e)} name='id' />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="radio-group" label="Giới tính">
|
||||
<Radio.Group name="gender" onChange={e => UserHandle(e)} defaultValue={crrData.gender}>
|
||||
<Radio name="gender" value={"1"}>Nam</Radio>
|
||||
<Radio name="gender" value={"2"}>Nữ</Radio>
|
||||
<Radio name="gender" value={"3"}>Giới tính khác</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Ngày sinh"
|
||||
name="birthday"
|
||||
>
|
||||
<DatePicker className="form-control m-input"
|
||||
locale={viVN}
|
||||
defaultValue={birthday !== null ? moment(birthday, 'DD-MM-YYYY') : null}
|
||||
format={'DD-MM-YYYY'}
|
||||
onChange={e => onChangeBirthday(e)}
|
||||
placeholder="Ngày sinh"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
</Form>
|
||||
<div className="row d-flex justify-content-end mr-1">
|
||||
<Button variant="accent" className={"m-loader--light m-loader--right "}
|
||||
// disabled={loading}
|
||||
onClick={() => form.submit()}
|
||||
>Lưu</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
}
|
||||
{/* <Modal.Footer>
|
||||
<Button variant="accent" className={"m-loader--light m-loader--right "}
|
||||
// disabled={loading}
|
||||
onClick={() => form.submit()}
|
||||
>Lưu</Button>
|
||||
<Button variant="secondary" onClick={onHide}>Đóng</Button>
|
||||
</Modal.Footer> */}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalEditLabel;
|
|
@ -73,7 +73,8 @@ const Modaledit = (props) => {
|
|||
id: crrData.id,
|
||||
name: crrData.name,
|
||||
birthday: crrData.birthday,
|
||||
gender: crrData.gender ? crrData.gender : ""
|
||||
gender: crrData.gender ? crrData.gender : "",
|
||||
person_type: 2
|
||||
}
|
||||
const result = await axios({
|
||||
method: 'POST',
|
||||
|
|
|
@ -84,7 +84,7 @@ class ModalEditImg extends Component {
|
|||
<div className="col-md-6 boder-right d-flex flex-column justify-content-between ">
|
||||
<div className="d-flex justify-content-center">
|
||||
<Image
|
||||
width={240}
|
||||
style={{ width: "350px", height: "auto", objectFit: "contain"}}
|
||||
src={this.state.valueImg.image_host}
|
||||
/>
|
||||
</div>
|
||||
|
|
44
app/src/components/Test/Test.js
Normal file
44
app/src/components/Test/Test.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Tooltip } from 'antd';
|
||||
import axios from 'axios';
|
||||
import ModalEditLabel from '../Modal/ModaEditLabel';
|
||||
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';
|
||||
|
||||
|
||||
|
||||
export default function Test() {
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="m-portlet m-portlet--mobile pb-3">
|
||||
<div className="m-portlet__head">
|
||||
<div className="m-portlet__head-caption">
|
||||
<div className="m-portlet__head-title">
|
||||
<h3 className="m-portlet__head-text">
|
||||
Test
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="m-portlet__body pt-2">
|
||||
<PulseLoader
|
||||
// css={override}
|
||||
sizeUnit={"px"}
|
||||
size={12}
|
||||
margin={'2px'}
|
||||
color={'#36D7B7'}
|
||||
// loading={loading}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -67,7 +67,27 @@ class MenuBar extends Component {
|
|||
</NavLink>
|
||||
</li>
|
||||
|
||||
|
||||
<li className="m-menu__item m-menu__item--submenu" aria-haspopup="true" m-menu-submenu-toggle="hover">
|
||||
<NavLink to="/label-image" className={"m-menu__link " + active} activeClassName="m-menu__item--active" onClick={() => this.onClickClose()}>
|
||||
<i className="m-menu__link-icon flaticon-delete" />
|
||||
<span className="m-menu__link-title">
|
||||
<span className="m-menu__link-wrap">
|
||||
<span className="m-menu__link-text">Gán nhãn</span>
|
||||
</span>
|
||||
</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
|
||||
<li className="m-menu__item m-menu__item--submenu" aria-haspopup="true" m-menu-submenu-toggle="hover">
|
||||
<NavLink to="/test" className={"m-menu__link " + active} activeClassName="m-menu__item--active" onClick={() => this.onClickClose()}>
|
||||
<i className="m-menu__link-icon flaticon-edit" />
|
||||
<span className="m-menu__link-title">
|
||||
<span className="m-menu__link-wrap">
|
||||
<span className="m-menu__link-text">Test</span>
|
||||
</span>
|
||||
</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/* END: Aside Menu */}
|
||||
|
|
|
@ -1049,7 +1049,7 @@
|
|||
core-js-pure "^3.20.2"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
|
||||
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
|
||||
|
@ -1114,7 +1114,7 @@
|
|||
"@emotion/utils" "0.11.3"
|
||||
"@emotion/weak-memoize" "0.2.5"
|
||||
|
||||
"@emotion/cache@^11.7.1":
|
||||
"@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1":
|
||||
version "11.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539"
|
||||
integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==
|
||||
|
@ -1140,7 +1140,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
||||
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
|
||||
|
||||
"@emotion/react@^11.1.4":
|
||||
"@emotion/react@^11.1.1", "@emotion/react@^11.1.4":
|
||||
version "11.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.7.1.tgz#3f800ce9b20317c13e77b8489ac4a0b922b2fe07"
|
||||
integrity sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==
|
||||
|
@ -1948,7 +1948,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
|
||||
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
|
||||
|
||||
"@types/react@>=16.9.11":
|
||||
"@types/react-transition-group@^4.4.0":
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
|
||||
integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@>=16.9.11":
|
||||
version "17.0.38"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd"
|
||||
integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==
|
||||
|
@ -6597,6 +6604,11 @@ memfs@^3.1.2, memfs@^3.2.2:
|
|||
dependencies:
|
||||
fs-monkey "1.0.3"
|
||||
|
||||
memoize-one@^5.0.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
||||
|
||||
memoize-one@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||
|
@ -7944,7 +7956,7 @@ prop-types-extra@^1.1.0:
|
|||
react-is "^16.3.2"
|
||||
warning "^4.0.0"
|
||||
|
||||
"prop-types@15.x.x - 16.x.x", prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
"prop-types@15.x.x - 16.x.x", prop-types@^15.5.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
|
@ -8643,6 +8655,19 @@ react-scripts@5.0.0:
|
|||
optionalDependencies:
|
||||
fsevents "^2.3.2"
|
||||
|
||||
react-select@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.1.tgz#416c25c6b79b94687702374e019c4f2ed9d159d6"
|
||||
integrity sha512-OOyNzfKrhOcw/BlembyGWgdlJ2ObZRaqmQppPFut1RptJO423j+Y+JIsmxkvsZ4D/3CpOmwIlCvWbbAWEdh12A==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.0"
|
||||
"@emotion/cache" "^11.4.0"
|
||||
"@emotion/react" "^11.1.1"
|
||||
"@types/react-transition-group" "^4.4.0"
|
||||
memoize-one "^5.0.0"
|
||||
prop-types "^15.6.0"
|
||||
react-transition-group "^4.3.0"
|
||||
|
||||
react-spinners@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.11.0.tgz#186fd150cc9f7ab1436227f70d5d113b47e9e43d"
|
||||
|
@ -8660,7 +8685,7 @@ react-transition-group@^2.5.0:
|
|||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react-transition-group@^4.0.0:
|
||||
react-transition-group@^4.0.0, react-transition-group@^4.3.0:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
|
||||
integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==
|
||||
|
|
Loading…
Reference in New Issue
Block a user