forked from Gitlink/forgeplus-react
增加成果模块,跨域调用,修改原资源中跨域不能传cookie的设置
This commit is contained in:
parent
52fa8da9a1
commit
db702ed816
|
|
@ -87,6 +87,7 @@
|
|||
"react-infinite-scroller": "^1.2.4",
|
||||
"react-loadable": "^5.3.1",
|
||||
"react-monaco-editor": "0.37",
|
||||
"react-pdf": "^4.2.0",
|
||||
"react-player": "^1.15.3",
|
||||
"react-redux": "5.0.7",
|
||||
"react-resizable": "^1.10.1",
|
||||
|
|
|
|||
19
src/App.js
19
src/App.js
|
|
@ -75,6 +75,12 @@ const EducoderLogin = Loadable({
|
|||
loading: Loading,
|
||||
})
|
||||
|
||||
// 成果库
|
||||
const Achieve=Loadable({
|
||||
loader: () => import('./achieveRequirement/index'),
|
||||
loading: Loading,
|
||||
})
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
@ -267,7 +273,20 @@ class App extends Component {
|
|||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{/*成果库*/}
|
||||
<Route
|
||||
path={"/achieve"}
|
||||
render={
|
||||
(props) => {
|
||||
return (<Achieve {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
}>
|
||||
</Route>
|
||||
|
||||
<Route component={Shixunnopage} />
|
||||
|
||||
|
||||
</Switch>
|
||||
</Router>
|
||||
</MuiThemeProvider>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Descriptions, Modal } from 'antd';
|
||||
import { Document, Page, pdfjs } from 'react-pdf';
|
||||
import DelModal from '../../components/DelModal';
|
||||
import { httpUrl } from '../../../fetch';
|
||||
import { deleteAchieve, getAchieveDetail } from '../api';
|
||||
import './index.scss';
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
||||
|
||||
export default (props) => {
|
||||
const { match, history, current_user } = props;
|
||||
const id = match.params.achieveId;
|
||||
const [achiveForm, setAchiveForm] = useState({});
|
||||
const [createUserId, setCreateUserId] = useState("");
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [fileType, setFileType] = useState(4);
|
||||
const [fileUrl, setFileUrl] = useState(4);
|
||||
const [numPages, setNumPages] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
getAchieveDetail(id).then(data => {
|
||||
setAchiveForm(data);
|
||||
setCreateUserId(data.user.id);
|
||||
})
|
||||
}, [id]);
|
||||
|
||||
function editItem() {
|
||||
props.history.push(`/achieve/achieveEdit/${id}`);
|
||||
}
|
||||
|
||||
function deletItem() {
|
||||
DelModal(() => {
|
||||
deleteAchieve(id).then(res => {
|
||||
if (res.code === '1') {
|
||||
props.showNotification("删除成功");
|
||||
history.go(-1);
|
||||
} else {
|
||||
props.showNotification("删除失败");
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
function pdfShow(e) {
|
||||
setFileType(e.fileType);
|
||||
if (e.fileType === 1 || e.fileType === 2 || e.fileType === 3) {
|
||||
// pdf||video||img
|
||||
setVisible(true);
|
||||
setFileUrl(httpUrl + '/busiAttachments/view/' + e.id);
|
||||
}
|
||||
}
|
||||
|
||||
function onDocumentLoadSuccess({ numPages }) {
|
||||
setNumPages(numPages);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="center-content">
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">{achiveForm.achievementName}</div>
|
||||
{
|
||||
createUserId === current_user.user_id &&
|
||||
<div className="center-right-but" ><span onClick={editItem}>编辑</span> <span onClick={deletItem}>删除</span></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<Descriptions className="item-content" column={1}>
|
||||
<Descriptions.Item label="成果类别">{achiveForm.achievementType && achiveForm.achievementType.dicItemName}</Descriptions.Item>
|
||||
<Descriptions.Item label="标签">
|
||||
{
|
||||
achiveForm.achievementLabel && achiveForm.achievementLabel.map(itemx => {
|
||||
return <span className="list-tag" key={itemx + 'ax'}>{itemx}</span>
|
||||
})
|
||||
}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="单位名称">{achiveForm.achievementBelong}</Descriptions.Item>
|
||||
<Descriptions.Item label="发布时间">{achiveForm.updatedAt}</Descriptions.Item>
|
||||
<Descriptions.Item label="成果描述">{achiveForm.achievementRemark}</Descriptions.Item>
|
||||
<Descriptions.Item label="成果文件" className="file-list-item">
|
||||
{
|
||||
achiveForm.achievementAttachments && achiveForm.achievementAttachments.map(item => {
|
||||
return <div className="file-list-box" key={item.id + 'down'}>
|
||||
<p onClick={() => { pdfShow(item) }}>{item.fileName}</p>
|
||||
<span className="downP" onClick={() => { downFile(item) }}>下载</span>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
visible={visible}
|
||||
maskClosable={true}
|
||||
closable={true}
|
||||
footer={null}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="file-modal"
|
||||
>
|
||||
{
|
||||
fileType === 3 && <div >
|
||||
<img className="show-img" src={fileUrl} alt="" />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
fileType === 2 && <div>
|
||||
<video src={fileUrl} style={{ width: '100%' }} controls="controls">您的浏览器不支持 video 标签。</video>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
fileType === 1 && <div className="pdf-box">
|
||||
{
|
||||
<Document
|
||||
file={fileUrl}
|
||||
onLoadSuccess={onDocumentLoadSuccess}
|
||||
>
|
||||
{new Array(numPages).fill("").map((item, index) => {
|
||||
return (
|
||||
<Page
|
||||
loading=""
|
||||
noData=""
|
||||
key={index}
|
||||
pageNumber={index + 1}
|
||||
renderTextLayer={true}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Document>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// 内容详情
|
||||
.item-content {
|
||||
padding: 10px 10px 0 30px;
|
||||
}
|
||||
.ant-descriptions-item-label {
|
||||
width: 5em;
|
||||
margin-right: 5px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
text-align: right;
|
||||
}
|
||||
.ant-descriptions-item-content {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
.file-list-item > span {
|
||||
vertical-align: top;
|
||||
}
|
||||
.file-list-box {
|
||||
width: 600px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p:hover {
|
||||
cursor: pointer;
|
||||
color: #0089ff;
|
||||
}
|
||||
.downP {
|
||||
color: #0089ff;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 文件预览modal样式
|
||||
.file-modal {
|
||||
width: 800px !important;
|
||||
.ant-modal-body {
|
||||
padding-top: 40px;
|
||||
.pdf-box {
|
||||
height: 70vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
.ant-modal-close {
|
||||
top: 0 !important;
|
||||
}
|
||||
.show-img {
|
||||
width: 100%;
|
||||
}
|
||||
.react-pdf__Page__canvas {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useState } from 'react';
|
||||
import { Form, Input, Select, Button, } from 'antd';
|
||||
import Upload from '../../components/Upload';
|
||||
import { httpUrl } from '../../../fetch';
|
||||
import { getDictionary, getAchieveDetail, addAchieve, editAchieve } from '../api';
|
||||
import './index.scss';
|
||||
|
||||
const Option = Select.Option;
|
||||
const { TextArea } = Input;
|
||||
|
||||
export default Form.create()(
|
||||
forwardRef(({ form, showNotification, match, history }, ref) => {
|
||||
|
||||
const [shareType, setShareType] = useState([]);
|
||||
const [tagType, setTagType] = useState([]);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
const [achievementFiles, setAchievementFiles] = useState(undefined);
|
||||
const [achievementFileTypes, setAchievementFileTypes] = useState(undefined);
|
||||
|
||||
const id = match.params.achieveId;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
|
||||
useEffect(() => {
|
||||
id && getAchieveDetail(id).then(data => {
|
||||
const formValue = {
|
||||
achievementName: data.achievementName,
|
||||
achievementTypeId: data.achievementTypeId,
|
||||
achievementBelong: data.achievementBelong,
|
||||
achievementLabel: data.achievementLabel,
|
||||
achievementRemark: data.achievementRemark
|
||||
};
|
||||
setFieldsValue(formValue);
|
||||
if (data.achievementAttachments.length) {
|
||||
for (const item of data.achievementAttachments) {
|
||||
item.name = item.fileName;
|
||||
item.size = item.fileSize;
|
||||
item.uid = "rc-upload" + item.id
|
||||
}
|
||||
setFileList(data.achievementAttachments);
|
||||
}
|
||||
})
|
||||
}, [id]);
|
||||
|
||||
// 加载选项数据
|
||||
useEffect(() => {
|
||||
getDictionary('share_type').then((res) => {
|
||||
setShareType(res.data);
|
||||
});
|
||||
getDictionary("tag_type").then((res) => {
|
||||
setTagType(res.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
||||
// 上传附件后得到的文件id数组
|
||||
function UploadFunc(ids, types) {
|
||||
setAchievementFiles(ids);
|
||||
setAchievementFileTypes(types);
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 4 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 20 },
|
||||
},
|
||||
};
|
||||
|
||||
const tailFormItemLayout = {
|
||||
wrapperCol: {
|
||||
xs: {
|
||||
span: 20,
|
||||
offset: 4,
|
||||
},
|
||||
sm: {
|
||||
span: 20,
|
||||
offset: 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// 修改
|
||||
function editItem() {
|
||||
if (!achievementFiles.length) {
|
||||
showNotification("请上传成果文件!");
|
||||
return;
|
||||
}
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = { ...values, achievementFiles, achievementFileTypes, uploadUserId: 1, };
|
||||
params.achievementLabel = params.achievementLabel.join();
|
||||
|
||||
if (id) {
|
||||
// 编辑
|
||||
editAchieve(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("成果更新成功!");
|
||||
history.go(-1);
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 新增
|
||||
addAchieve(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("成果更新成功!");
|
||||
history.go(-1);
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="center-content">
|
||||
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">修改成果</div>
|
||||
</div>
|
||||
|
||||
<Form className="achieve-form" {...formItemLayout}>
|
||||
{helper(
|
||||
"成果名称:",
|
||||
"achievementName",
|
||||
[{ required: true, message: "请输入成果名称" }],
|
||||
<Input
|
||||
placeholder="请输入成果名称"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"成果类别:",
|
||||
"achievementTypeId",
|
||||
[{ required: true, message: "请选择成果类别" }],
|
||||
<Select placeholder="请选择成果类别" style={{ width: "350px" }}
|
||||
>
|
||||
{
|
||||
shareType.map(item => {
|
||||
return <Option key={item.dicItemName + item.id} value={item.id}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"单位名称:",
|
||||
"achievementBelong",
|
||||
[{ required: true, message: "请输入单位名称" }],
|
||||
<Input
|
||||
placeholder="请输入单位名称"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Form.Item label={"成果文件:"} required={true}>
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={UploadFunc}
|
||||
size={100}
|
||||
showNotification={showNotification}
|
||||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{helper(
|
||||
"标签:",
|
||||
"achievementLabel",
|
||||
[{ required: true, message: "请选择成果标签" }],
|
||||
<Select
|
||||
placeholder="请选择成果标签" style={{ width: "350px" }}
|
||||
mode="tags"
|
||||
tokenSeparators={[',']}
|
||||
>
|
||||
{
|
||||
tagType.map(item => {
|
||||
return <Option key={item.dicItemName}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"成果描述:",
|
||||
"achievementRemark",
|
||||
[{ required: true, message: "请输入成果描述" }],
|
||||
<TextArea
|
||||
placeholder="请输入成果描述"
|
||||
autoSize={{ minRows: 3, maxRows: 5 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button className="mr20" type={"primary"} onClick={editItem}>保存</Button>
|
||||
<Button onClick={() => { history.go(-1) }}>取消</Button>
|
||||
</Form.Item>
|
||||
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.achieve-form{
|
||||
padding:24px 40px 0px 40px;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Pagination, Button, Icon } from 'antd';
|
||||
import ChooseNav from '../../components/chooseNav';
|
||||
import ItemList from '../../components/itemList';
|
||||
import { getDictionary, getAchieveList } from '../api';
|
||||
|
||||
export default (props) => {
|
||||
const { current_user } = props;
|
||||
// console.log(current_user);
|
||||
|
||||
const [achievementTypeId, setAchievementTypeId] = useState(''); //成果类别
|
||||
const [achievementFileTypes, setAchievementFileTypes] = useState(''); //文件类型
|
||||
const [orderBy, setOrderBy] = useState('-1');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [industryOption, setIndustryOption] = useState([]);
|
||||
const [achiveList, setAchiveList] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
getDictionary('share_type').then(res => {
|
||||
if (res && res.data) setIndustryOption(res.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
achievementTypeId,
|
||||
achievementFileTypes,
|
||||
achievementLabel: '',
|
||||
isOwned: '',
|
||||
orderBy,
|
||||
curPage,
|
||||
pageSize: 10
|
||||
};
|
||||
getAchieveList(params).then(data => {
|
||||
setAchiveList(data.rows);
|
||||
setTotal(data.total);
|
||||
})
|
||||
}, [achievementTypeId, achievementFileTypes, orderBy, curPage]);
|
||||
|
||||
|
||||
function changeOptionId(id, type) {
|
||||
if (type === 'share_type') {
|
||||
setAchievementTypeId(id);
|
||||
setCurPage(1);
|
||||
} else if (type === 'file_type') {
|
||||
setAchievementFileTypes(id);
|
||||
setCurPage(1);
|
||||
}
|
||||
}
|
||||
|
||||
function changeSort(sortType) {
|
||||
setOrderBy(sortType);
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
function goAchieveMine() {
|
||||
props.history.push('/achieve/achieveMine');
|
||||
}
|
||||
function goAdd() {
|
||||
props.history.push("/achieve/achieveAdd");
|
||||
}
|
||||
|
||||
function achiveClick(id) {
|
||||
props.history.push(`/achieve/achieveDetail/${id}`);
|
||||
}
|
||||
|
||||
const filetypeOption = [
|
||||
{
|
||||
dicItemName: '文件',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
dicItemName: '视频',
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
dicItemName: '图片',
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
dicItemName: '软件',
|
||||
id: 4
|
||||
},
|
||||
{
|
||||
dicItemName: '其它',
|
||||
id: 5
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="nav-content">
|
||||
<ChooseNav
|
||||
key={'share_type'}
|
||||
type={'share_type'}
|
||||
title={'成果类别'}
|
||||
options={industryOption}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
|
||||
<ChooseNav
|
||||
key={'file_type'}
|
||||
type={'file_type'}
|
||||
title={'文件类型'}
|
||||
options={filetypeOption}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="center-content">
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">
|
||||
<div className={classNames({ 'center-left-butD': true, 'center-left-butDACT': orderBy === '-1' })} onClick={() => { changeSort('-1') }}>默认</div>
|
||||
<div className={classNames({ 'center-left-butD': true, 'center-left-butDACT': orderBy === 'created_at' })} onClick={() => { changeSort('created_at') }}><Icon type="arrow-down" />最新</div>
|
||||
<div className={classNames({ 'center-left-butD': true, 'center-left-butDACT': orderBy === 'view_count' })} onClick={() => { changeSort('view_count') }}><Icon type="arrow-down" />最热</div>
|
||||
</div>
|
||||
{
|
||||
current_user.login &&
|
||||
<div className="center-right-but">
|
||||
<Button className="mr15 font-12" size="small" type="primary" onClick={goAchieveMine}>我的成果</Button>
|
||||
<Button className="mr20 font-12" size="small" type="primary" onClick={goAdd}><i className="iconfont icon-zaibianji font-12 mr3"></i>发布成果</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ItemList
|
||||
list={achiveList}
|
||||
itemClick={achiveClick}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="edu-txt-center ">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Pagination } from 'antd';
|
||||
import ItemList from '../../components/itemList';
|
||||
import DelModal from '../../components/DelModal';
|
||||
import { deleteAchieve, getAchieveList } from '../api';
|
||||
|
||||
export default (props) => {
|
||||
const [achiveList, setAchiveList] = useState([]);
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
getAcheiveListOwn();
|
||||
}, [curPage]);
|
||||
|
||||
function getAcheiveListOwn() {
|
||||
const params = {
|
||||
achievementTypeId: '',
|
||||
achievementFileTypes: '',
|
||||
achievementLabel: '',
|
||||
// isOwned: '', //方便游客身份时显示数据
|
||||
isOwned: true,
|
||||
orderBy: -1,
|
||||
curPage,
|
||||
pageSize: 10
|
||||
};
|
||||
getAchieveList(params).then(data => {
|
||||
setAchiveList(data.rows);
|
||||
setTotal(data.total);
|
||||
})
|
||||
}
|
||||
|
||||
function achiveClick(id) {
|
||||
props.history.push(`/achieve/achieveDetail/${id}`);
|
||||
}
|
||||
|
||||
function editItem(id) {
|
||||
props.history.push(`/achieve/achieveEdit/${id}`);
|
||||
}
|
||||
|
||||
function deletItem(id) {
|
||||
DelModal(() => {
|
||||
deleteAchieve(id).then(res => {
|
||||
if (res.code === '1') {
|
||||
props.showNotification("删除成功");
|
||||
getAcheiveListOwn();
|
||||
} else {
|
||||
props.showNotification("删除失败");
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="center-content">
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">
|
||||
我的成果
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ItemList
|
||||
list={achiveList}
|
||||
itemClick={achiveClick}
|
||||
deletItem={deletItem}
|
||||
editItem={editItem}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="edu-txt-center ">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import fetch from '../../fetch';
|
||||
|
||||
// 获取字典分类列表
|
||||
export function getDictionary(id) {
|
||||
return fetch({
|
||||
url: '/dicItem/getData?dicTypeCode=' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 成果列表查询
|
||||
export async function getAchieveList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/achievement/',
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
if (res && res.data) {
|
||||
for (const i of res.data.rows) {
|
||||
// 处理分解标签
|
||||
i.achievementLabel = i.achievementLabel.split(',');
|
||||
}
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
|
||||
//新增成果
|
||||
export function addAchieve(data) {
|
||||
return fetch({
|
||||
url: '/api/achievement/',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//删除成果
|
||||
export function deleteAchieve(id) {
|
||||
return fetch({
|
||||
url: '/api/achievement/' + id,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
//更新成果
|
||||
export function editAchieve(data) {
|
||||
return fetch({
|
||||
url: '/api/achievement/',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 成果详情查询
|
||||
export async function getAchieveDetail(id) {
|
||||
let res = await fetch({
|
||||
url: '/api/achievement/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
res.data.achievementLabel = res.data.achievementLabel.split(',');
|
||||
return res.data;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Modal } from 'antd';
|
||||
|
||||
export default (
|
||||
handleOk,
|
||||
title,
|
||||
content,
|
||||
handleCancel) => {
|
||||
return Modal.confirm({
|
||||
title: title || "警告",
|
||||
content: content || "确认删除?",
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk() {
|
||||
handleOk && handleOk();
|
||||
},
|
||||
onCancel() {
|
||||
handleCancel && handleCancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Upload, Button } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { appendFileSizeToUploadFileAll } from 'educoder';
|
||||
axios.defaults.withCredentials = true;
|
||||
|
||||
function Uploads({ className, size, actionUrl, fileList, showNotification, load }) {
|
||||
const [files, setFiles] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (fileList) {
|
||||
init();
|
||||
}
|
||||
}, [fileList]);
|
||||
|
||||
function init() {
|
||||
let f = appendFileSizeToUploadFileAll(fileList);
|
||||
setFiles(f);
|
||||
}
|
||||
function onAttachmentRemove(file) {
|
||||
if (!file.percent || file.percent === 100) {
|
||||
deleteAttachment(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function deleteAttachment(file) {
|
||||
let id = (file.response && file.response.data && file.response.data.id) || file.id;
|
||||
|
||||
// 暂时不直接删除上传的文件,只在最后保存的时候进行修改
|
||||
let nf = files.filter(item => (item.response && item.response.data && item.response.data.id !== id) && (item.id !== id));
|
||||
setFiles(nf);
|
||||
fileIdList(nf);
|
||||
|
||||
// 发送服务到后台删除文件,同步更新数据
|
||||
// const url = actionUrl + `/busiAttachments/${id}`;
|
||||
// axios.delete(url).then((response) => {
|
||||
// if (response.data) {
|
||||
// if (response.data.code === "1") {
|
||||
// let nf = files.filter(item => (item.response.data.id !== id) && (item.id !== id));
|
||||
// setFiles(nf);
|
||||
// fileIdList(nf);
|
||||
// } else {
|
||||
// showNotification(response.data.message);
|
||||
// }
|
||||
// }
|
||||
// }).catch(function (error) {
|
||||
// console.log(error);
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
function handleChange(info) {
|
||||
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
|
||||
let fileList = info.fileList;
|
||||
setFiles(appendFileSizeToUploadFileAll(fileList));
|
||||
if (info.file.status === 'done' || info.file.status === 'removed') fileIdList(fileList);
|
||||
}
|
||||
}
|
||||
|
||||
function fileIdList(fileList) {
|
||||
let id = [];
|
||||
let fileType = [];
|
||||
for (const item of fileList) {
|
||||
id.push(item.id || item.response.data.id);
|
||||
fileType.push(item.fileType || item.response.data.fileType);
|
||||
}
|
||||
load && load(id.join(), fileType.join());
|
||||
}
|
||||
|
||||
function beforeUpload(file) {
|
||||
const isLt100M = file.size / 1024 / 1024 < size;
|
||||
if (!isLt100M) {
|
||||
showNotification(`文件大小必须小于${size}MB!`);
|
||||
}
|
||||
return isLt100M;
|
||||
}
|
||||
|
||||
const upload = {
|
||||
name: 'file',
|
||||
fileList: files,
|
||||
action: actionUrl + `/busiAttachments/upload`,
|
||||
onChange: handleChange,
|
||||
onRemove: onAttachmentRemove,
|
||||
beforeUpload: beforeUpload,
|
||||
};
|
||||
return (
|
||||
<Upload {...upload} className={className}>
|
||||
<Button type="primary">点击上传</Button>
|
||||
<span className="ml10 color-grey-9">(你可以上传小于<span className="color-red">{size}MB</span>的文件)</span>
|
||||
</Upload>
|
||||
)
|
||||
}
|
||||
export default Uploads;
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './index.scss';
|
||||
|
||||
export default (props) => {
|
||||
const {title, options,changeOptionId ,type} = props;
|
||||
|
||||
const [id, setId] = useState("");
|
||||
|
||||
useEffect(()=>{
|
||||
changeOptionId(id,type);
|
||||
},[id])
|
||||
|
||||
return (
|
||||
|
||||
<div className="shop-box">
|
||||
<div className="choose-title">{title}</div>
|
||||
<div className="choose-list">
|
||||
<div className={classNames({"choose-item-checked":id==="","choose-item":true})} key={"all"} onClick={()=>{setId("")}}>全部</div>
|
||||
{
|
||||
options.map((item) => {
|
||||
return <div className={classNames({"choose-item-checked":id===item.id,"choose-item":true})} key={item.dicItemName} onClick={()=>{setId(item.id)}} >{item.dicItemName}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
.nav-content {
|
||||
margin-top:20px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #eaeaea;
|
||||
box-shadow: #ddd 0px 0px 5px;
|
||||
}
|
||||
.shop-box {
|
||||
width: 1280px;
|
||||
border-top: 1px solid #eaeaea;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
}
|
||||
.choose-title {
|
||||
width: 110px;
|
||||
background: #f3f3f3;
|
||||
text-align: center;
|
||||
padding: 16px 0;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
}
|
||||
.choose-list {
|
||||
width: 1170px;
|
||||
padding: 16px 0;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
}
|
||||
.choose-item {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 0 15px ;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color: #0072ff;
|
||||
}
|
||||
}
|
||||
|
||||
.choose-item-checked {
|
||||
color: #0072ff;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import './index.scss';
|
||||
|
||||
export default (props) => {
|
||||
const { list, itemClick, editItem, deletItem } = props;
|
||||
|
||||
return (
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
<div className="list-title" onClick={() => { itemClick(item.id) }}>
|
||||
{item.achievementName}
|
||||
</div>
|
||||
<div >
|
||||
{
|
||||
item.achievementLabel.map(i => {
|
||||
return <span className="list-tag" key={i + "av"}>{i}</span>;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="list-other">
|
||||
{item.user && <p>发布者:{item.user.nickname ? item.user.nickname : item.user.login}</p>}
|
||||
<p>发布时间:{item.achievementPublishTime}</p>
|
||||
</div>
|
||||
{editItem && <div className="list-box-action">
|
||||
<button onClick={() => { editItem(item.id) }}><i className="iconfont icon-zaibianji font-25"></i></button>
|
||||
<button onClick={() => { deletItem(item.id) }}><i className="iconfont icon-shanchu font-30 "></i></button>
|
||||
</div>}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
.list-title {
|
||||
font-size: 17px;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
.list-title p {
|
||||
display: inline-block;
|
||||
}
|
||||
.list-title p:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
.list-title span {
|
||||
padding: 3px 5px;
|
||||
background: #f8c753;
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
span.list-done {
|
||||
background: #35d77e;
|
||||
}
|
||||
|
||||
.list-tag {
|
||||
display: inline-block;
|
||||
margin: 5px 10px 5px 0;
|
||||
background: #cfe9ff;
|
||||
color: #0089ff;
|
||||
font-size: 14px;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
.list-other > p {
|
||||
display: inline-block;
|
||||
margin: 0 10px 0 0;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.list-box-action {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 100px;
|
||||
visibility: hidden;
|
||||
}
|
||||
.list-box:hover .list-box-action {
|
||||
visibility: visible;
|
||||
}
|
||||
.list-box-action button {
|
||||
display: inline-block;
|
||||
margin: 0 25px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
color: #0089ff;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
border: 0;
|
||||
border-radius: 25px;
|
||||
box-shadow: 2px 2px 5px 2px #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../Loading";
|
||||
import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC";
|
||||
import './index.scss';
|
||||
|
||||
const AchieveIndex = Loadable({
|
||||
loader: () => import("./achieve/achieveList"),
|
||||
loading: Loading,
|
||||
});
|
||||
const AchieveDetail = Loadable({
|
||||
loader: () => import("./achieve/achieveDetail"),
|
||||
loading: Loading,
|
||||
});
|
||||
const AchieveMine = Loadable({
|
||||
loader: () => import("./achieve/achieveMine"),
|
||||
loading: Loading,
|
||||
});
|
||||
const AchieveAdd = Loadable({
|
||||
loader: () => import("./achieve/achieveEdit"),
|
||||
loading: Loading,
|
||||
});
|
||||
const AchieveEdit = Loadable({
|
||||
loader: () => import("./achieve/achieveEdit"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
class Index extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Switch {...this.props}>
|
||||
<Route
|
||||
path="/achieve/achieveDetail/:achieveId"
|
||||
render={(props) => (
|
||||
<AchieveDetail {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/achieve/achieveMine"
|
||||
render={(props) => (
|
||||
<AchieveMine {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/achieve/achieveAdd"
|
||||
render={(props) => (
|
||||
<AchieveAdd {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/achieve/achieveEdit/:achieveId"
|
||||
render={(props) => (
|
||||
<AchieveEdit {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/"
|
||||
render={(props) => (
|
||||
<AchieveIndex {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* <Route
|
||||
exact
|
||||
path="/"
|
||||
render={(props) => (
|
||||
this.props.current_user && this.props.current_user.login ?
|
||||
<Infos {...this.props} {...props} />
|
||||
:
|
||||
<AchieveIndex {...this.props} {...props} />
|
||||
)}
|
||||
></Route> */}
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default withRouter(
|
||||
ImageLayerOfCommentHOC({
|
||||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||
parentSelector: ".newMain",
|
||||
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Index))))
|
||||
);
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// 本模块公共样式
|
||||
|
||||
.centerbox {
|
||||
width: 1280px;
|
||||
margin:40px auto;
|
||||
}
|
||||
.center-content {
|
||||
width: 1280px;
|
||||
margin: 20px 0;
|
||||
background: #fff;
|
||||
border: 1px solid #dedede;
|
||||
box-shadow: #eee 0px 1px 1px 3px;
|
||||
}
|
||||
.centerScreen {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 46px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
|
||||
// 内容标题左侧样式
|
||||
.center-left-but {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
margin-left: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.center-left-butD {
|
||||
height: 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
color: #333;
|
||||
padding: 0 10px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #dedede;
|
||||
}
|
||||
.center-left-butD:hover {
|
||||
background-color: #fff;
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
.center-left-butDACT {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// 内容标题右侧样式
|
||||
.center-right-but {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.center-right-but>span{
|
||||
margin: 0 10px;
|
||||
font-size: 16px;
|
||||
color: #0089ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 通用标签样式
|
||||
.list-tag{
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
background: #cfe9ff;
|
||||
color: #0089ff;
|
||||
font-size: 14px;
|
||||
border-radius:3px ;
|
||||
padding: 2px 5px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
import axios from 'axios';
|
||||
import cookie from 'react-cookies';
|
||||
|
||||
export const httpUrl='http://117.50.100.12:8001';
|
||||
|
||||
const TokenKey = 'autologin_forge_military';
|
||||
axios.defaults.withCredentials = true;
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
// baseURL: process.env.BASE_API, // api的base_url
|
||||
baseURL:httpUrl,
|
||||
timeout: 5000 // 请求超时时间
|
||||
// headers:{'X-Custom-Header': 'foobar'} // 请求头
|
||||
});
|
||||
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(config => {
|
||||
if (cookie.load(TokenKey)) {
|
||||
config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
// config.headers['Authorization'] = 'autologin_forge_military=' + cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config;
|
||||
}, error => {
|
||||
// Do something with request error
|
||||
console.log(error); // for debug
|
||||
Promise.reject(error);
|
||||
});
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
|
||||
response => {
|
||||
/**
|
||||
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
||||
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
||||
*/
|
||||
const res = response;
|
||||
if (res.status === 400) {
|
||||
// Message({
|
||||
// message: '请求错误',
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000
|
||||
// });
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
// Message({
|
||||
// message: '未授权,请登录!',
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000
|
||||
// });
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 40001) {
|
||||
// Message({
|
||||
// message: '账户或密码错误!',
|
||||
// type: 'warning'
|
||||
// });
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (response.status !== 200 && res.status !== 200) {
|
||||
// Message({
|
||||
// message: res.message,
|
||||
// type: 'error',
|
||||
// duration: 7 * 1000
|
||||
// });
|
||||
} else {
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
if (error.response&& error.response.status === 401 && !error.config.url.includes('/auth-server/oauth/token')) {
|
||||
return cookie.remove(TokenKey);
|
||||
// that.$router.push('/Login');
|
||||
} else {
|
||||
// that.$router.push('/Login');
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
|
|
@ -44,6 +44,7 @@ function Index(props){
|
|||
|
||||
function getData(){
|
||||
const url = https +`/api/project/achievement/`;
|
||||
axios.defaults.withCredentials = true;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
projectId:repo_id,
|
||||
|
|
|
|||
Loading…
Reference in New Issue