修改头像组件

This commit is contained in:
caishi 2022-01-05 11:48:31 +08:00
parent 25f193a1d3
commit 0a334abede
11 changed files with 292 additions and 56 deletions

13
package-lock.json generated
View File

@ -3934,6 +3934,11 @@
"warning": "^4.0.3"
}
},
"cropperjs": {
"version": "1.5.12",
"resolved": "https://registry.npmmirror.com/cropperjs/download/cropperjs-1.5.12.tgz",
"integrity": "sha1-2cDbK/uMDXadUXOej5FrvEThD1A="
},
"cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@ -14227,6 +14232,14 @@
"countup.js": "^2.0.8"
}
},
"react-cropper": {
"version": "2.1.8",
"resolved": "https://registry.npmmirror.com/react-cropper/download/react-cropper-2.1.8.tgz?cache=0&sync_timestamp=1634379691101&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Freact-cropper%2Fdownload%2Freact-cropper-2.1.8.tgz",
"integrity": "sha1-vzWn3mV2n4rTV+iuiE55H+P+khI=",
"requires": {
"cropperjs": "^1.5.12"
}
},
"react-datepicker": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.14.1.tgz",

View File

@ -85,6 +85,7 @@
"react-content-loader": "^3.1.1",
"react-cookies": "^0.1.1",
"react-countup": "^6.1.0",
"react-cropper": "^2.1.8",
"react-datepicker": "^2.14.1",
"react-dev-utils": "^9.2.0-next.80",
"react-dom": "^16.13.1",

View File

@ -42,8 +42,8 @@ class NewHeader extends Component {
setevaluatinghides: false,
occupation: 0,
mydisplay: false,
headtypesonClickbool: false,
headtypess: "/",
// headtypesonClickbool: false,
// headtypess: "/",
settings: null,
visiblemyss: false,
openSearch:false,
@ -137,12 +137,12 @@ class NewHeader extends Component {
AccountProfiletype: false
})
};
headtypesonClick = (url, bool) => {
this.setState({
headtypess: url,
headtypesonClickbool: bool,
})
}
// headtypesonClick = (url, bool) => {
// this.setState({
// headtypess: url,
// headtypesonClickbool: bool,
// })
// }
//获取数据为空的时候
gettablogourlnull = () => {
this.setState({
@ -295,12 +295,14 @@ class NewHeader extends Component {
{...this.props}
{...this.state}
/> : ""}
{
publicNav &&
<a href={'https://www.ccf.org.cn/'} className={"fl pr15"}>
<img src={MainLogo} alt="ccf" />
</a>
}
<div style={{width:"78px"}}>
{
publicNav &&
<a href={'https://www.ccf.org.cn/'} className={"fl"}>
<img src={MainLogo} alt="ccf" />
</a>
}
</div>
{
settings && settings.nav_logo_url ?
<a href={settings && settings.new_course.default_url} className={"fl mr50"}>
@ -316,26 +318,26 @@ class NewHeader extends Component {
{
settings.navbar && settings.navbar.map((item, key) => {
var new_link = item.link;
var user_login = current_user && current_user.login;
var is_hidden = item.hidden
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
if (user_login) {
if (new_link.indexOf("courses") > -1) {
new_link = new_link.replace(/courses/g, user_login + "/courses")
} else if (new_link.indexOf("contests") > -1) {
new_link = new_link.replace(/contests/g, user_login + "/contests")
}
} else {
is_hidden = true
}
}
if (user_login && (new_link && new_link.indexOf("homes") > -1)) {
new_link = new_link.replace(/homes/g, user_login + "/user_activities")
}
// var user_login = current_user && current_user.login;
var is_hidden = item.hidden;
// if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
// if (user_login) {
// if (new_link.indexOf("courses") > -1) {
// new_link = new_link.replace(/courses/g, user_login + "/courses")
// } else if (new_link.indexOf("contests") > -1) {
// new_link = new_link.replace(/contests/g, user_login + "/contests")
// }
// } else {
// is_hidden = true
// }
// }
// if (user_login && (new_link && new_link.indexOf("homes") > -1)) {
// new_link = new_link.replace(/homes/g, user_login + "/user_activities")
// }
var waiLian = (new_link && str.filter(item=>new_link.indexOf(item)>-1) );
var wl = waiLian && waiLian.length>0;
return (
<li key={key} onClick={() => this.headtypesonClick(item.link, true)} className={`${this.matchpaths(new_link) === true ? 'pr active' : 'pr'}`} style={!is_hidden ? { display: 'flex' } : { display: 'none' }}>
<li key={key} className={`${this.matchpaths(new_link) === true ? 'pr active' : 'pr'}`} style={{display:!is_hidden ? 'flex' : 'none'} }>
<a href={new_link} target={wl ? "_self":"_blank"}>{item.name}</a>
</li>
)
@ -350,7 +352,6 @@ class NewHeader extends Component {
{
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
{/* <i className="iconfont icon-tianjiafangda ml30 mr15"></i> */}
<img src={require(`./img/add.png`)} alt="" width="16px" className="mr15 ml30"/>
</Dropdown>:""
}

View File

@ -321,7 +321,7 @@ class MilepostDetail extends Component {
</div>
{
search_count > limit?
<div className="mt30 pb30 edu-txt-center">
<div className="pt30 pb30 edu-txt-center" style={{borderTop:"1px solid #eee"}}>
<Pagination simple current={page} total={search_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>:""
}

View File

@ -232,6 +232,9 @@
border-bottom: 1px solid #eee;
padding: 16px 0px 16px 20px;
}
.issueItem:last-child{
border-bottom: none;
}
.issueNo {
padding: 0px 5px;
border-radius: 4px;

View File

@ -852,7 +852,7 @@ class order extends Component {
)}
{
search_count > select_params.limit ?
<div className="mt30 mb30 edu-txt-center">
<div className="pt30 mb30 edu-txt-center" style={{borderTop:"1px solid #eee"}}>
<Pagination
simple
defaultCurrent={select_params.page}

View File

@ -0,0 +1,101 @@
import React ,{useEffect, useRef, useState} from 'react';
import './Index.scss';
import { Modal , message } from 'antd';
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';
import axios from 'axios';
function Index({onCancel,avatarImg,login}){
const [ avatarPhoto , setAvatarPhoto ] = useState(avatarImg);
useEffect(()=>{
if(avatarImg){
setAvatarPhoto(avatarImg);
}
},[avatarImg])
const cropper = useRef();
const saveAvatar = async () => {
const imgUrl = cropper.current.cropper.getCroppedCanvas().toDataURL("image/jpeg");
if (!imgUrl) {
message.info('请先上传图片');
}
const url = `/users/${login}/update_image.json`;
axios.put(url,{
image:imgUrl
}).then(result=>{
if(result){
message.success("头像修改成功!");
onCancel(true);
}
}).catch(error=>{})
}
function onChange(e){
let files;
if (e.dataTransfer) {
files = e.dataTransfer.files;
} else if (e.target) {
files = e.target.files;
}
if (!files || (files && files.length===0)) {
return;
}
const file = files[0];
if (!/^image\/\w+/.test(file.type)) {
message.info('请选择一个图片格式的文件');
return;
}
if (file.size > 2 * 1024 * 1024) {
message.info('仅支持文件大小小于2M的文件');
return;
}
const reader = new FileReader();
reader.onload = () => {
setAvatarPhoto(reader.result);
};
reader.readAsDataURL(files[0]);
}
return(
<Modal
visible={true}
width="638px"
footer={null}
centered
title="修改头像"
onCancel={()=>onCancel(false)}
className="avatarBox"
>
<div className="avatarDiv">
<div>
<Cropper
style={{ height: 320, width: 320 }}
src={avatarPhoto}
guides={false}
preview="#updateAvatarImg"
ref={cropper}
/>
{/* <span className={"tips"}>仅支持JPG、GIF、PNG且文件小于2M</span> */}
</div>
<div className="previewBox">
<div className={"previewImg"} id="updateAvatarImg"></div>
<div className="uploadBtn">
<label className={"uploadButton"} id="uploadBtn" htmlFor="inputImage">
<input type="file" className="sr-only" id="inputImage" name="file" accept="image/*" style={{ display: "none" }} onChange={onChange}></input>
点击上传
</label>
<a onClick={saveAvatar}>保存头像</a>
</div>
</div>
</div>
</Modal>
)
}
export default Index;

View File

@ -0,0 +1,66 @@
.avatarBox{
position: relative;
.ant-modal-header{
background-color: rgba(242, 242, 255, 1);
.ant-modal-title{
text-align: left;
}
}
.ant-modal-body{
position: relative;
}
.avatarDiv{
display: flex;
.previewBox{
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
margin-left: 30px;
.uploadBtn{
margin-bottom: 30px;
display: flex;
a,label{
cursor: pointer;
display: block;
height: 32px;
line-height: 30px;
margin:0px 10px;
width: 100px;
border:1px solid rgba(208, 208, 208, 1);
background-color: white;
border-radius:4px;
text-align: center;
color:#666666;
span{
display: block;
.ant-upload.ant-upload-select {
width: 100%;
height: 32px;
}
.ant-upload-list{
display: none;
}
}
}
a{
background-color: rgba(65, 84, 241, 1);
color: white;
border-color: rgba(65, 84, 241, 1);
&:hover{
color: white!important;
}
}
}
}
.previewImg{
overflow: hidden;
background-color: #fff;
border-radius: 50%;
text-align: center;
width: 100px!important;
height: 100px!important;
}
}
}

View File

@ -137,7 +137,6 @@
.infoBox span {
margin-left: 10px;
}
.headimg {
position: relative;
display: block;
@ -150,8 +149,7 @@
.headimg span {
position: absolute;
bottom: -6px;
right: 0px;
left: 65px;
right: -16px;
}
.headimg span i {
font-size: 25px !important;

View File

@ -133,6 +133,32 @@ $flex:flex;
margin-left:10px ;
}
}
.headimg-div{
width: 110px;
height: 110px;
margin:0px auto;
position: relative;
.updateAvatar{
cursor: pointer;
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
content: "";
left: 0px;
top:0px;
background-color: rgba(0,0,0,0.2);
display: none;
align-items: center;
justify-content: center;
color: white;
transition: 1s;
}
&:hover .updateAvatar{
display: flex;
}
}
.headimg{
position: relative;
display: block;
@ -145,7 +171,7 @@ $flex:flex;
position: absolute;
bottom: -6px;
right: 0px;
left: 65px;
z-index: 11;
i{
font-size: 25px!important;
border-radius: 50%;

View File

@ -1,11 +1,12 @@
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { Button, Spin , Menu } from "antd";
import { Spin , Menu } from "antd";
import FocusButton from "../UsersList/focus_button";
import axios from "axios";
import { getImageUrl } from "educoder";
import { Route, Switch } from "react-router-dom";
import Avatar from './Avatar/Index';
import "./new_user.css";
import "../css/index.scss";
@ -14,10 +15,10 @@ import './Index.scss';
import Loadable from "react-loadable";
import Loading from "../../Loading";
const UpdateInfo = Loadable({
loader: () => import("./Material/Index"),
loading: Loading,
});
// const UpdateInfo = Loadable({
// loader: () => import("./Material/Index"),
// loading: Loading,
// });
const InfosDevOps = Loadable({
loader: () => import("./devOpsCI"),
loading: Loading,
@ -66,7 +67,8 @@ class Infos extends Component {
project_type: undefined,
route_type: undefined,
undo_events:0,
menuKey:"0"
menuKey:"0",
avatarVisible:false
};
}
@ -193,29 +195,54 @@ class Infos extends Component {
})
}
onCancelAvatar=(reset)=>{
this.setState({
avatarVisible:false
})
if(reset){
this.fetchUser();
const { resetUserInfo } = this.props;
resetUserInfo && resetUserInfo();
}
}
render() {
const { current_user } = this.props;
const { username } = this.props.match.params;
const { user, isSpin, route_type , undo_events , menuKey } = this.state;
const { user, isSpin, route_type , undo_events , menuKey , avatarVisible } = this.state;
return (
<div className="newMain clearfix">
{
avatarVisible &&
<Avatar
onCancel={this.onCancelAvatar}
avatarImg={getImageUrl(`/${user && user.image_url}`)}
login={current_user && current_user.login}
/>
}
<Spin spinning={isSpin}>
<div className="new-content-flex">
<div className="list-left" style={{border:"none"}}>
<div className="bgcF">
<div className="list-l-Menu text-center" style={{padding:"20px 25px"}}>
<span className="headimg">
<img src={getImageUrl(`/${user && user.image_url}`)} alt=""/>
<span>
{
user && user.gender===1?
<i className="iconfont icon-nan1"></i>
:
<i className="iconfont icon-nv1"></i>
}
<div className="headimg-div">
<span className="headimg">
<img src={getImageUrl(`/${user && user.image_url}`)} alt=""/>
<span>
{
user && user.gender===1?
<i className="iconfont icon-nan1"></i>
:
<i className="iconfont icon-nv1"></i>
}
</span>
</span>
</span>
{
current_user && current_user.login && current_user.login === username ?
<span className="updateAvatar" onClick={()=>{this.setState({avatarVisible:true})}}>修改头像</span>
:""
}
</div>
<div className="text-center mt15 font-24 task-hide" title={user && user.username}>
{user && user.username}
</div>