比較提交

...

8 次程式碼提交

共有 15 個檔案被更改,包括 331 行新增149 行删除

查看文件

@@ -101,6 +101,21 @@ a.btn {
height: 30px; height: 30px;
margin-left: 10px; margin-left: 10px;
} }
.nav {
display: flex;
margin-left: 20px;
}
.nav-item {
padding: 12px 16px;
}
.nav-link {
text-decoration: none;
color: white;
font-size: 18px;
}
.nav-link:active {
color: white;
}
b { b {
color: #9E0004; color: #9E0004;

查看文件

@@ -7,6 +7,7 @@ import { apis } from '../../helper/apis';
import { alert, confirmWithClose } from '../../helper/alert'; import { alert, confirmWithClose } from '../../helper/alert';
import { UserContext } from '../../helper/Context'; import { UserContext } from '../../helper/Context';
import Spinner from '../../components/Spinner/Spinner'; import Spinner from '../../components/Spinner/Spinner';
import { Link } from '../../components/SingleRouter/SingleRouter';
export class ReviewContainer extends Component { export class ReviewContainer extends Component {
static contextType = UserContext; static contextType = UserContext;
@@ -66,6 +67,11 @@ export class ReviewContainer extends Component {
<div className="sdu"> <div className="sdu">
<img src={images.icon} className="sdu-logo" alt="logo" /> <img src={images.icon} className="sdu-logo" alt="logo" />
<img src={images.name} className="sdu-name" alt="" /> <img src={images.name} className="sdu-name" alt="" />
<div className="nav">
<div className="nav-item">
<Link to="/" className="nav-link">首页</Link>
</div>
</div>
</div> </div>
<UserControl pageAuthLevel={2} /> <UserControl pageAuthLevel={2} />
</div> </div>

查看文件

@@ -120,3 +120,32 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
} }
.nickname-edit {
margin-top: 5px;
margin-left: -1px;
width: 360px;
padding: 4px;
border-radius: 8px;
background-color: #f7f7f7;
border: 1px solid #e5e5e5;
display: flex;
}
.nickname-edit > label {
line-height: 1.7em;
font-size: 18px;
}
.nickname-edit > input {
flex-grow: 1;
border: none;
background-color: #eee;
border-radius: 6px;
margin-right: 10px;
padding: 0 5px;
font-size: 16px;
}
.nickname-edit > .btn {
padding: .1em 0;
width: 60px;
border-radius: 6px;
}

查看文件

@@ -1,11 +1,11 @@
import { useState, useCallback, useRef } from "react"; import { useState, useCallback, useRef, useEffect } from "react";
import Spinner from '../Spinner/Spinner'; import Spinner from '../Spinner/Spinner';
import './AvatarUnit.css'; import './AvatarUnit.css';
import { multiFormPost } from '../../helper/axios'; import { multiFormPost, post } from '../../helper/axios';
import { alert } from '../../helper/alert'; import { alert } from '../../helper/alert';
import { apis } from "../../helper/apis"; import { apis } from "../../helper/apis";
export default function AvatarUnit({ avatar, onChangeAvatar, showTip }) { export default function AvatarUnit({ avatar, nickname, onChangeAvatar, showTip }) {
const [showBubble, setShowBubble] = useState(showTip); const [showBubble, setShowBubble] = useState(showTip);
const [showUpload, setShowUpload] = useState(false); const [showUpload, setShowUpload] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -14,9 +14,15 @@ export default function AvatarUnit({ avatar, onChangeAvatar, showTip }) {
const [uploaded, setUploaded] = useState(false); const [uploaded, setUploaded] = useState(false);
const [dataURL, setDataURL] = useState(null); const [dataURL, setDataURL] = useState(null);
const [file, setFile] = useState(null); const [file, setFile] = useState(null);
const [nicknameNow, setNicknameNow] = useState('');
const [nicknameUploading, setNicknameUploading] = useState(false);
const inputRef = useRef(null); const inputRef = useRef(null);
useEffect(() => {
setNicknameNow(nickname || '');
}, [nickname]);
// useEffect(() => { // useEffect(() => {
// setShowBubble(!localStorage.getItem("avatarTipShown")); // setShowBubble(!localStorage.getItem("avatarTipShown"));
// localStorage.setItem("avatarTipShown", true); // localStorage.setItem("avatarTipShown", true);
@@ -64,22 +70,37 @@ export default function AvatarUnit({ avatar, onChangeAvatar, showTip }) {
const formData = new FormData(); const formData = new FormData();
formData.append("image", file); formData.append("image", file);
multiFormPost(apis.uploadAvatar, formData).then(data => { multiFormPost(apis.uploadAvatar, formData).then(data => {
if (data.networkStatus === 200 && data.status) { setUploading(false);
if (data.networkStatus !== 200) return;
if (data.status) {
setUploaded(true); setUploaded(true);
setUploading(false);
setTimeout(() => { setTimeout(() => {
handleClose(); handleClose();
onChangeAvatar(data.data); onChangeAvatar(data.data);
}, 800); }, 800);
} }
else { else {
alert(data.data); alert('头像上传失败:' + data.data);
setUploading(false);
} }
}); });
} }
}, [file, onChangeAvatar]); }, [file, onChangeAvatar]);
const handleChangeNickname = useCallback(() => {
setNicknameUploading(true);
post(apis.updateNickname, { nickname: nicknameNow }).then(data => {
setNicknameUploading(false);
if (data.networkStatus !== 200) return;
if (data.status) {
alert('昵称已修改为:' + nicknameNow);
setNicknameNow(nicknameNow);
}
else {
alert('修改失败:' + data.data.map(item => item.msg).join(','));
}
});
}, [nicknameNow]);
return ( return (
<div className="user-avatar"> <div className="user-avatar">
<img src={avatar} alt="user avatar" onClick={() => { <img src={avatar} alt="user avatar" onClick={() => {
@@ -96,7 +117,7 @@ export default function AvatarUnit({ avatar, onChangeAvatar, showTip }) {
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M597.333333 512l284.444445 284.444444c2.929778 3.328 2.929778 22.357333 0 28.444445l-56.888889 56.888889c-6.087111 2.929778-25.116444 2.929778-28.444445 0L512 597.333333 227.555556 881.777778c-3.328 2.929778-22.328889 2.929778-28.444445 0l-56.888889-56.888889c-2.929778-6.087111-2.929778-25.116444 0-28.444445l284.444445-284.444444L142.222222 227.555556c-2.929778-3.328-2.929778-22.328889 0-28.444445l56.888889-56.888889c6.115556-2.929778 25.116444-2.929778 28.444445 0l284.444444 284.444445L796.444444 142.222222c3.328-2.929778 22.357333-2.929778 28.444445 0l56.888889 56.888889c2.929778 6.115556 2.929778 25.116444 0 28.444445L597.333333 512z" fill="#4a4a4a"></path></svg> <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M597.333333 512l284.444445 284.444444c2.929778 3.328 2.929778 22.357333 0 28.444445l-56.888889 56.888889c-6.087111 2.929778-25.116444 2.929778-28.444445 0L512 597.333333 227.555556 881.777778c-3.328 2.929778-22.328889 2.929778-28.444445 0l-56.888889-56.888889c-2.929778-6.087111-2.929778-25.116444 0-28.444445l284.444445-284.444444L142.222222 227.555556c-2.929778-3.328-2.929778-22.328889 0-28.444445l56.888889-56.888889c6.115556-2.929778 25.116444-2.929778 28.444445 0l284.444444 284.444445L796.444444 142.222222c3.328-2.929778 22.357333-2.929778 28.444445 0l56.888889 56.888889c2.929778 6.115556 2.929778 25.116444 0 28.444445L597.333333 512z" fill="#4a4a4a"></path></svg>
</button> </button>
<div className="user-avatar-edit-content"> <div className="user-avatar-edit-content">
<span className={'user-avatar-edit-tip' + (showBubble && !showUpload ? ' show' : '')}>点击图标修改头像</span> <span className={'user-avatar-edit-tip' + (showBubble && !showUpload ? ' show' : '')}>点击图标修改头像和昵称</span>
<div className="avatar-upload"> <div className="avatar-upload">
<div className={"upload-unit-progress" + (uploaded ? ' show' : '')}> <div className={"upload-unit-progress" + (uploaded ? ' show' : '')}>
<div className="icon"> <div className="icon">
@@ -129,6 +150,19 @@ export default function AvatarUnit({ avatar, onChangeAvatar, showTip }) {
</div> </div>
</div> </div>
</div> </div>
<div className="nickname-edit">
<label>昵称</label>
<input type="text" value={nicknameNow} onChange={e => setNicknameNow(e.target.value)} />
<button className="btn btn-primary" onClick={handleChangeNickname} disabled={nicknameUploading}>
{
nicknameUploading ? (
<Spinner />
) : (
'保存'
)
}
</button>
</div>
</div> </div>
</div> </div>
); );

查看文件

@@ -0,0 +1,8 @@
.preview {
width: 200px;
height: 200px;
}
.preview > img {
height: 200px;
cursor: zoom-in;
}

查看文件

@@ -0,0 +1,69 @@
import './ImagePreview.css';
import { useCallback, useRef, useState, useEffect, Fragment } from 'react';
import Spinner from '../Spinner/Spinner';
export default function ImagePreview({ image }) {
const [isScaled, setIsScaled] = useState(false);
const [transform, setTransform] = useState('');
const imgRef = useRef(null);
const [loading, setLoading] = useState(false);
const imgWidth = useRef(0), imgHeight = useRef(0);
useEffect(() => {
setLoading(true);
let img = new Image();
img.onload = () => {
setLoading(false);
imgWidth.current = img.width;
imgHeight.current = img.height;
};
img.src = image;
}, [image]);
const scale = useCallback(() => {
if (isScaled) return;
let el = imgRef.current;
let { x, y } = el.getBoundingClientRect();
let { innerWidth, innerHeight } = window;
let initialScale = 200 / imgHeight.current,
terminalScale = Math.min(1, Math.min((innerWidth - 10) / imgWidth.current, (innerHeight - 10) / imgHeight.current));
setTransform(`translate(${x + (imgWidth.current * initialScale - innerWidth) / 2}px, ${y + (200 - innerHeight) / 2}px) scale(${initialScale})`);
setIsScaled(true);
setTimeout(() => {
setTransform(`translate(0, 0) scale(${terminalScale})`);
}, 0);
}, [isScaled]);
const unscale = useCallback(() => {
if (!isScaled) return;
let el = imgRef.current;
let { x, y } = el.getBoundingClientRect();
let { innerWidth, innerHeight } = window;
let initialScale = 200 / imgHeight.current;
setTransform(`translate(${x + (imgWidth.current * initialScale - innerWidth) / 2}px, ${y + (200 - innerHeight) / 2}px) scale(${initialScale})`);
setIsScaled(true);
setTimeout(() => {
setIsScaled(false);
}, 300);
}, [isScaled]);
return (
<div className="preview">
{
loading ? (
<div className="spinner-wrap">
<Spinner isGray />
</div>
) : (
<Fragment>
<img src={image} alt="图片" onClick={scale} ref={imgRef} />
<div className={isScaled ? 'scaled-wrap open' : 'scaled-wrap'} onClick={unscale}>
<img className="scaled-image" src={image} alt="图片" style={{ transform }} />
</div>
</Fragment>
)
}
</div>
);
}

查看文件

@@ -9,6 +9,14 @@
animation: spin 1s steps(8, start) infinite; animation: spin 1s steps(8, start) infinite;
} }
.spinner-wrap {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
@keyframes spin { @keyframes spin {
from { from {
transform: rotate(0deg); transform: rotate(0deg);

查看文件

@@ -10,7 +10,6 @@ import { alert } from '../../helper/alert';
import History from '../../helper/history'; import History from '../../helper/history';
import AvatarUnit from '../AvatarUnit/AvatarUnit'; import AvatarUnit from '../AvatarUnit/AvatarUnit';
const exitContent = ['登录', '退出', '退出审核'];
// page level: 0: everyone, 1: login needed, 2: admin only // page level: 0: everyone, 1: login needed, 2: admin only
export default function UserControl({ pageAuthLevel, buttonOnly }) { export default function UserControl({ pageAuthLevel, buttonOnly }) {
const { userData, setUserData } = useContext(UserContext); const { userData, setUserData } = useContext(UserContext);
@@ -26,6 +25,7 @@ export default function UserControl({ pageAuthLevel, buttonOnly }) {
name: data.realName, name: data.realName,
role: data.role, role: data.role,
avatar: data.avatar, avatar: data.avatar,
nickname: data.nickname
}); });
}); });
return; return;
@@ -47,47 +47,49 @@ export default function UserControl({ pageAuthLevel, buttonOnly }) {
<UserContext.Consumer> <UserContext.Consumer>
{({ userData, setUserData }) => ( {({ userData, setUserData }) => (
<div className="user"> <div className="user">
{buttonOnly || (
<Fragment>
{
userData.role === -1
? (
<Spinner isGray />
)
: userData.role > 0 && (
<AvatarUnit
avatar={userData.avatar || images.avatar}
onChangeAvatar={url => setUserData({ ...userData, avatar: url })}
showTip={!userData.avatar}
/>
)
}
{
userData.role !== 0 && (
<div className="user-name">{userData.name}</div>
)
}
</Fragment>
)}
{ {
userData.role === pageAuthLevel userData.role === -1
? ( ? (
<button <Spinner />
className="btn btn-hollow btn-straight" ) : (
onClick={() => { <Fragment>
localStorage.setItem('jwt', ''); {buttonOnly || (
setUserData({ role: 0, name: '' }); <Fragment>
History.force('/login'); {
}} userData.role > 0 && (
>{exitContent[pageAuthLevel]}</button> <AvatarUnit
) avatar={userData.avatar || images.avatar}
: userData.role === 2 && ( onChangeAvatar={url => setUserData({ ...userData, avatar: url })}
<button showTip={!userData.avatar}
className="btn btn-hollow btn-straight" />
onClick={() => { )
History.push('/admin/review'); }
}} {
>进入审核</button> userData.role !== 0 && (
<div className="user-name">{userData.name}</div>
)
}
</Fragment>
)}
<button
className="btn btn-hollow btn-straight"
onClick={() => {
localStorage.setItem('jwt', '');
setUserData({ role: 0, name: '' });
History.force('/login');
}}
>{userData.role > 0 ? '退出账号' : '登录'}</button>
{
userData.role === 2 && pageAuthLevel !== 2 && (
<button
className="btn btn-light btn-straight"
onClick={() => {
History.push('/admin/review');
}}
>进入审核</button>
)
}
</Fragment>
) )
} }
</div> </div>

查看文件

@@ -6,3 +6,6 @@
color: white; color: white;
margin: 0 10px; margin: 0 10px;
} }
.user > :not(:first-child) {
margin-left: 10px;
}

查看文件

@@ -5,6 +5,7 @@ export const apis = {
login: backEndBaseURL + "/user/login", login: backEndBaseURL + "/user/login",
getProfile: backEndBaseURL + "/user/me", getProfile: backEndBaseURL + "/user/me",
uploadAvatar: backEndBaseURL + "/user/uploadAvatar", uploadAvatar: backEndBaseURL + "/user/uploadAvatar",
updateNickname: backEndBaseURL + "/user/updateNickname",
submitMessage: backEndBaseURL + "/post/submit", submitMessage: backEndBaseURL + "/post/submit",
listEssence: backEndBaseURL + "/post/listPublished?page=1", listEssence: backEndBaseURL + "/post/listPublished?page=1",

查看文件

@@ -84,28 +84,38 @@ async function send(xhr, retryConf) {
return failData; return failData;
} }
if (!waitToSend.length) return failData; if (waitToSend.length) return failData;
waitToSend.push(retryConf); waitToSend.push(retryConf);
console.log(err);
// 等待列表不为空时弹框要么出现了要么就是在消失的路上,没有办法给予用户点击重试的机会,所以交由外部逻辑处理 // 等待列表不为空时弹框要么出现了要么就是在消失的路上,没有办法给予用户点击重试的机会,所以交由外部逻辑处理
const failPostProceess = () => {
waitToSend.splice(waitToSend.indexOf(retryConf), 1);
return failData;
}
// 注意,理论上带有时间戳的请求是不可以重试的,但是这里不做那方面考虑,如果未来有需要,可以自己实现一个刷新时间戳重试的逻辑 // 注意,理论上带有时间戳的请求是不可以重试的,但是这里不做那方面考虑,如果未来有需要,可以自己实现一个刷新时间戳重试的逻辑
if (err.message === 'Network Error') if (err.message === 'Network Error')
return await failed('您的设备似乎断网了,或者服务器发生了问题,请检查网络后重试或刷新', flushWaitList) || failData; return (await failed('您的设备似乎断网了,或者服务器发生了问题,请检查网络后重试或刷新', flushWaitList(retryConf))) || failPostProceess();
if (!err?.response?.status) if (!err?.response?.status)
return await failed('请求发生问题:' + err.message, flushWaitList) || failData; return (await failed('请求发生问题:' + err.message, flushWaitList(retryConf))) || failPostProceess();
if (err.response.status === 504) if (err.response.status === 504)
return await failed('请求超时,请耐心等待几秒后重试或刷新', flushWaitList) || failData; return (await failed('请求超时,请耐心等待几秒后重试或刷新', flushWaitList(retryConf))) || failPostProceess();
return await failed('服务器出现问题,请稍后重试或刷新,错误代码' + err.response.status, flushWaitList) || failData; return (await failed('服务器出现问题,请稍后重试或刷新,错误代码' + err.response.status, flushWaitList(retryConf))) || failPostProceess();
} }
} }
function flushWaitList() { function flushWaitList(confToRun) {
let fns = waitToSend.map( return async () => {
conf => waitToSend.splice(waitToSend.indexOf(confToRun), 1);
async () => conf.resolver(await conf.fetcher()) let fns = waitToSend.map(
); conf =>
waitToSend.splice(0, waitToSend.length); async () => conf.resolver ? conf.resolver(await conf.fetcher()) : await conf.fetcher()
fns.forEach(fn => fn()); );
waitToSend.splice(0, waitToSend.length);
fns.forEach(fn => fn());
return confToRun.resolver ? confToRun.resolver(await confToRun.fetcher()) : await confToRun.fetcher()
};
} }
function feedWaitList(data) { function feedWaitList(data) {

查看文件

@@ -1,15 +1,20 @@
.index-container {
background-color: #F4F4F4;
min-height: 100vh;
}
.poster { .poster {
width: 100%; width: 100%;
height: 400px; height: 400px;
background-color: #84000B; background-color: #84000B;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
position: relative; position: relative;
} }
.img-poster {
height: 100%;
}
.index-btns { .index-btns {
position: absolute; position: absolute;
right: 40px; right: 40px;
@@ -20,7 +25,6 @@
.index-btns > .user { .index-btns > .user {
margin-right: 10px; margin-right: 10px;
} }
/* 这里的卡片和分栏结构就比较接近bootstrap了,可惜视觉做的太古板,如果愿意的话改成Material Design就更好了 */
.split-lg > .card { .split-lg > .card {
width: 440px; width: 440px;
flex-shrink: 0; flex-shrink: 0;
@@ -29,7 +33,7 @@
.card-header { .card-header {
padding: .5em; padding: .5em;
font-size: 20px; font-size: 20px;
border-bottom: 1px solid #e6e6e6; font-weight: bold;
} }
.card-body { .card-body {
padding: 10px 5px; padding: 10px 5px;
@@ -41,42 +45,47 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.img-list {
width: 100%;
display: flex;
flex-wrap: wrap;
margin: -3px -5px;
align-items: flex-start;
}
.img-list > img {
width: 200px;
margin: 3px 5px;
}
.message-list {
margin: 0;
padding-left: 0;
list-style: none;
}
.message-list > li {
line-height: 20px;
padding: 8px 0;
position: relative;
}
/* list disk */
.message-list > li::before {
content: "";
width: 8px;
height: 8px;
background-color: #DADADA;
margin-right: 10px;
border-radius: 50%;
display: inline-block;
}
@media (max-width: 980px) { @media (max-width: 980px) {
.split-lg > .card { .split-lg > .card {
width: 100%; width: 100%;
margin-bottom: 20px; margin-bottom: 20px;
} }
} }
.posts {
}
.post {
padding: 10px;
border-radius: 12px;
background-color: white;
margin-bottom: 10px;
box-shadow: 2px 2px 4px #0001;
}
.post > p {
padding-left: 40px;
}
.post-header {
padding: 5px;
display: flex;
align-items: center;
border-bottom: 1px solid #eee;
}
.post-body {
padding: 5px;
}
.post-avatar {
width: 40px;
height: 40px;
border-radius: 20px;
margin-right: 10px;
}
.post-username {
}
.post-time {
color: #888;
}
.post-image {
width: 200px;
height: 200px;
}

查看文件

@@ -1,4 +1,5 @@
import { Component } from 'react'; import { Component } from 'react';
import ImagePreview from '../components/ImagePreview/ImagePreview';
import { Link } from '../components/SingleRouter/SingleRouter'; import { Link } from '../components/SingleRouter/SingleRouter';
import Spinner from '../components/Spinner/Spinner'; import Spinner from '../components/Spinner/Spinner';
import UserControl from '../components/UserControl/UserControl'; import UserControl from '../components/UserControl/UserControl';
@@ -12,8 +13,7 @@ export class AppContainer extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
essentialMessages: [], posts: [],
essentialImages: [],
fetchingEssential: false, fetchingEssential: false,
}; };
} }
@@ -25,26 +25,20 @@ export class AppContainer extends Component {
this.setState({ fetchingEssential: false }); this.setState({ fetchingEssential: false });
if (networkStatus !== 200) return; if (networkStatus !== 200) return;
if (!status) return alert('获取精选列表失败:' + data + ',请刷新重试'); if (!status) return alert('获取精选列表失败:' + data + ',请刷新重试');
let messages = [], images = []; this.setState({ posts: data });
data.forEach(post => {
if (post.content) messages.push(post.content);
if (post.image) images.push(post.image);
});
this.setState({ essentialMessages: messages, essentialImages: images });
}); });
} }
render() { render() {
return ( return (
<div className="index-container"> <div className="index-container">
<div className="poster"> <div className="poster" style={{ backgroundImage: `url(${images.poster})` }}>
<img src={images.poster} className="img-poster" alt="海报" />
<div className='index-btns'> <div className='index-btns'>
<UserControl pageAuthLevel={1} buttonOnly /> <UserControl pageAuthLevel={1} buttonOnly />
<Link to="/upload" className="btn btn-light btn-straight btn-partIn">点击参加</Link> <Link to="/upload" className="btn btn-light btn-straight btn-partIn">点击参加</Link>
</div> </div>
</div> </div>
<div className="content split-lg"> <div className="content">
<div className="card"> <div className="card">
<div className="card-header"> <div className="card-header">
精选留言 精选留言
@@ -56,43 +50,33 @@ export class AppContainer extends Component {
<div className="col-center"><Spinner isGray /></div> <div className="col-center"><Spinner isGray /></div>
) )
: ( : (
this.state.essentialMessages.length === 0 this.state.posts.length === 0
? ( ? (
<div className="col-center">暂时没有精选留言</div> <div className="col-center">暂时没有精选留言</div>
) )
: ( : (
<ul className="message-list"> <div className="posts">
{ {
this.state.essentialMessages.map((msg, i) => ( this.state.posts.map((post, i) => (
<li dangerouslySetInnerHTML={{ __html: msg }} key={i}></li> <div className="post" key={i}>
)) <div className="post-header">
} <img class="post-avatar" src={post.avatar} alt="头像" />
</ul> <div>
) <div class="post-username">{post.nickname}</div>
) <div class="post-time">{new Date(post.time * 1000).toLocaleString()}发布</div>
} </div>
</div> </div>
</div> <div className="post-body">
<div className="card"> <p dangerouslySetInnerHTML={{ __html: post.content }}></p>
<div className="card-header"> {
精选图片 post.image && (
</div> <div className="post-image">
<div className="card-body"> <ImagePreview image={post.image} />
{ </div>
this.state.fetchingEssential )
? ( }
<div className="col-center"><Spinner isGray /></div> </div>
) </div>
: (
this.state.essentialImages.length === 0
? (
<div className="col-center">暂时没有精选图片</div>
)
: (
<div className="img-list">
{
this.state.essentialImages.map((src, i) => (
<img src={src} key={i} alt="精选图片" />
)) ))
} }
</div> </div>

查看文件

@@ -21,7 +21,7 @@
} }
.form-group > input:focus { .form-group > input:focus {
outline: none; outline: none;
border-color: #FDFDFD; border-color: transparent;
background-color: #FDFDFD; background-color: #FDFDFD;
box-shadow: 1px 3px 6px #0001; box-shadow: 1px 3px 6px #0001;
transform: translate(-2px, -2px); transform: translate(-2px, -2px);

查看文件

@@ -8,6 +8,7 @@ import { images } from '../resources.json';
import './upload.css'; import './upload.css';
import UserControl from '../components/UserControl/UserControl'; import UserControl from '../components/UserControl/UserControl';
import { Link } from '../components/SingleRouter/SingleRouter';
export class UploadContainer extends Component { export class UploadContainer extends Component {
constructor(props) { constructor(props) {
@@ -34,7 +35,7 @@ export class UploadContainer extends Component {
} }
handleSubmit() { handleSubmit() {
if ((this.state.msg === "" && this.file === null) || this.state.submitting) return; if (this.file === null || this.state.submitting) return;
this.setState({ submitting: true }); this.setState({ submitting: true });
localStorage.removeItem('msgTemp'); localStorage.removeItem('msgTemp');
} }
@@ -43,15 +44,13 @@ export class UploadContainer extends Component {
if (this.state.submitting && (!this.state.file || this.state.url !== "")) { if (this.state.submitting && (!this.state.file || this.state.url !== "")) {
post(apis.submitMessage, { content: this.state.msg, image: this.state.url }) post(apis.submitMessage, { content: this.state.msg, image: this.state.url })
.then(({ data, status, networkStatus }) => { .then(({ data, status, networkStatus }) => {
this.setState({ submitting: false });
if (networkStatus !== 200) return; if (networkStatus !== 200) return;
if (!status) { if (!status) {
this.setState({ submitting: false });
return alert('提交内容失败:' + data); return alert('提交内容失败:' + data);
} }
this.setState({ submitting: false, msg: "", url: "", file: null }); this.setState({ msg: "", url: "", file: null });
alert('内容提交成功啦').then(({ isConfirmed }) => { alert('内容提交成功啦');
if (isConfirmed) window.close();
});
}); });
} }
} }
@@ -69,6 +68,11 @@ export class UploadContainer extends Component {
<div className="sdu"> <div className="sdu">
<img src={images.icon} className="sdu-logo" alt="logo" /> <img src={images.icon} className="sdu-logo" alt="logo" />
<img src={images.name} className="sdu-name" alt="" /> <img src={images.name} className="sdu-name" alt="" />
<div className="nav">
<div className="nav-item">
<Link to="/" className="nav-link">首页</Link>
</div>
</div>
</div> </div>
<UserControl pageAuthLevel={1} /> <UserControl pageAuthLevel={1} />
</div> </div>
@@ -109,7 +113,7 @@ export class UploadContainer extends Component {
<button <button
className="btn btn-sdu btn-straight btn-upload" className="btn btn-sdu btn-straight btn-upload"
onClick={this.handleSubmit} onClick={this.handleSubmit}
disabled={(this.state.msg === "" && this.state.file === null) || this.state.submitting} disabled={this.state.file === null || this.state.submitting}
> >
{ {
this.state.submitting this.state.submitting