Merge pull request 'add some components 01' (#6) from binary/OpenPBL:pr02 into master
This commit is contained in:
commit
7786ef3ef1
|
@ -0,0 +1,473 @@
|
|||
import React, {Component} from "react";
|
||||
import {Button, Form, Input, Modal, Select, Space, Table, Tag, message} from "antd";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import * as ProjectBackend from "./backend/ProjectBackend";
|
||||
import ModalCard from "./ModulaCard";
|
||||
import "./BuildTeam.less";
|
||||
import {WarningTwoTone} from "@ant-design/icons";
|
||||
|
||||
const {Search, TextArea} = Input;
|
||||
const {confirm} = Modal;
|
||||
const {Option} = Select;
|
||||
|
||||
class index extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
loadingState: false,
|
||||
createLoading: false,
|
||||
roleChangeForm: {
|
||||
show: false,
|
||||
assignment_id: "",
|
||||
new_role: "",
|
||||
updateLoading: false,
|
||||
},
|
||||
addMemberForm: {
|
||||
show: false,
|
||||
loadingState: false,
|
||||
role: 1,
|
||||
user_id: "",
|
||||
},
|
||||
emailForm: {
|
||||
show: false,
|
||||
loadingState: false,
|
||||
message: "",
|
||||
send_time: "",
|
||||
sender: "binary",
|
||||
destination: [],
|
||||
subject: "",
|
||||
},
|
||||
memberList: [],
|
||||
};
|
||||
}
|
||||
columns = [{
|
||||
title: "姓名",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.name}</span>
|
||||
),
|
||||
}, {
|
||||
title: "年龄",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.birthday}</span>
|
||||
),
|
||||
}, {
|
||||
title: "性别",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.gender ? "男" : "女"}</span>
|
||||
),
|
||||
}, {
|
||||
title: "专业",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<Tag color="processing">{record.info.owner}</Tag>
|
||||
),
|
||||
}, {
|
||||
title: "职位",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.type}</span>
|
||||
),
|
||||
}, {
|
||||
title: "邮箱",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<Button type="link" onClick={() => {
|
||||
this.setState({
|
||||
emailForm: Object.assign(this.state.emailForm, {destination: [record.info.email], send_time: new Date().getTime().toString(), show: true}),
|
||||
});
|
||||
}}>
|
||||
{record.info.email}
|
||||
</Button>
|
||||
),
|
||||
}, {
|
||||
title: "组织",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.signupApplication}</span>
|
||||
),
|
||||
}, {
|
||||
title: "位置",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.region}</span>
|
||||
),
|
||||
}, {
|
||||
title: "电话",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<span>{record.info.phone}</span>
|
||||
),
|
||||
}, {
|
||||
title: "项目角色",
|
||||
align: "center",
|
||||
render: (text, record) => {
|
||||
let roleList = ["管理员", "专家", "学科助理", "教师", "外审专家"];
|
||||
return (
|
||||
<Tag color="green">{roleList[record.role - 1]}</Tag>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: "状态",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<>
|
||||
{
|
||||
record.info.isOnline ? (
|
||||
<Tag color="#87d068">已确认 √</Tag>
|
||||
) : (
|
||||
<Tag color="#f50">未确认 ×</Tag>
|
||||
)
|
||||
}
|
||||
</>
|
||||
),
|
||||
}, {
|
||||
title: "管理",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
<Button type="link" onClick={() => {
|
||||
this.setState({
|
||||
roleChangeForm: Object.assign(this.state.roleChangeForm, {
|
||||
assignment_id: record.Id,
|
||||
new_role: record.role,
|
||||
show: true,
|
||||
}),
|
||||
});
|
||||
}}>更改角色</Button>
|
||||
<Button type="link" danger onClick={() => {
|
||||
confirm({
|
||||
icon: <WarningTwoTone />,
|
||||
content: "该删除操作不可逆,是否继续?",
|
||||
okText: "确认移除",
|
||||
cancelText: "取消移除",
|
||||
// onOk: () => {
|
||||
// this.setState({
|
||||
// loadingState: true
|
||||
// });
|
||||
// request({
|
||||
// url: baseURL + `/review/proj/assign/${record.uuid}`,
|
||||
// // url:`http://49.232.73.36:8081/review/proj/assign/${record.uuid}`,
|
||||
// method: "DELETE"
|
||||
// }).then(res => {
|
||||
// this.setState({
|
||||
// loadingState: false
|
||||
// });
|
||||
// message.success("删除成功!");
|
||||
// this.getProjectMember();
|
||||
// }).catch(err => {
|
||||
// message.error(err.message || "请求错误!");
|
||||
// this.setState({
|
||||
// loadingState: false
|
||||
// });
|
||||
// });
|
||||
// },
|
||||
onOk: () => { },
|
||||
onCancel() {
|
||||
message.info("已取消移除");
|
||||
},
|
||||
});
|
||||
}}>移除人员</Button>
|
||||
</Space>
|
||||
),
|
||||
}]
|
||||
|
||||
emailFormRef = React.createRef()
|
||||
|
||||
componentDidMount() {
|
||||
this.getProjectMember();
|
||||
}
|
||||
|
||||
getProjectMember = () => {
|
||||
this.setState({
|
||||
loadingState: true,
|
||||
});
|
||||
ProjectBackend.GetProjectAssignments(this.props.match.params.project_id.split("_").join("/")).then(res => {
|
||||
let memberList = [];
|
||||
memberList = [...res.data.admins.map(item => {
|
||||
item.roleName = "admin";
|
||||
return item;
|
||||
}), ...res.data.assistants.map(item => {
|
||||
item.roleName = "assistant";
|
||||
return item;
|
||||
}), ...res.data.experts.map(item => {
|
||||
item.roleName = "expert";
|
||||
return item;
|
||||
}), ...res.data.out_experts.map(item => {
|
||||
item.roleName = "out_expert";
|
||||
return item;
|
||||
}), ...res.data.teachers.map(item => {
|
||||
item.roleName = "teacher";
|
||||
return item;
|
||||
})];
|
||||
let id_list = memberList.map(item => item.user_id);
|
||||
ProjectBackend.GetUserList(id_list).then(res => {
|
||||
let userInfo_list = Object.values(res.data);
|
||||
memberList = memberList.map((item, index) => {
|
||||
item.info = userInfo_list[index];
|
||||
return item;
|
||||
});
|
||||
this.setState({
|
||||
memberList,
|
||||
loadingState: false,
|
||||
});
|
||||
});
|
||||
// var res1 = {
|
||||
// "operation_code": 1000,
|
||||
// "message": "",
|
||||
// "data": {
|
||||
// "2ab2770e-b6e7-476b-969c-2db815e878e6": {
|
||||
// "Id": "62e4b104b686c0cf874cf17a",
|
||||
// "CreateAt": "2022-07-30T04:18:12.557Z",
|
||||
// "UpdateAt": "2022-07-30T04:18:12.557Z",
|
||||
// "uuid": "2ab2770e-b6e7-476b-969c-2db815e878e6",
|
||||
// "profile": {
|
||||
// "name": "string",
|
||||
// "age": 0,
|
||||
// "locaion": "string",
|
||||
// "email": "string",
|
||||
// "phone": "string",
|
||||
// "gender": true,
|
||||
// "organization": "",
|
||||
// "degree": "string",
|
||||
// "position": "string",
|
||||
// "employer": "string",
|
||||
// "major": "string",
|
||||
// },
|
||||
// "password": "a6ba7732dfb7c19d1520b1eb0386d1a2",
|
||||
// "salt": "371832835a7ea8c50f44c8c8ab333c55",
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// let userInfo_list = Object.values(res1.data);
|
||||
// memberList = memberList.map((item, index) => {
|
||||
// item.info = userInfo_list[index].profile;
|
||||
// return item;
|
||||
// });
|
||||
// this.setState({
|
||||
// memberList,
|
||||
// loadingState: false,
|
||||
// });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="build-team-page" data-component="build-team-page">
|
||||
<ModalCard
|
||||
title="项目成员"
|
||||
right={(
|
||||
<Button type="primary" size="small" onClick={() => {
|
||||
this.setState({
|
||||
addMemberForm: Object.assign(this.state.addMemberForm, {show: true}),
|
||||
});
|
||||
}}>添加成员</Button>
|
||||
)}
|
||||
>
|
||||
<div className="member-list">
|
||||
<Table
|
||||
key="admins"
|
||||
columns={this.columns}
|
||||
rowKey="Id"
|
||||
pagination={false}
|
||||
dataSource={this.state.memberList}
|
||||
size="small"
|
||||
loading={this.state.loadingState}
|
||||
/>
|
||||
</div>
|
||||
</ModalCard>
|
||||
<Modal
|
||||
title="角色分配修改"
|
||||
visible={this.state.roleChangeForm.show}
|
||||
okText="确认修改"
|
||||
cancelText="取消修改"
|
||||
closable={!this.state.roleChangeForm.updateLoading}
|
||||
keyboard={!this.state.roleChangeForm.updateLoading}
|
||||
maskClosable={!this.state.roleChangeForm.updateLoading}
|
||||
confirmLoading={this.state.roleChangeForm.updateLoading}
|
||||
// onOk={() => {
|
||||
// this.setState({
|
||||
// roleChangeForm: Object.assign(this.state.roleChangeForm, {updateLoading: true})
|
||||
// });
|
||||
// request({
|
||||
// url: baseURL + "/review/proj/assign",
|
||||
// // url:"http://49.232.73.36:8081/review/proj/assign",
|
||||
// method: "PATCH",
|
||||
// data: {
|
||||
// assignment_id: this.state.roleChangeForm.assignment_id,
|
||||
// new_role: this.state.roleChangeForm.new_role,
|
||||
// }
|
||||
// }).then(res => {
|
||||
// console.log(res);
|
||||
// this.setState({
|
||||
// roleChangeForm: Object.assign(this.state.roleChangeForm, {updateLoading: false, show: false})
|
||||
// });
|
||||
// this.getProjectMember();
|
||||
// message.success("修改成功!");
|
||||
// }).catch(err => {
|
||||
// message.error(err.message || "请求错误!");
|
||||
// this.setState({
|
||||
// roleChangeForm: Object.assign(this.state.roleChangeForm, {updateLoading: false})
|
||||
// });
|
||||
// });
|
||||
// }}
|
||||
onOk={() => { }}
|
||||
onCancel={() => {
|
||||
if (this.state.roleChangeForm.updateLoading) {
|
||||
message.error("修改中,操作不可中断!");
|
||||
} else {
|
||||
this.setState({
|
||||
roleChangeForm: Object.assign(this.state.roleChangeForm, {show: false}),
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label style={{lineHeight: ".6rem"}}>新的角色:</label>
|
||||
<Select value={this.state.roleChangeForm.new_role} style={{width: "100%"}} onChange={(e) => {
|
||||
this.setState({
|
||||
roleChangeForm: Object.assign(this.state.roleChangeForm, {new_role: e}),
|
||||
});
|
||||
}}>
|
||||
<Option value={1}>管理员</Option>
|
||||
<Option value={2}>专家</Option>
|
||||
<Option value={3}>学科助理</Option>
|
||||
<Option value={4}>教师</Option>
|
||||
<Option value={5}>外审人员</Option>
|
||||
</Select>
|
||||
</Modal>
|
||||
<Modal
|
||||
title="添加成员"
|
||||
visible={this.state.addMemberForm.show}
|
||||
okText="确认添加"
|
||||
cancelText="取消添加"
|
||||
closable={!this.state.addMemberForm.loadingState}
|
||||
keyboard={!this.state.addMemberForm.loadingState}
|
||||
maskClosable={!this.state.addMemberForm.loadingState}
|
||||
confirmLoading={this.state.addMemberForm.loadingState}
|
||||
onOk={() => {
|
||||
|
||||
}}
|
||||
onCancel={() => {
|
||||
if (this.state.addMemberForm.loadingState) {
|
||||
message.error("添加中,操作不可中断!");
|
||||
} else {
|
||||
this.setState({
|
||||
addMemberForm: Object.assign(this.state.addMemberForm, {show: false}),
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label style={{lineHeight: ".6rem"}}>查找用户:</label>
|
||||
<Search placeholder="请输入被添加用户账号" onSearch={() => {
|
||||
|
||||
}} enterButton />
|
||||
{
|
||||
this.state.addMemberForm.user_id === "" ? "" : (
|
||||
<>
|
||||
<label style={{lineHeight: ".6rem"}}>角色分配:</label>
|
||||
<Select value={this.state.addMemberForm.role} style={{width: "100%"}} onChange={(e) => {
|
||||
this.setState({
|
||||
addMemberForm: Object.assign(this.state.addMemberForm, {role: e}),
|
||||
});
|
||||
}}>
|
||||
<Option value={1}>管理员</Option>
|
||||
<Option value={2}>专家</Option>
|
||||
<Option value={3}>学科助理</Option>
|
||||
<Option value={4}>教师</Option>
|
||||
<Option value={5}>外审人员</Option>
|
||||
</Select>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Modal>
|
||||
<Modal
|
||||
title="发送邮件"
|
||||
visible={this.state.emailForm.show}
|
||||
okText="确认发送"
|
||||
cancelText="取消发送"
|
||||
closable={!this.state.emailForm.loadingState}
|
||||
keyboard={!this.state.emailForm.loadingState}
|
||||
maskClosable={!this.state.emailForm.loadingState}
|
||||
confirmLoading={this.state.emailForm.loadingState}
|
||||
// onOk={() => {
|
||||
// this.emailFormRef.current.validateFields().then(formData => {
|
||||
// let data = {
|
||||
// body: {
|
||||
// message: formData.message,
|
||||
// send_time: this.state.emailForm.send_time,
|
||||
// sender: this.state.emailForm.sender
|
||||
// },
|
||||
// destination: this.state.emailForm.destination,
|
||||
// subject: formData.subject
|
||||
// };
|
||||
// this.setState({
|
||||
// emailForm: Object.assign(this.state.emailForm, {loadingState: true})
|
||||
// });
|
||||
// request({
|
||||
// url: baseURL + "/review/noticer/email",
|
||||
// // url:"http://49.232.73.36:8081/review/noticer/email",
|
||||
// method: "POST",
|
||||
// data
|
||||
// }).then(res => {
|
||||
// this.setState({
|
||||
// emailForm: Object.assign(this.state.emailForm, {loadingState: false, show: false})
|
||||
// });
|
||||
// this.emailFormRef.current.resetFields();
|
||||
// message.success("发送成功");
|
||||
// }).catch(err => {
|
||||
// this.setState({
|
||||
// emailForm: Object.assign(this.state.emailForm, {loadingState: false})
|
||||
// });
|
||||
// message.error(err.message || "请求错误");
|
||||
// });
|
||||
// }).catch(err => {
|
||||
// message.warning("请正确填写邮件内容");
|
||||
// });
|
||||
// }}
|
||||
|
||||
onOk={() => { }}
|
||||
onCancel={() => {
|
||||
if (this.state.emailForm.loadingState) {
|
||||
message.error("发送中,操作不可中断!");
|
||||
} else {
|
||||
this.emailFormRef.current.resetFields();
|
||||
this.setState({
|
||||
emailForm: Object.assign(this.state.emailForm, {show: false}),
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Form
|
||||
name="emailForm"
|
||||
labelCol={{span: 4}}
|
||||
wrapperCol={{span: 20}}
|
||||
initialValues={this.state.emailForm}
|
||||
autoComplete="off"
|
||||
ref={this.emailFormRef}
|
||||
>
|
||||
<Form.Item
|
||||
label="邮件主题"
|
||||
name="subject"
|
||||
rules={[{required: true, message: "请输入邮件主题"}]}
|
||||
>
|
||||
<Input placeholder="请输入邮件主题" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="邮件内容"
|
||||
name="message"
|
||||
rules={[{required: true, message: "请输入邮件内容"}]}
|
||||
>
|
||||
<TextArea placeholder="请输入邮件内容" autoSize={{minRows: 2, maxRows: 6}} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(index);
|
|
@ -0,0 +1,10 @@
|
|||
[data-component=build-team-page]{
|
||||
width: 100%;
|
||||
min-height: 6rem;
|
||||
background-color: white;
|
||||
.member-list{
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0px .2rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
import React, {Component} from "react";
|
||||
import {Button, Calendar, Col, Row, Select} from "antd";
|
||||
import "./CalendarButton.less";
|
||||
|
||||
/**
|
||||
* @description: 参数
|
||||
* @icon 按钮icon
|
||||
* @label 按钮名称
|
||||
*/
|
||||
|
||||
export default class index extends Component {
|
||||
|
||||
state = {
|
||||
calendarVisible: false,
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="calendar-button-box" data-component="calendar-button-box">
|
||||
<Button size="small" icon={this.props.icon} onClick={() => {
|
||||
this.setState({
|
||||
calendarVisible: true,
|
||||
});
|
||||
}}>{this.props.label}</Button>
|
||||
<div className="calendar-box" style={{maxHeight: this.state.calendarVisible ? "5rem" : 0}}>
|
||||
<Calendar
|
||||
fullscreen={false}
|
||||
headerRender={({value, type, onChange, onTypeChange}) => {
|
||||
const start = 0;
|
||||
const end = 12;
|
||||
const monthOptions = [];
|
||||
|
||||
const current = value.clone();
|
||||
const localeData = value.localeData();
|
||||
const months = [];
|
||||
for (let i = 0; i < 12; i++) {
|
||||
current.month(i);
|
||||
months.push(localeData.monthsShort(current));
|
||||
}
|
||||
|
||||
for (let index = start; index < end; index++) {
|
||||
monthOptions.push(
|
||||
<Select.Option className="month-item" key={`${index}`}>
|
||||
{months[index]}
|
||||
</Select.Option>
|
||||
);
|
||||
}
|
||||
const month = value.month();
|
||||
|
||||
const year = value.year();
|
||||
const options = [];
|
||||
for (let i = year - 10; i < year + 10; i += 1) {
|
||||
options.push(
|
||||
<Select.Option key={i} value={i} className="year-item">
|
||||
{i}
|
||||
</Select.Option>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div style={{padding: 8}}>
|
||||
<Row gutter={8} justify="end">
|
||||
<Col>
|
||||
<Select
|
||||
size="small"
|
||||
dropdownMatchSelectWidth={false}
|
||||
className="my-year-select"
|
||||
onChange={newYear => {
|
||||
const now = value.clone().year(newYear);
|
||||
onChange(now);
|
||||
}}
|
||||
value={String(year)}
|
||||
>
|
||||
{options}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col>
|
||||
<Select
|
||||
size="small"
|
||||
dropdownMatchSelectWidth={false}
|
||||
value={String(month)}
|
||||
onChange={selectedMonth => {
|
||||
const newValue = value.clone();
|
||||
newValue.month(parseInt(selectedMonth, 10));
|
||||
onChange(newValue);
|
||||
}}
|
||||
>
|
||||
{monthOptions}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
onSelect={(_date) => {
|
||||
let date = new Date(_date._d);
|
||||
this.setState({
|
||||
calendarVisible: false,
|
||||
});
|
||||
this.props.onDateChange(`${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
[data-component=calendar-button-box]{
|
||||
position: relative;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
> .calendar-box{
|
||||
width: auto;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: all .2s;
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
|
||||
top: .34rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 600;
|
||||
.ant-picker-calendar-date-value,th{
|
||||
font-size: .14rem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
import React, {Component} from "react";
|
||||
import {Input, Tag, Tooltip} from "antd";
|
||||
import {PlusOutlined} from "@ant-design/icons";
|
||||
import "./ChangeTags.less";
|
||||
|
||||
export default class index extends Component {
|
||||
state = {
|
||||
tags: [],
|
||||
inputVisible: false,
|
||||
inputValue: "",
|
||||
editInputIndex: -1,
|
||||
editInputValue: "",
|
||||
};
|
||||
|
||||
handleClose = (removedTag) => {
|
||||
const tags = this.state.tags.filter((tag) => tag !== removedTag);
|
||||
this.props.onChange(tags);
|
||||
this.setState({tags});
|
||||
};
|
||||
|
||||
showInput = () => {
|
||||
this.setState({inputVisible: true}, () => this.input.focus());
|
||||
};
|
||||
|
||||
handleInputChange = (e) => {
|
||||
this.setState({inputValue: e.target.value});
|
||||
};
|
||||
|
||||
handleInputConfirm = () => {
|
||||
const {inputValue} = this.state;
|
||||
let {tags} = this.state;
|
||||
if (inputValue && tags.indexOf(inputValue) === -1) {
|
||||
tags = [...tags, inputValue];
|
||||
}
|
||||
this.props.onChange(tags);
|
||||
this.setState({
|
||||
tags,
|
||||
inputVisible: false,
|
||||
inputValue: "",
|
||||
});
|
||||
};
|
||||
|
||||
handleEditInputChange = (e) => {
|
||||
this.setState({editInputValue: e.target.value});
|
||||
};
|
||||
|
||||
handleEditInputConfirm = () => {
|
||||
this.setState(({tags, editInputIndex, editInputValue}) => {
|
||||
const newTags = [...tags];
|
||||
newTags[editInputIndex] = editInputValue;
|
||||
|
||||
return {
|
||||
tags: newTags,
|
||||
editInputIndex: -1,
|
||||
editInputValue: "",
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
saveInputRef = (input) => {
|
||||
this.input = input;
|
||||
};
|
||||
|
||||
saveEditInputRef = (input) => {
|
||||
this.editInput = input;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {tags, inputVisible, inputValue, editInputIndex, editInputValue} =
|
||||
this.state;
|
||||
return (
|
||||
<>
|
||||
{tags.map((tag, index) => {
|
||||
if (editInputIndex === index) {
|
||||
return (
|
||||
<Input
|
||||
ref={this.saveEditInputRef}
|
||||
key={tag}
|
||||
size="small"
|
||||
className="tag-input"
|
||||
value={editInputValue}
|
||||
onChange={this.handleEditInputChange}
|
||||
onBlur={this.handleEditInputConfirm}
|
||||
onPressEnter={this.handleEditInputConfirm}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const isLongTag = tag.length > 20;
|
||||
|
||||
const tagElem = (
|
||||
<Tag
|
||||
className="edit-tag"
|
||||
key={tag}
|
||||
closable={true}
|
||||
onClose={() => this.handleClose(tag)}
|
||||
>
|
||||
<span
|
||||
onDoubleClick={(e) => {
|
||||
if (index !== 0) {
|
||||
this.setState(
|
||||
{editInputIndex: index, editInputValue: tag},
|
||||
() => {
|
||||
this.editInput.focus();
|
||||
}
|
||||
);
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
||||
</span>
|
||||
</Tag>
|
||||
);
|
||||
return isLongTag ? (
|
||||
<Tooltip title={tag} key={tag}>
|
||||
{tagElem}
|
||||
</Tooltip>
|
||||
) : (
|
||||
tagElem
|
||||
);
|
||||
})}
|
||||
{inputVisible && (
|
||||
<Input
|
||||
ref={this.saveInputRef}
|
||||
type="text"
|
||||
size="small"
|
||||
className="tag-input"
|
||||
value={inputValue}
|
||||
onChange={this.handleInputChange}
|
||||
onBlur={this.handleInputConfirm}
|
||||
onPressEnter={this.handleInputConfirm}
|
||||
/>
|
||||
)}
|
||||
{!inputVisible && (
|
||||
<Tag className="site-tag-plus" onClick={this.showInput}>
|
||||
<PlusOutlined /> 添加
|
||||
</Tag>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
.site-tag-plus {
|
||||
background: #fff;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.edit-tag {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.tag-input {
|
||||
width: 78px;
|
||||
margin-right: 8px;
|
||||
vertical-align: top;
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
import React, {Component} from "react";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import {Button, Col, Row, Select, Slider, Spin, Tag, message} from "antd";
|
||||
import BraftEditor from "braft-editor";
|
||||
import "braft-editor/dist/index.css";
|
||||
import "./ChoiceQuestionEditer.less";
|
||||
import * as PropositionBackend from "./backend/PropositionBackend";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
class ChoiceQuestionEditer extends Component {
|
||||
state = {
|
||||
editorState: BraftEditor.createEditorState(null),
|
||||
loadingState: false,
|
||||
questionParams: {
|
||||
subject: "",
|
||||
difficulty: 1,
|
||||
answer: "",
|
||||
},
|
||||
}
|
||||
upLoadQuestion = (uid) => {
|
||||
this.setState({
|
||||
loadingState: true,
|
||||
});
|
||||
let data = {
|
||||
advanced_props: {
|
||||
ctt_diff_1: this.state.questionParams.difficulty,
|
||||
ctt_diff_2: this.state.questionParams.difficulty,
|
||||
ctt_level: this.state.questionParams.difficulty,
|
||||
irt_level: this.state.questionParams.difficulty,
|
||||
},
|
||||
apply_record: {
|
||||
grade_fits: this.props.grade_range.join(","),
|
||||
participant_count: 0,
|
||||
test_count: 0,
|
||||
test_region: [],
|
||||
test_year: `${new Date().getFullYear()}`,
|
||||
},
|
||||
author: uid,
|
||||
basic_props: {
|
||||
ability_dimension: this.props.ability.join(","),
|
||||
description: "暂无",
|
||||
details: this.state.editorState.toHTML(),
|
||||
details_dimension: this.props.content.join(","),
|
||||
encode: "",
|
||||
keywords: [],
|
||||
sub_ability_dimension: "",
|
||||
sub_details_dimension: "",
|
||||
subject: this.state.questionParams.subject,
|
||||
subject_requirements: "",
|
||||
},
|
||||
extra_props: {
|
||||
is_question_group: false,
|
||||
is_scene: true,
|
||||
material_length: 0,
|
||||
reading_material_topic: "",
|
||||
},
|
||||
info: {
|
||||
answer: this.state.questionParams.answer,
|
||||
body: this.state.editorState.toHTML(),
|
||||
solution: "无",
|
||||
title: "无",
|
||||
type: "选择题",
|
||||
},
|
||||
source_project: this.props.projectId,
|
||||
spec_props: {
|
||||
article_type: "无",
|
||||
length: "无",
|
||||
topic: "无",
|
||||
},
|
||||
};
|
||||
PropositionBackend.CreateNewQuestion(data).then(res => {
|
||||
this.setState({
|
||||
loadingState: false,
|
||||
});
|
||||
}).then(res => {
|
||||
this.props.history.goBack();
|
||||
message.success("上传成功");
|
||||
}).catch(err => {
|
||||
this.setState({
|
||||
loadingState: false,
|
||||
});
|
||||
message.error(err.message || "请求错误");
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
questionParams: Object.assign(this.state.questionParams, {subject: this.props.defaultSubjectValue}),
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="choice-question-editer" data-component="choice-question-editer" id="choice-question-edit-box">
|
||||
<Spin spinning={this.state.loadingState} tip="上传试题中">
|
||||
<Row>
|
||||
<BraftEditor
|
||||
value={this.state.editorState}
|
||||
onChange={(editorState) => {
|
||||
this.setState({editorState});
|
||||
}}
|
||||
onSave={() => {
|
||||
console.log("保存题目");
|
||||
}}
|
||||
/>
|
||||
</Row>
|
||||
<Row className="question-params">
|
||||
<div className="title">
|
||||
<span>参数编辑</span>
|
||||
</div>
|
||||
<Row className="param-item" style={{marginTop: ".17rem"}}>
|
||||
<Col span="4" className="label">
|
||||
<span>学科</span>
|
||||
</Col>
|
||||
<Col span="20" className="value">
|
||||
<Select
|
||||
placeholder="选择学科"
|
||||
value={this.state.questionParams.subject}
|
||||
defaultValue={this.props.defaultSubjectValue}
|
||||
onSelect={(e) => {
|
||||
let questionParams = Object.assign(this.state.questionParams, {subject: e});
|
||||
this.setState({
|
||||
questionParams,
|
||||
});
|
||||
}}
|
||||
size="small"
|
||||
>
|
||||
{
|
||||
this.props.subjectList.map((item, index) => (
|
||||
<Option value={item} key={index + Math.random(100)}>{item}</Option>
|
||||
))
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="param-item" style={{marginTop: ".17rem"}}>
|
||||
<Col span="4" className="label">
|
||||
<span>难度</span>
|
||||
</Col>
|
||||
<Col span="20" className="value">
|
||||
<Slider marks={{1: 1, 2: 2, 3: 3, 4: 4, 5: 5}} step={null} defaultValue={1} max={5} min={1} onChange={(e) => {
|
||||
let questionParams = Object.assign(this.state.questionParams, {difficulty: e});
|
||||
this.setState({
|
||||
questionParams,
|
||||
});
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="param-item" style={{marginTop: ".3rem"}}>
|
||||
<Col span="4" className="label">
|
||||
<span>能力纬度</span>
|
||||
</Col>
|
||||
<Col span="20" className="value">
|
||||
<div className="tag-list">
|
||||
{
|
||||
this.props.ability.map(item => (
|
||||
<Tag key={item.id}>{item}</Tag>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="param-item" style={{marginTop: ".17rem"}}>
|
||||
<Col span="4" className="label">
|
||||
<span>内容纬度</span>
|
||||
</Col>
|
||||
<Col span="20" className="value">
|
||||
<div className="tag-list">
|
||||
{
|
||||
this.props.content.map(item => (
|
||||
<Tag key={item.id}>{item}</Tag>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Row>
|
||||
<div className="question-complete-box">
|
||||
<Button type="primary" block onClick={() => {
|
||||
this.upLoadQuestion(this.props.author);
|
||||
}}>完成编辑</Button>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(ChoiceQuestionEditer);
|
|
@ -0,0 +1,48 @@
|
|||
[data-component=choice-question-editer]{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
.question-params{
|
||||
> .title{
|
||||
width: 100%;
|
||||
height: .41rem;
|
||||
background-color: #EEEEEE;
|
||||
line-height: .41rem;
|
||||
box-sizing: border-box;
|
||||
padding-left: .1rem;
|
||||
> span{
|
||||
font-size: .14rem;
|
||||
color: #000000;
|
||||
|
||||
}
|
||||
}
|
||||
> .param-item{
|
||||
width: 100%;
|
||||
height: .32rem;
|
||||
.label{
|
||||
box-sizing: border-box;
|
||||
padding-left: .1rem;
|
||||
line-height: .32rem;
|
||||
> span{
|
||||
font-size: .14rem;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
.value{
|
||||
> .ant-select{
|
||||
width: 100%;
|
||||
}
|
||||
> .tag-list{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-complete-box{
|
||||
width: 100%;
|
||||
margin-top: .77rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
import React, {Component} from "react";
|
||||
import {Col, Row, Statistic} from "antd";
|
||||
import ModulaCard from "./ModulaCard";
|
||||
import "./CompletionStatus.less";
|
||||
|
||||
export default class index extends Component {
|
||||
|
||||
state = {
|
||||
status: {},
|
||||
loadingState: false,
|
||||
}
|
||||
|
||||
getStatusList = () => {
|
||||
this.setState({
|
||||
loadingState: true,
|
||||
});
|
||||
// request({
|
||||
// url:baseURL+`/review/proj/step/stat/${this.props.stepId}`,
|
||||
// // url:`http://49.232.73.36:8081/review/proj/step/stat/${this.props.stepId}`,
|
||||
// method:"GET"
|
||||
// }).then(res => {
|
||||
// this.setState({
|
||||
// status:res.data,
|
||||
// loadingState:false
|
||||
// });
|
||||
// }).catch(err => {
|
||||
// this.setState({
|
||||
// loadingState:false
|
||||
// });
|
||||
// });
|
||||
var res = {
|
||||
"operation_code": 1000,
|
||||
"message": "",
|
||||
"data": {
|
||||
"pass": 0,
|
||||
"pass_rate": 0,
|
||||
"return": 0,
|
||||
"to_audit": 0,
|
||||
"to_correct": 0,
|
||||
"to_upload": 0,
|
||||
"total": 0,
|
||||
},
|
||||
};
|
||||
this.setState({
|
||||
status: res.data,
|
||||
loadingState: false,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getStatusList();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ModulaCard title="完成情况">
|
||||
{
|
||||
this.state.loadingState ? (
|
||||
<></>
|
||||
) : (
|
||||
<div className="completion-status-box" data-component="completion-status-box">
|
||||
<div className="left-box">
|
||||
<div className="title">
|
||||
<span>{this.props.title}</span>
|
||||
</div>
|
||||
<div className="value-list">
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Statistic title="材料总计" value={this.state.status.total} />
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Statistic title="通过率" value={this.state.status.pass_rate} suffix="%" />
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
<div className="right-box">
|
||||
<Row gutter={16} style={{width: "4.2rem"}}>
|
||||
<Col span={4}>
|
||||
<Statistic title={<div className="statistic-item-title"><div className="circle" style={{backgroundColor: "#87D068"}}></div>通过</div>} value={this.state.status.pass} />
|
||||
</Col>
|
||||
<Col span={4}>
|
||||
<Statistic title={<div className="statistic-item-title"><div className="circle" style={{backgroundColor: "#FF5500"}}></div>驳回</div>} value={this.state.status.return} />
|
||||
</Col>
|
||||
<Col span={5}>
|
||||
<Statistic title={<div className="statistic-item-title"><div className="circle" style={{backgroundColor: "#FF5500"}}></div>未上传</div>} value={this.state.status.to_upload} />
|
||||
</Col>
|
||||
<Col span={5}>
|
||||
<Statistic title={<div className="statistic-item-title"><div className="circle" style={{backgroundColor: "#2DB7F5"}}></div>待审核</div>} value={this.state.status.to_audit} />
|
||||
</Col>
|
||||
<Col span={5}>
|
||||
<Statistic title={<div className="statistic-item-title"><div className="circle" style={{backgroundColor: "#2DB7F5"}}></div>再修改</div>} value={this.state.status.to_correct} />
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</ModulaCard>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
[data-component=completion-status-box]{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding-left: 0.47rem;
|
||||
> .left-box{
|
||||
> .title{
|
||||
height: .24rem;
|
||||
line-height: .24rem;
|
||||
margin-bottom: .08rem;
|
||||
> span{
|
||||
font-size: .14rem;
|
||||
color: #8C8C8C;
|
||||
}
|
||||
}
|
||||
> .value-list{
|
||||
.ant-statistic-title{
|
||||
font-size: .14rem;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.ant-statistic-content-value-int,.ant-statistic-content-suffix{
|
||||
font-size: .26rem;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
}
|
||||
> .right-box{
|
||||
.statistic-item-title{
|
||||
font-size: .14rem;
|
||||
color: #000000D9;
|
||||
line-height: .22rem;
|
||||
box-sizing: border-box;
|
||||
padding-left: .14rem;
|
||||
position: relative;
|
||||
> .circle{
|
||||
width: .06rem;
|
||||
height: .06rem;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.ant-statistic-content-value-int,.ant-statistic-content-suffix{
|
||||
font-size: .26rem;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,477 @@
|
|||
import React, {Component} from "react";
|
||||
import {Button, Col, Descriptions, Input, Modal, PageHeader, Pagination, Row, Select, Slider, Spin, Tag, message} from "antd";
|
||||
import UpLoadQuestionModal from "./UpLoadQuestionModal";
|
||||
import HistoryQuestion from "./HistoryQuestion";
|
||||
import BraftEditor from "braft-editor";
|
||||
import "braft-editor/dist/index.css";
|
||||
import "./CreatePaper.less";
|
||||
import * as ProjectBackend from "./backend/ProjectBackend";
|
||||
import * as PropositionBackend from "./backend/PropositionBackend";
|
||||
|
||||
const {Option} = Select;
|
||||
const {Search} = Input;
|
||||
|
||||
export default class CreatePaper extends Component {
|
||||
state = {
|
||||
initLoading: true,
|
||||
createTime: 0,
|
||||
projectInfo: {},
|
||||
upLoadQuestionModalParams: {
|
||||
show: false,
|
||||
type: "update-paper",
|
||||
},
|
||||
questionList: [{
|
||||
state: "edit", // 表示编辑中
|
||||
subject: "",
|
||||
difficulty: 1,
|
||||
ability: this.props.match.params.ability,
|
||||
content: this.props.match.params.content,
|
||||
body: BraftEditor.createEditorState(null),
|
||||
}],
|
||||
paperViewVisible: false,
|
||||
loadingState: false,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let t = new Date();
|
||||
this.setState({
|
||||
createTime: `${t.getFullYear()}-${t.getMonth().toString().padStart(2, "0")}-${t.getDate().toString().padStart(2, "0")} ${t.getHours().toString().padStart(2, "0")}:${t.getMinutes().toString().padStart(2, "0")}:${t.getSeconds().toString().padStart(2, "0")}`,
|
||||
});
|
||||
this.getProjectInfo();
|
||||
}
|
||||
|
||||
// upLoadQuestion = (info) => {
|
||||
// this.setState({
|
||||
// loadingState: true
|
||||
// });
|
||||
// return request({
|
||||
// url: baseURL1 + "/qbank/question",
|
||||
// // url:"http://49.232.73.36:8082/qbank/question",
|
||||
// method: "POST",
|
||||
// data: {
|
||||
// advanced_props: {
|
||||
// ctt_diff_1: info.difficulty,
|
||||
// ctt_diff_2: info.difficulty,
|
||||
// ctt_level: info.difficulty,
|
||||
// irt_level: info.difficulty
|
||||
// },
|
||||
// apply_record: {
|
||||
// grade_fits: this.state.projectInfo.basic_info.grade_range.join(","),
|
||||
// participant_count: 0,
|
||||
// test_count: 0,
|
||||
// test_region: [],
|
||||
// test_year: `${new Date().getFullYear()}`,
|
||||
// },
|
||||
// author: store.getState().userInfo.Id,
|
||||
// basic_props: {
|
||||
// ability_dimension: info.ability,
|
||||
// description: "暂无",
|
||||
// details: info.body.toHTML(),
|
||||
// details_dimension: info.content,
|
||||
// encode: "",
|
||||
// keywords: [],
|
||||
// sub_ability_dimension: "",
|
||||
// sub_details_dimension: "",
|
||||
// subject: info.subject,
|
||||
// subject_requirements: ""
|
||||
// },
|
||||
// extra_props: {
|
||||
// is_question_group: false,
|
||||
// is_scene: true,
|
||||
// material_length: 0,
|
||||
// reading_material_topic: ""
|
||||
// },
|
||||
// info: {
|
||||
// answer: "",
|
||||
// body: info.body.toHTML(),
|
||||
// solution: "无",
|
||||
// title: "无",
|
||||
// type: "选择题"
|
||||
// },
|
||||
// source_project: this.props.match.params.project,
|
||||
// spec_props: {
|
||||
// article_type: "无",
|
||||
// length: "无",
|
||||
// topic: "无"
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
upLoadQuestion = (info) => {
|
||||
this.setState({
|
||||
loadingState: true,
|
||||
});
|
||||
let data = {
|
||||
advanced_props: {
|
||||
ctt_diff_1: info.difficulty,
|
||||
ctt_diff_2: info.difficulty,
|
||||
ctt_level: info.difficulty,
|
||||
irt_level: info.difficulty,
|
||||
},
|
||||
apply_record: {
|
||||
grade_fits: this.state.projectInfo.basic_info.grade_range.join(","),
|
||||
participant_count: 0,
|
||||
test_count: 0,
|
||||
test_region: [],
|
||||
test_year: `${new Date().getFullYear()}`,
|
||||
},
|
||||
author: this.props.match.params.uid,
|
||||
basic_props: {
|
||||
ability_dimension: info.ability,
|
||||
description: "暂无",
|
||||
details: info.body.toHTML(),
|
||||
details_dimension: info.content,
|
||||
encode: "",
|
||||
keywords: [],
|
||||
sub_ability_dimension: "",
|
||||
sub_details_dimension: "",
|
||||
subject: info.subject,
|
||||
subject_requirements: "",
|
||||
},
|
||||
extra_props: {
|
||||
is_question_group: false,
|
||||
is_scene: true,
|
||||
material_length: 0,
|
||||
reading_material_topic: "",
|
||||
},
|
||||
info: {
|
||||
answer: "",
|
||||
body: info.body.toHTML(),
|
||||
solution: "无",
|
||||
title: "无",
|
||||
type: "选择题",
|
||||
},
|
||||
source_project: this.props.match.params.project,
|
||||
spec_props: {
|
||||
article_type: "无",
|
||||
length: "无",
|
||||
topic: "无",
|
||||
},
|
||||
};
|
||||
return PropositionBackend.CreateNewQuestion(data);
|
||||
}
|
||||
|
||||
getProjectInfo = () => {
|
||||
let newParms = this.props.match.params;
|
||||
ProjectBackend.GetDetailedInfo(newParms.uid + "/" + newParms.project).then(res => {
|
||||
this.setState({
|
||||
projectInfo: res.data.basic_info,
|
||||
initLoading: false,
|
||||
});
|
||||
}).catch(err => {
|
||||
this.setState({
|
||||
initLoading: false,
|
||||
});
|
||||
this.props.history.goBack();
|
||||
message.error("编辑器加载失败!");
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="create-paper-page" data-component="create-paper-page">
|
||||
<PageHeader
|
||||
ghost={false}
|
||||
onBack={() => this.props.history.goBack()}
|
||||
title="命题组卷"
|
||||
subTitle="上传试题"
|
||||
extra={[
|
||||
<Button key="1" onClick={() => {
|
||||
this.setState({
|
||||
upLoadQuestionModalParams: {
|
||||
show: true,
|
||||
type: "update-paper",
|
||||
},
|
||||
});
|
||||
}}>编辑内容</Button>,
|
||||
]}
|
||||
>
|
||||
{
|
||||
this.state.initLoading ? (
|
||||
<Spin spinning={true} tip="初始化中"></Spin>
|
||||
) : (
|
||||
<Descriptions size="small" column={3}>
|
||||
<Descriptions.Item label="创建时间" key="createAt">{this.state.createTime}</Descriptions.Item>
|
||||
<Descriptions.Item label="项目" key="peojects">{this.state.projectInfo.basic_info.name}</Descriptions.Item>
|
||||
<Descriptions.Item label="学科" key="subjects">{
|
||||
this.state.projectInfo.basic_info.subjects.map((item, index) => (
|
||||
<span key={index}>{item}{index === this.state.projectInfo.basic_info.subjects.length - 1 ? "" : "、"}</span>
|
||||
))
|
||||
}</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label="内容纬度" key="content">{
|
||||
this.props.match.params.content.split(",").map((item, index) => (
|
||||
<span key={index}>{item}{index === this.props.match.params.content.split(",").length - 1 ? "" : "、"}</span>
|
||||
))
|
||||
}</Descriptions.Item>
|
||||
<Descriptions.Item label="能力纬度" key="ability">
|
||||
{
|
||||
this.props.match.params.ability.split(",").map((item, index) => (
|
||||
<span key={index}>{item}{index === this.props.match.params.ability.split(",").length - 1 ? "" : "、"}</span>
|
||||
))
|
||||
}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
)
|
||||
}
|
||||
</PageHeader>
|
||||
<Spin spinning={this.state.loadingState} tip="上传中">
|
||||
<Row className="container">
|
||||
<Col span="8" className="left-box">
|
||||
<div className="title-box">
|
||||
<div className="title-value">
|
||||
<div className="ver-line"></div>
|
||||
<div className="value">
|
||||
<span>相关题库</span>
|
||||
</div>
|
||||
</div>
|
||||
<Search placeholder="input search text" style={{width: "2.64rem"}} size="middle" />
|
||||
</div>
|
||||
<HistoryQuestion />
|
||||
<HistoryQuestion />
|
||||
<HistoryQuestion />
|
||||
<Pagination defaultCurrent={1} total={50} className="page-spare" />
|
||||
</Col>
|
||||
<Col span="16" className="right-box">
|
||||
{
|
||||
this.state.questionList.map((item, index) => (
|
||||
<Row className="question-item" key={index + Math.random(100)} gutter={[8, 8]}>
|
||||
<Col className="info-box" span="18">
|
||||
<Row className="main-box">
|
||||
{
|
||||
item.state === "edit" ? (
|
||||
<BraftEditor
|
||||
value={item.body}
|
||||
onChange={(editorState) => {
|
||||
let questionList = [...this.state.questionList];
|
||||
questionList[index].body = editorState;
|
||||
this.setState({questionList});
|
||||
}}
|
||||
onSave={() => {
|
||||
console.log("保存题目");
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="view-box" dangerouslySetInnerHTML={{__html: item.body.toHTML()}}>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Row>
|
||||
<Row className="btn-line">
|
||||
<Button type="primary" size="small" style={{width: "1rem", marginRight: ".2rem"}} onClick={() => {
|
||||
let questionList = [...this.state.questionList];
|
||||
questionList[index].state = item.state === "edit" ? "complete" : "edit";
|
||||
this.setState({
|
||||
questionList,
|
||||
});
|
||||
}}>
|
||||
{
|
||||
item.state === "edit" ? "保存" : "编辑"
|
||||
}
|
||||
</Button>
|
||||
<Button type="primary" danger size="small" style={{width: "1rem"}} onClick={() => {
|
||||
let questionList = [...this.state.questionList];
|
||||
questionList.splice(index, 1);
|
||||
this.setState({
|
||||
questionList,
|
||||
});
|
||||
}}>
|
||||
删除
|
||||
</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col className="params-box" span="6">
|
||||
<div className="title">
|
||||
<span>参数编辑</span>
|
||||
</div>
|
||||
<Row className="params-item">
|
||||
<Col className="label" span="8">
|
||||
<span>学科</span>
|
||||
</Col>
|
||||
<Col className="value" span="16">
|
||||
<Select
|
||||
placeholder="选择学科"
|
||||
value={item.subject}
|
||||
defaultValue={this.props.match.params.subject}
|
||||
onSelect={(e) => {
|
||||
let questionList = [...this.state.questionList];
|
||||
questionList[index].subject = e;
|
||||
this.setState({
|
||||
questionList,
|
||||
});
|
||||
}}
|
||||
size="small"
|
||||
>
|
||||
{
|
||||
this.state.initLoading ? "" : this.state.projectInfo.basic_info.subjects.map((item, index) => (
|
||||
<Option value={item} key={index + Math.random(100)}>{item}</Option>
|
||||
))
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="params-item" style={{marginTop: ".17rem"}}>
|
||||
<Col span="8" className="label">
|
||||
<span>难度</span>
|
||||
</Col>
|
||||
<Col span="16" className="value">
|
||||
<Slider marks={{1: 1, 2: 2, 3: 3, 4: 4, 5: 5}} step={null} value={item.difficulty} defaultValue={1} max={5} min={1} onChange={(e) => {
|
||||
let questionList = [...this.state.questionList];
|
||||
questionList[index].difficulty = e;
|
||||
this.setState({
|
||||
questionList,
|
||||
});
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="params-item" style={{marginTop: ".17rem"}}>
|
||||
<Col span="8" className="label">
|
||||
<span>能力纬度</span>
|
||||
</Col>
|
||||
<Col span="16" className="value">
|
||||
<div className="tag-list">
|
||||
{
|
||||
item.ability.split(",").map(item => (
|
||||
<Tag key={item.Id}>{item}</Tag>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="params-item" style={{marginTop: ".1rem"}}>
|
||||
<Col span="8" className="label">
|
||||
<span>内容纬度</span>
|
||||
</Col>
|
||||
<Col span="16" className="value">
|
||||
<div className="tag-list">
|
||||
{
|
||||
item.content.split(",").map(item => (
|
||||
<Tag Key={item.Id}>{item}</Tag>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Row gutter={[8, 8]} className="oper-btn-line">
|
||||
<Col span="18" className="left">
|
||||
{
|
||||
index === this.state.questionList.length - 1 ? (
|
||||
<Button type="primary" size="large" onClick={() => {
|
||||
let questionList = [...this.state.questionList];
|
||||
questionList.push({
|
||||
state: "edit", // 表示编辑中
|
||||
subject: "",
|
||||
difficulty: 1,
|
||||
ability: this.props.match.params.ability,
|
||||
content: this.props.match.params.content,
|
||||
body: BraftEditor.createEditorState(null),
|
||||
});
|
||||
this.setState({
|
||||
questionList,
|
||||
});
|
||||
}}>
|
||||
添加一题
|
||||
</Button>
|
||||
) : ""
|
||||
}
|
||||
</Col>
|
||||
<Col span="6" className="right">
|
||||
<Button size="large" style={{backgroundColor: "#EEEEEE"}} onClick={() => {
|
||||
this.setState({
|
||||
paperViewVisible: true,
|
||||
});
|
||||
}}>
|
||||
预览试卷
|
||||
</Button>
|
||||
<Button type="primary" size="large" style={{width: "1.2rem"}} onClick={async() => {
|
||||
let questionIdList = [];
|
||||
for (let i = 0; i < this.state.questionList.length; i++) {
|
||||
await this.upLoadQuestion(this.state.questionList[i]).then((res) => {
|
||||
questionIdList.push({
|
||||
comment: "暂无",
|
||||
question_id: res.data,
|
||||
score: 0,
|
||||
});
|
||||
}).catch(err => {
|
||||
this.setState({
|
||||
loadingState: false,
|
||||
});
|
||||
message.error(err.message || "试题上传失败,请重试");
|
||||
});
|
||||
}
|
||||
let data = {
|
||||
author: this.props.match.params.uid,
|
||||
info: [{
|
||||
description: "暂无",
|
||||
question_list: questionIdList,
|
||||
score: 0,
|
||||
title: "无",
|
||||
}],
|
||||
props: {
|
||||
difficulty: "1",
|
||||
grade_range: this.state.projectInfo.basic_info.grade_range,
|
||||
subjects: this.state.projectInfo.basic_info.subjects,
|
||||
time_limit: "0",
|
||||
},
|
||||
source_project: this.props.match.params.project,
|
||||
title: "无",
|
||||
};
|
||||
PropositionBackend.CreateNewTestpaper(data).then(res => {
|
||||
this.setState({
|
||||
loadingState: false,
|
||||
});
|
||||
this.props.history.goBack();
|
||||
message.success("试题上传成功");
|
||||
}).catch(err => {
|
||||
this.setState({
|
||||
loadingState: false,
|
||||
});
|
||||
message.error(err.message || "试题上传失败,请重试");
|
||||
this.props.history.goBack();
|
||||
});
|
||||
}}>
|
||||
保存
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Row>
|
||||
))
|
||||
}
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
</Spin>
|
||||
<UpLoadQuestionModal
|
||||
{...this.state.upLoadQuestionModalParams}
|
||||
onClose={() => {
|
||||
this.setState({
|
||||
upLoadQuestionModalParams: {
|
||||
show: false,
|
||||
type: "update-paper",
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Modal width={1200} title="试卷预览" visible={this.state.paperViewVisible} onOk={() => {
|
||||
this.setState({
|
||||
paperViewVisible: false,
|
||||
});
|
||||
}} onCancel={() => {
|
||||
this.setState({
|
||||
paperViewVisible: false,
|
||||
});
|
||||
}}>
|
||||
<div className="view-box">
|
||||
{
|
||||
this.state.questionList.map(item => (
|
||||
<div className="question-view-item" dangerouslySetInnerHTML={{__html: item.body.toHTML()}} key={item.Id} ></div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
[data-component=create-paper-page]{
|
||||
width: 100%;
|
||||
.container{
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
> .left-box{
|
||||
background-color: white;
|
||||
box-sizing: border-box;
|
||||
padding: .22rem .1rem .4rem .22rem;
|
||||
> .title-box{
|
||||
width: 100%;
|
||||
height: .32rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding-left: .1rem;
|
||||
padding-right: .24rem;
|
||||
margin-bottom: .2rem;
|
||||
> .title-value{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> .ver-line{
|
||||
height: .18rem;
|
||||
width: .06rem;
|
||||
background-color: #1890FF;
|
||||
margin-right: .06rem;
|
||||
}
|
||||
> .value{
|
||||
font-size: .16rem;
|
||||
color: #000000D9;
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-spare{
|
||||
margin: .2rem;
|
||||
.ant-pagination-item-link,.ant-pagination-item{
|
||||
background: #91D5FF;
|
||||
border: 1px solid #FFFEFE;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
.anticon{
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
> .right-box{
|
||||
background-color: #EEEEEE;
|
||||
box-sizing: border-box;
|
||||
padding: .16rem;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
> .question-item{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
box-sizing: border-box;
|
||||
padding: .62rem .73rem 0px .29rem;
|
||||
overflow-y: scroll;
|
||||
margin-top: .2rem;
|
||||
> .params-box{
|
||||
> .title{
|
||||
width: 100%;
|
||||
height: .41rem;
|
||||
background-color: #EEEEEE;
|
||||
line-height: .41rem;
|
||||
box-sizing: border-box;
|
||||
padding-left: .1rem;
|
||||
> span{
|
||||
font-size: .14rem;
|
||||
color: #000000;
|
||||
|
||||
}
|
||||
}
|
||||
> .params-item{
|
||||
width: 100%;
|
||||
min-height: .32rem;
|
||||
margin-top: .1rem;
|
||||
> .label{
|
||||
box-sizing: border-box;
|
||||
padding-left: .1rem;
|
||||
line-height: .32rem;
|
||||
> span{
|
||||
font-size: .14rem;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
> .value{
|
||||
> .ant-select{
|
||||
width: 100%;
|
||||
}
|
||||
> .tag-list{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
> .oper-btn-line{
|
||||
height: 1rem;
|
||||
width: 100%;
|
||||
> .right{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
> .info-box{
|
||||
> .btn-line{
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,435 @@
|
|||
import React, {Component} from "react";
|
||||
import {Button, Modal, Pagination, Radio, Space, Table, Tag, Upload, message} from "antd";
|
||||
import ModulaCard from "./ModulaCard";
|
||||
import ModifyRecordModal from "./ModifyRecordModal";
|
||||
import {FileTextTwoTone, UploadOutlined} from "@ant-design/icons";
|
||||
import "./DataTable.less";
|
||||
|
||||
export default class index extends Component {
|
||||
|
||||
state = {
|
||||
data: [],
|
||||
loadingState: false,
|
||||
reviewResultsVisible: false,
|
||||
statusChangeLoading: false,
|
||||
modifyRecordVisible: false,
|
||||
selectedSubmitId: "",
|
||||
statusChangeParams: {
|
||||
value: 1,
|
||||
submitId: "",
|
||||
},
|
||||
}
|
||||
|
||||
modifyRecordRef = React.createRef()
|
||||
|
||||
colums = [[{
|
||||
title: "上传时间",
|
||||
key: "CreateAt",
|
||||
align: "center",
|
||||
width: 150,
|
||||
render: (text, record) => (
|
||||
<span>{this.dateFilter(record.CreateAt)}</span>
|
||||
),
|
||||
}, {
|
||||
title: "上传用户",
|
||||
dataIndex: "user",
|
||||
key: "user",
|
||||
align: "center",
|
||||
width: 120,
|
||||
}, {
|
||||
title: "评审材料",
|
||||
key: "contents",
|
||||
align: "center",
|
||||
width: 220,
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
{
|
||||
record.contents ? (
|
||||
<span style={{cursor: "pointer"}} onClick={this.downLoadFile.bind(this, record.contents[0].item_id)}>{record.contents[0].comment} <FileTextTwoTone /></span>
|
||||
) : "无"
|
||||
}
|
||||
</Space>
|
||||
),
|
||||
}, {
|
||||
title: "评审结果",
|
||||
key: "status",
|
||||
align: "center",
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
let levelList = [{
|
||||
mode: "等待审核",
|
||||
color: "default",
|
||||
}, {
|
||||
mode: "通过",
|
||||
color: "#87D068",
|
||||
}, {
|
||||
mode: "再修改",
|
||||
color: "#2DB7F5",
|
||||
}, {
|
||||
mode: "驳回",
|
||||
color: "#FF5500",
|
||||
}];
|
||||
return (
|
||||
<Space size="middle">
|
||||
<Tag color={levelList[record.status].color} onClick={() => {
|
||||
this.setState({
|
||||
reviewResultsVisible: true,
|
||||
statusChangeParams: {
|
||||
submitId: record.uuid,
|
||||
value: record.status,
|
||||
},
|
||||
});
|
||||
}} style={{cursor: "pointer"}}>{levelList[record.status].mode}</Tag>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: "反馈批注材料",
|
||||
dataIndex: "feedback-material",
|
||||
key: "feedback-material",
|
||||
align: "center",
|
||||
render: (text, record) => {
|
||||
if (!record.feedbackMaterial) {
|
||||
return (
|
||||
<Space size="middle">
|
||||
<Upload>
|
||||
<Button icon={<UploadOutlined />} size="small">上传批注</Button>
|
||||
</Upload>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Space size="middle">
|
||||
<span>{record.feedbackMaterial}</span><FileTextTwoTone />
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
}], [{
|
||||
title: "材料编号",
|
||||
dataIndex: "uuid",
|
||||
key: "id",
|
||||
align: "center",
|
||||
}, {
|
||||
title: "上传时间",
|
||||
key: "date",
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
<span>{this.dateFilter(record.CreateAt)}</span>{record.isDelay ? (<Tag color="error">延时提交</Tag>) : ""}
|
||||
</Space>
|
||||
),
|
||||
}, {
|
||||
title: "评审材料",
|
||||
key: "review-materials",
|
||||
width: 220,
|
||||
align: "center",
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
{
|
||||
record.contents ? (
|
||||
<span style={{cursor: "pointer"}} onClick={this.downLoadFile.bind(this, record.contents[0].item_id)}>{record.contents[0].comment} <FileTextTwoTone /></span>
|
||||
) : "无"
|
||||
}
|
||||
</Space>
|
||||
),
|
||||
}, {
|
||||
title: "评审结果",
|
||||
key: "result",
|
||||
align: "center",
|
||||
render: (text, record) => {
|
||||
let levelList = [{
|
||||
mode: "等待评审",
|
||||
color: "default",
|
||||
}, {
|
||||
mode: "通过",
|
||||
color: "#87D068",
|
||||
}, {
|
||||
mode: "再修改",
|
||||
color: "#2DB7F5",
|
||||
}, {
|
||||
mode: "驳回",
|
||||
color: "#FF5500",
|
||||
}];
|
||||
return (
|
||||
<Space size="middle">
|
||||
<Tag color={levelList[record.status].color} style={{cursor: "pointer"}}>{levelList[record.status].mode}</Tag>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: "反馈意见",
|
||||
key: "feedback",
|
||||
align: "center",
|
||||
render: (text, record) => {
|
||||
if (record.feedback === "") {
|
||||
return (
|
||||
<Space size="middle">
|
||||
<span style={{cursor: "pointer"}}>等待评审...</span>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Space size="middle">
|
||||
{/* <span style={{cursor:'pointer'}} onClick={this.downLoadFile}>{record.feedback}</span><FileTextTwoTone /> */}
|
||||
<span>无</span>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: "修改记录",
|
||||
key: "isModify",
|
||||
align: "center",
|
||||
width: 80,
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
{record.contents ? (<Button type="link" onClick={() => {
|
||||
this.setState({
|
||||
selectedSubmitId: record.uuid,
|
||||
modifyRecordVisible: true,
|
||||
});
|
||||
this.modifyRecordRef.current.getRecordList();
|
||||
}}>查看</Button>) : (<span>无</span>)}
|
||||
</Space>
|
||||
),
|
||||
}], [{
|
||||
title: "上传时间",
|
||||
dataIndex: "CreateAt",
|
||||
key: "CreateAt",
|
||||
align: "center",
|
||||
width: 150,
|
||||
}, {
|
||||
title: "上传用户",
|
||||
dataIndex: "user",
|
||||
key: "user",
|
||||
align: "center",
|
||||
width: 120,
|
||||
}, {
|
||||
title: "评审材料",
|
||||
key: "contents",
|
||||
align: "center",
|
||||
width: 220,
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
{
|
||||
record.contents ? (
|
||||
<span style={{cursor: "pointer"}} onClick={this.downLoadFile.bind(this, record.contents[0].item_id)}>{record.contents[0].comment} <FileTextTwoTone /></span>
|
||||
) : "无"
|
||||
}
|
||||
</Space>
|
||||
),
|
||||
}, {
|
||||
title: "评审结果",
|
||||
key: "status",
|
||||
align: "center",
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
let levelList = [{
|
||||
mode: "等待审核",
|
||||
color: "default",
|
||||
}, {
|
||||
mode: "通过",
|
||||
color: "#87D068",
|
||||
}, {
|
||||
mode: "再修改",
|
||||
color: "#2DB7F5",
|
||||
}, {
|
||||
mode: "驳回",
|
||||
color: "#FF5500",
|
||||
}];
|
||||
return (
|
||||
<Space size="middle">
|
||||
<Tag color={levelList[record.status].color} style={{cursor: "pointer"}}>{levelList[record.status].mode}</Tag>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: "反馈批注材料",
|
||||
dataIndex: "feedback-material",
|
||||
key: "feedback-material",
|
||||
align: "center",
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Space size="middle">
|
||||
<span>无</span>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
}],
|
||||
]
|
||||
|
||||
dateFilter(time) {
|
||||
let date = new Date(time);
|
||||
return `${date.getFullYear()}-${date.getMonth().toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
downLoadFile(file_id) {
|
||||
message.info(`开始下载文件:${file_id}!`);
|
||||
// request({
|
||||
// url:baseURL+`/review/file/${file_id}`,
|
||||
// // url:`http://49.232.73.36:8081/review/file/${file_id}`,
|
||||
// method: "GET",
|
||||
// responseType:"blob"
|
||||
// }).then(res => {
|
||||
// console.log(res);
|
||||
// const filename = res.headers["content-disposition"];
|
||||
// const blob = new Blob([res.data]);
|
||||
// var downloadElement = document.createElement("a");
|
||||
// var href = window.URL.createObjectURL(blob);
|
||||
// downloadElement.href = href;
|
||||
// downloadElement.download = decodeURIComponent(filename.split("filename*=")[1].replace("utf-8''", ""));
|
||||
// document.body.appendChild(downloadElement);
|
||||
// downloadElement.click();
|
||||
// document.body.removeChild(downloadElement);
|
||||
// window.URL.revokeObjectURL(href);
|
||||
// message.success("文件下载成功!");
|
||||
// }).catch(err => {
|
||||
// message.error("文件下载失败!");
|
||||
// });
|
||||
}
|
||||
|
||||
loadClumsIndex = () => {
|
||||
if (this.props.role === "2") {
|
||||
return 0;
|
||||
} else if (this.props.role === "3") {
|
||||
return 1;
|
||||
} else if (this.props.role === "4" && this.props.stepName === "测试框架与论证报告") {
|
||||
return 2;
|
||||
} else if (this.props.role === "4" && this.props.stepName !== "测试框架与论证报告") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getDataList();
|
||||
}
|
||||
|
||||
getDataList = () => {
|
||||
this.setState({
|
||||
loadingState: true,
|
||||
});
|
||||
var res = {
|
||||
"operation_code": 1000,
|
||||
"message": "",
|
||||
"data": null,
|
||||
};
|
||||
this.setState({
|
||||
data: res.data,
|
||||
loadingState: false,
|
||||
});
|
||||
// request({method:"GET", url:baseURL+`/review/proj/submits/${this.props.stepId}`}).then(res => {
|
||||
// // request({ method:'GET', url:`http://49.232.73.36:8081/review/proj/submits/${this.props.stepId}`}).then(res=>{
|
||||
// console.log(res.data);
|
||||
// this.setState({
|
||||
// data:res.data,
|
||||
// loadingState:false
|
||||
// });
|
||||
// }).catch(err => {
|
||||
// message.error(err.message||"审查材料加载失败!");
|
||||
// this.setState({
|
||||
// loadingState:false
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ModulaCard title={this.props.title}>
|
||||
<div className="data-table-box" data-component="data-table-box">
|
||||
<Table
|
||||
dataSource={this.state.data}
|
||||
columns={this.colums[this.loadClumsIndex()]}
|
||||
size="small"
|
||||
rowKey="Id"
|
||||
pagination={false}
|
||||
scroll={{y: "5.8rem"}}
|
||||
loading={this.state.loadingState}
|
||||
/>
|
||||
<div className="footer">
|
||||
<Pagination
|
||||
total={85}
|
||||
showTotal={total => `Total ${total} items`}
|
||||
defaultPageSize={20}
|
||||
defaultCurrent={1}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Modal title="评审意见" visible={this.state.reviewResultsVisible}
|
||||
cancelText="关闭"
|
||||
okText="审核"
|
||||
confirmLoading={this.state.statusChangeLoading}
|
||||
closable={!this.state.statusChangeLoading}
|
||||
maskClosable={!this.state.statusChangeLoading}
|
||||
keyboard={!this.state.statusChangeLoading}
|
||||
onOk={() => {
|
||||
// this.setState({
|
||||
// statusChangeLoading:true
|
||||
// });
|
||||
// request({
|
||||
// url:baseURL+"/review/proj/submit",
|
||||
// // url:`http://49.232.73.36:8081/review/proj/submit`,
|
||||
// method: "PUT",
|
||||
// data:{
|
||||
// new_status:this.state.statusChangeParams.value,
|
||||
// submit_id:this.state.statusChangeParams.submitId
|
||||
// }
|
||||
// }).then(res => {
|
||||
// this.setState({
|
||||
// statusChangeLoading:false,
|
||||
// reviewResultsVisible:false
|
||||
// });
|
||||
// this.getDataList();
|
||||
// message.success("审核成功");
|
||||
|
||||
// }).catch(err => {
|
||||
// this.setState({
|
||||
// statusChangeLoading:false
|
||||
// });
|
||||
// message.error(err.message||"审核失败");
|
||||
// });
|
||||
}}
|
||||
onCancel={() => {
|
||||
if (this.state.statusChangeLoading) {
|
||||
message.warning("请等待");
|
||||
} else {
|
||||
this.setState({
|
||||
reviewResultsVisible: false,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span>材料评审结果:</span>
|
||||
<Radio.Group name="radiogroup" value={this.state.statusChangeParams.value} onChange={(e) => {
|
||||
let statusChangeParams = Object.assign(this.state.statusChangeParams, {
|
||||
value: e.target.value,
|
||||
});
|
||||
this.setState({
|
||||
statusChangeParams,
|
||||
});
|
||||
}}>
|
||||
<Radio value={1}>通过</Radio>
|
||||
<Radio value={2}>再修改</Radio>
|
||||
<Radio value={3}>驳回</Radio>
|
||||
</Radio.Group>
|
||||
</Modal>
|
||||
<ModifyRecordModal
|
||||
show={this.state.modifyRecordVisible}
|
||||
submitId={this.state.selectedSubmitId}
|
||||
ref={this.modifyRecordRef}
|
||||
onCancel={() => {
|
||||
this.setState({
|
||||
modifyRecordVisible: false,
|
||||
});
|
||||
}}
|
||||
onComplete={() => {
|
||||
this.setState({
|
||||
modifyRecordVisible: false,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</ModulaCard>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
[data-component=data-table-box]{
|
||||
width: 100%;
|
||||
height: calc(100% - .38rem);
|
||||
box-sizing: border-box;
|
||||
padding: 0rem .25rem 0rem .4rem;
|
||||
position: relative;
|
||||
.ant-table-thead,.ant-table-row{
|
||||
height: .58rem;
|
||||
}
|
||||
.ant-table-cell{
|
||||
font-size: .14rem;
|
||||
}
|
||||
> .footer{
|
||||
width: 100%;
|
||||
height: .40rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
box-sizing: border-box;
|
||||
padding-left: .4rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
import React from "react";
|
||||
import {Button, Card, Col, DatePicker, Input, Row, Select} from "antd";
|
||||
import * as DatasetBackend from "./backend/DatasetBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import moment from "moment";
|
||||
import i18next from "i18next";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
class DatasetEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
datasetName: props.match.params.datasetName,
|
||||
dataset: null,
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getDataset();
|
||||
}
|
||||
|
||||
getDataset() {
|
||||
DatasetBackend.getDataset(this.props.account.name, this.state.datasetName)
|
||||
.then((dataset) => {
|
||||
this.setState({
|
||||
dataset: dataset,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseDatasetField(key, value) {
|
||||
if (["score"].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
updateDatasetField(key, value) {
|
||||
value = this.parseDatasetField(key, value);
|
||||
|
||||
let dataset = this.state.dataset;
|
||||
dataset[key] = value;
|
||||
this.setState({
|
||||
dataset: dataset,
|
||||
});
|
||||
}
|
||||
|
||||
renderDataset() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("dataset:Edit Dataset")}
|
||||
<Button type="primary" onClick={this.submitDatasetEdit.bind(this)}>{i18next.t("general:Save")}</Button>
|
||||
</div>
|
||||
} style={{marginLeft: "5px"}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("general:Name")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.dataset.name} onChange={e => {
|
||||
this.updateDatasetField("name", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Start date")}:
|
||||
</Col>
|
||||
<Col span={5} >
|
||||
<DatePicker defaultValue={moment(this.state.dataset.startDate, "YYYY-MM-DD")} onChange={(time, timeString) => {
|
||||
this.updateDatasetField("startDate", timeString);
|
||||
}} />
|
||||
</Col>
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:End date")}:
|
||||
</Col>
|
||||
<Col span={10} >
|
||||
<DatePicker defaultValue={moment(this.state.dataset.endDate, "YYYY-MM-DD")} onChange={(time, timeString) => {
|
||||
this.updateDatasetField("endDate", timeString);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Full name")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.dataset.fullName} onChange={e => {
|
||||
this.updateDatasetField("fullName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Organizer")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.dataset.organizer} onChange={e => {
|
||||
this.updateDatasetField("organizer", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Location")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.dataset.location} onChange={e => {
|
||||
this.updateDatasetField("location", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Address")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.dataset.address} onChange={e => {
|
||||
this.updateDatasetField("address", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("general:Status")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.dataset.status} onChange={(value => {this.updateDatasetField("status", value);})}>
|
||||
{
|
||||
[
|
||||
{id: "Public", name: "Public (Everyone can see it)"},
|
||||
{id: "Hidden", name: "Hidden (Only yourself can see it)"},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Carousels")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: "100%"}} placeholder="Please input"
|
||||
value={this.state.dataset.carousels}
|
||||
onChange={value => {
|
||||
this.updateDatasetField("carousels", value);
|
||||
}}
|
||||
>
|
||||
{
|
||||
this.state.dataset.carousels.map((carousel, index) => <Option key={carousel}>{carousel}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Introduction text")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.dataset.introText} onChange={e => {
|
||||
this.updateDatasetField("introText", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Default item")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.dataset.defaultItem} onChange={value => {this.updateDatasetField("defaultItem", value);}}>
|
||||
{
|
||||
this.state.dataset.treeItems.filter(treeItem => treeItem.children.length === 0).map((treeItem, index) => <Option key={treeItem.title}>{`${treeItem.title} | ${treeItem.titleEn}`}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{i18next.t("dataset:Language")}:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.dataset.language} onChange={(value => {this.updateDatasetField("language", value);})}>
|
||||
{
|
||||
[
|
||||
{id: "zh", name: "zh"},
|
||||
{id: "en", name: "en"},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
submitDatasetEdit() {
|
||||
let dataset = Setting.deepCopy(this.state.dataset);
|
||||
DatasetBackend.updateDataset(this.state.dataset.owner, this.state.datasetName, dataset)
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
this.setState({
|
||||
datasetName: this.state.dataset.name,
|
||||
});
|
||||
this.props.history.push(`/datasets/${this.state.dataset.name}`);
|
||||
} else {
|
||||
Setting.showMessage("error", "failed to save: server side failure");
|
||||
this.updateDatasetField("name", this.state.datasetName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `failed to save: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Row style={{width: "100%"}}>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
{
|
||||
this.state.dataset !== null ? this.renderDataset() : null
|
||||
}
|
||||
</Col>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{margin: 10}}>
|
||||
<Col span={2}>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<Button type="primary" size="large" onClick={this.submitDatasetEdit.bind(this)}>{i18next.t("general:Save")}</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatasetEditPage;
|
|
@ -0,0 +1,208 @@
|
|||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Col, Popconfirm, Row, Table} from "antd";
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as DatasetBackend from "./backend/DatasetBackend";
|
||||
import i18next from "i18next";
|
||||
|
||||
class DatasetListPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
datasets: null,
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getDatasets();
|
||||
}
|
||||
|
||||
getDatasets() {
|
||||
DatasetBackend.getDatasets(this.props.account.name)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
datasets: res,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
newDataset() {
|
||||
return {
|
||||
owner: this.props.account.name,
|
||||
name: `dataset_${this.state.datasets.length}`,
|
||||
createdTime: moment().format(),
|
||||
startDate: moment().format("YYYY-MM-DD"),
|
||||
endDate: moment().format("YYYY-MM-DD"),
|
||||
fullName: `Dataset ${this.state.datasets.length}`,
|
||||
organizer: "Casbin",
|
||||
location: "Shanghai, China",
|
||||
address: "3663 Zhongshan Road North",
|
||||
status: "Public",
|
||||
language: "zh",
|
||||
carousels: [],
|
||||
introText: "Introduction..",
|
||||
defaultItem: "Home",
|
||||
treeItems: [{key: "Home", title: "首页", titleEn: "Home", content: "内容", contentEn: "Content", children: []}],
|
||||
};
|
||||
}
|
||||
|
||||
addDataset() {
|
||||
const newDataset = this.newDataset();
|
||||
DatasetBackend.addDataset(newDataset)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Dataset added successfully");
|
||||
this.setState({
|
||||
datasets: Setting.prependRow(this.state.datasets, newDataset),
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Dataset failed to add: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteDataset(i) {
|
||||
DatasetBackend.deleteDataset(this.state.datasets[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Dataset deleted successfully");
|
||||
this.setState({
|
||||
datasets: Setting.deleteRow(this.state.datasets, i),
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Dataset failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(datasets) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
width: "120px",
|
||||
sorter: (a, b) => a.name.localeCompare(b.name),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/datasets/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("dataset:Start date"),
|
||||
dataIndex: "startDate",
|
||||
key: "startDate",
|
||||
width: "70px",
|
||||
sorter: (a, b) => a.startDate.localeCompare(b.startDate),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("dataset:End date"),
|
||||
dataIndex: "endDate",
|
||||
key: "endDate",
|
||||
width: "70px",
|
||||
sorter: (a, b) => a.endDate.localeCompare(b.endDate),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("dataset:Full name"),
|
||||
dataIndex: "fullName",
|
||||
key: "fullName",
|
||||
width: "200px",
|
||||
sorter: (a, b) => a.fullName.localeCompare(b.fullName),
|
||||
},
|
||||
{
|
||||
title: i18next.t("dataset:Organizer"),
|
||||
dataIndex: "organizer",
|
||||
key: "organizer",
|
||||
width: "120px",
|
||||
sorter: (a, b) => a.organizer.localeCompare(b.organizer),
|
||||
},
|
||||
{
|
||||
title: i18next.t("dataset:Location"),
|
||||
dataIndex: "location",
|
||||
key: "location",
|
||||
width: "120px",
|
||||
sorter: (a, b) => a.location.localeCompare(b.location),
|
||||
},
|
||||
{
|
||||
title: i18next.t("dataset:Address"),
|
||||
dataIndex: "address",
|
||||
key: "address",
|
||||
width: "120px",
|
||||
sorter: (a, b) => a.address.localeCompare(b.address),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
width: "80px",
|
||||
sorter: (a, b) => a.status.localeCompare(b.status),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: "action",
|
||||
key: "action",
|
||||
width: "120px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/datasets/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Popconfirm
|
||||
title={`Sure to delete dataset: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteDataset(index)}
|
||||
okText="OK"
|
||||
cancelText="Cancel"
|
||||
>
|
||||
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table columns={columns} dataSource={datasets} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Datasets")}
|
||||
<Button type="primary" size="small" onClick={this.addDataset.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={datasets === null}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Row style={{width: "100%"}}>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
{
|
||||
this.renderTable(this.state.datasets)
|
||||
}
|
||||
</Col>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatasetListPage;
|
|
@ -0,0 +1,59 @@
|
|||
import React, {Component} from "react";
|
||||
import {Button, Col, Row} from "antd";
|
||||
import "./HistoryQuestion.less";
|
||||
|
||||
export default class HistoryQuestion extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="history-question-item" data-component="history-question-item">
|
||||
<Row gutter={[16, 16]} className="queston-content">
|
||||
<Col span="16" className="question-title">
|
||||
<span>题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目......题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目.题目题目题目题目题目题目题目题目.(最多5行过多省略)题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目......题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目题目.题目题目题目题目题目题目题目题目.(最多5行过多省略)</span>
|
||||
</Col>
|
||||
<Col span="8" className="question-params">
|
||||
<Row className="params-item">
|
||||
<Col span="12" className="title">
|
||||
<span>学科名称:</span>
|
||||
</Col>
|
||||
<Col span="12" className="value" >
|
||||
<span>数学</span>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="params-item">
|
||||
<Col span="12" className="title">
|
||||
<span>能力纬度:</span>
|
||||
</Col>
|
||||
<Col span="12" className="value">
|
||||
<span>参数1;参数2;参数3</span>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="params-item">
|
||||
<Col span="12" className="title">
|
||||
<span>内容纬度</span>
|
||||
</Col>
|
||||
<Col span="12" className="value">
|
||||
<span>参数1;参数2;参数3</span>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="params-item">
|
||||
<Col span="12" className="title">
|
||||
<span>难度等级:</span>
|
||||
</Col>
|
||||
<Col span="12" className="value">
|
||||
<span>参数1</span>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={[16, 16]} className="question-footer">
|
||||
<Col span="16" className="question-answer">
|
||||
<span>答案:xxxx</span>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<Button type="primary" size="small" style={{backgroundColor: "#56BFFF", borderColor: "#56BFFF"}}>使用</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
[data-component=history-question-item]{
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: .14rem .1rem .16rem .24rem;
|
||||
background-color: #FFFEFE33;
|
||||
border: .01rem solid #2DB7F5;
|
||||
margin-top: .2rem;
|
||||
> .queston-content{
|
||||
width: 100%;
|
||||
> .question-title{
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-top: .11rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 5;
|
||||
-webkit-box-orient: vertical;
|
||||
text-align: justify;
|
||||
line-height: .22rem;
|
||||
> span{
|
||||
font-size: .14rem;
|
||||
color: #00000059;
|
||||
}
|
||||
}
|
||||
> .question-params{
|
||||
width: 100%;
|
||||
> .params-item{
|
||||
width: 100%;
|
||||
> .title{
|
||||
line-height: .22rem;
|
||||
> span{
|
||||
font-size: .1rem;
|
||||
color: #1890FF;
|
||||
}
|
||||
}
|
||||
> .value{
|
||||
line-height: .22rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
> span{
|
||||
font-size: .1rem;
|
||||
color: #1890FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .question-footer{
|
||||
width: 100%;
|
||||
margin-top: .25rem;
|
||||
> .question-answer{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> span{
|
||||
font-size: .1rem;
|
||||
color: #1890FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import React from "react";
|
||||
|
||||
class HomePage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
hello
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default HomePage;
|
Loading…
Reference in New Issue