竞赛-作品提交新页面

This commit is contained in:
caishi 2024-08-23 11:28:57 +08:00
parent 84f97c3eaa
commit 1360e9f4d9
11 changed files with 688 additions and 29 deletions

View File

@ -16,4 +16,7 @@ $ npm run start
```
install过程中报错可先安装node-sass
npm install node-sass --save-dev
yarn install --force
yarn install --force

View File

@ -0,0 +1,20 @@
import { Button } from 'antd'
import React, { useState } from 'react'
type AsyncButtonProps = React.ComponentProps<typeof Button> & {
onClick: (e?: React.MouseEvent<HTMLElement, MouseEvent>) => Promise<any>
}
export const AsyncButton = ({ children, ...props }: AsyncButtonProps) => {
const [btnLoading, setBtnLoading] = useState(false)
return <Button {...props} loading={btnLoading} onClick={async (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
try {
setBtnLoading(true)
await props.onClick(e)
setBtnLoading(false)
} catch (error) {
console.error(error);
setBtnLoading(false)
}
}}>{children}</Button>
}

View File

@ -35,7 +35,8 @@ import { getCompetitionsList,
getCourse,
Results,
TabResults,
getHSCompetitionInfo
getHSCompetitionInfo,
getWorkSubmitUpdateRes,
} from "@/service/competitions";
export interface CompetitionsModelState {
name: string;
@ -91,6 +92,7 @@ export interface CompetitionsType {
Results:Effect;
TabResults:Effect;
getHSCompetitionInfo:Effect
getWorkSubmitUpdateRes?: Effect;
};
reducers: {
save: Reducer<CompetitionsModelState>;
@ -127,6 +129,10 @@ const CompetitionsModel: CompetitionsType = {
})
return response
},
*getWorkSubmitUpdateRes({ payload, callback }, { call, put }) {
const response = yield call(getWorkSubmitUpdateRes, payload);
return response;
},
//提交学生数据
*addApplytojoincourse({ payload, callback }, { call, put }) {
const response = yield call(addApplytojoincourse, payload);

View File

@ -59,7 +59,7 @@ const ShixunsListPage: FC<PageProps> = ({
return (
<Modal
title="提交文件"
visible={shixunsDetail.actionTabs.key === 'md-tab'}
open={shixunsDetail.actionTabs.key === 'md-tab'}
confirmLoading={confirmLoading}
onOk={async ()=>{
if(fileList?.length<=0){
@ -68,7 +68,7 @@ const ShixunsListPage: FC<PageProps> = ({
}
setConfirmLoading(true);
const resulr=await uploadFile(fileList[0],{
login:user.eduUserInfo?.login,
login:user.userInfo?.login,
container_type:"Competition",
container_id: shixunsDetail.actionTabs.params.id,
stage_type:shixunsDetail.actionTabs.params.value,

View File

@ -291,13 +291,14 @@ function Ranking({ChartRules,ItemData,getCharts,Selectkey,HeaderDetail,getChartR
<div>
{ChartRules?.stages?.length>0?null:<RankingNull/>}
{ChartRules?.stages?.length>0&&<Tabs animated={true} tabBarExtraContent={(userinfo?.admin||userinfo?.business||Editable)?<Button onClick={()=>{
setIsupdate(true)
}}>
{ChartRules?.stages?.length>0&&
<Tabs animated={true}
tabBarExtraContent={(userinfo?.admin||userinfo?.business||Editable)?
<Button onClick={()=>{setIsupdate(true)}}>
</Button>:(StaffDetail.enrolled&&item?.start_time&&item?.end_time)&&<span>{moment(item?.start_time).format("YYYY-MM-DD HH:mm:ss")}{moment(item?.end_time).format("YYYY-MM-DD HH:mm:ss")}
<Button style={{marginLeft:'20px'}} disabled={moment(item?.start_time).unix()>moment(moment().format('YYYY-MM-DD HH:mm:s')).unix()||moment(moment().format('YYYY-MM-DD HH:mm:s')).unix()>moment(item?.end_time).unix()} onClick={()=>{
</Button>:
(StaffDetail.enrolled&&item?.start_time&&item?.end_time)&&<span>{moment(item?.start_time).format("YYYY-MM-DD HH:mm:ss")}{moment(item?.end_time).format("YYYY-MM-DD HH:mm:ss")}
<Button style={{marginLeft:'20px'}} disabled={moment(item?.start_time).unix()>moment(moment().format('YYYY-MM-DD HH:mm:s')).unix()||moment(moment().format('YYYY-MM-DD HH:mm:s')).unix()>moment(item?.end_time).unix()} onClick={()=>{
// <moment(item?.end_time).unix()
dispatch({
type: 'shixunsDetail/setActionTabs',
@ -309,7 +310,7 @@ function Ranking({ChartRules,ItemData,getCharts,Selectkey,HeaderDetail,getChartR
}
},
})
}}></Button></span>} onChange={(e)=>{
}}></Button></span>} onChange={(e)=>{
setIsupdate(false)
let data=ChartRules?.stages?.filter(item=>parseInt(e)===parseInt(item?.id))[0];
let datas=data?.children?.[0];

View File

@ -0,0 +1,45 @@
[class^='ant-upload-list-item-info']{
height: 26px;
background: #F6F7F9;
border-radius: 15px;
}
[class^='ant-upload-list-item-info'] [class^="anticon"]{
top:7px!important;
}
[class^="ant-table-cell"]::before{
background: rgba(255,255,255,0);
}
.WorkSubmit{
&Desc{
width: 100%;
padding: 8px 14px;
background: #f5f5f5;
color:#9096a3;
font-size: 12px;
border-radius: 0 0 8px 8px;
margin: 20px 0 30px 0;
}
.span{
font-size: 12px;
font-weight: 400;
color: #C5C5C5;
span{
color: #717171;
}
}
.search{
width: 292px;
border-radius: 19px;
height: 38px;
padding: 5px 14px;
font-size: 14px;
}
.downBut{
border-radius: 16px;
color: #3061D0;
padding: 0 20px;
height: 32px;
border: 1px solid #BACFFE;
box-shadow: 0px 2px 4px 0px #E0DFE1, inset 0px 1px 3px 0px rgba(255,255,255,0.5);
}
}

View File

@ -0,0 +1,567 @@
import React, { useEffect, useRef, useState } from 'react'
import type { FC } from 'react';
import {
connect, ConnectProps, Dispatch, useParams
} from 'umi';
import {
Tabs,
Row,
Pagination,
Table,
Button,
Modal,
Form,
message,
Upload,
Tooltip,
Input,
Select
} from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import styles from './index.less';
import NoData from '@/components/NoData';
import { AsyncButton } from '@/components/AsyncButton';
import MarkdownEditor from '@/components/markdown-editor';
import RenderHtml from '@/components/RenderHtml';
import moment from 'moment';
import { uploadFile } from '@/components/UploadFile';
import JSZip from 'jszip';
import { downLoadLink } from "@/utils/util";
import Fetch from '@/utils/fetch';
import ENV from "@/utils/env";
interface PageProps extends Partial<ConnectProps> {
dispatch?: Dispatch,
userinfo?: any,
Editable?: boolean,
ItemData?: any,
TabResults?: any,
HeaderDetail?: any,
StaffDetail?: any,
getTabResults?: Function,//获取Tab和md数据
}
const WorkSubmit: FC<PageProps> = ({
dispatch,
userinfo,
Editable,
ItemData,
TabResults,
HeaderDetail,
StaffDetail,
getTabResults = () => { }
}) => {
const [form] = Form.useForm();
const [formButLoading, setFormButLoading] = useState<boolean>(false);
// 开启/关闭 编辑
const [isEdit, setIsEdit] = useState<boolean>(false)
const { identifier } = useParams();
// 提交作品1, 仅提交文件2
const [modelType, setModelType] = useState<number>(1);
// 竞赛管理员、超管、运营
const [identity, setIdentity] = useState<boolean>(false);
const [isSubmitModel, setIsSubmitModel] = useState<boolean>(false);
// 上传列表数据
const [fileList, setFileList] = useState<any[]>([]);
// 表格数据
const [tableLoading, setTableLoading] = useState<boolean>(false);
//战队信息
const [teamList, setTeamlist] = useState<any>([]);
//loading状态
const [isloading, setisloading] = useState<any>(false)
//获取id
const [rowTable, setRowTable] = useState<any>({
name: "",
url: "",
id: null,
fileList: [],
competition_team_id: ''
});
const [tableList, setTableList] = useState<any>({
total_count: 0,
results: [],
});
// 当前赛事
const [gameItem, setGameItem] = useState<any>(null);
// 分页,搜索
const [urlData, setUrlData] = useState<any>({
page: 1,
per_page: 20,
keyword: "",
});
// MD内容
const [mdContent, setMdContent] = useState<any>("");
// 下载所有文件时打包成zip文件
const [zipAll, setZipAll] = useState(new JSZip());
useEffect(() => {
setIdentity(userinfo?.admin || userinfo?.business || Editable)
}, [userinfo?.admin, userinfo?.business, Editable])
useEffect(() => {
ItemData?.only_file ? setModelType(2) : setModelType(1);
}, [ItemData])
useEffect(() => {
if (TabResults.stages && TabResults.stages?.length > 0) {
TabResults.stages?.[0]?.children?.length > 0 ?
setGameItem(TabResults.stages?.[0]?.children?.[0] || null) :
setGameItem(TabResults.stages?.[0] || null);
}
}, [TabResults.stages])
useEffect(() => {
getResults();
// getTeamList()
getTeam()
}, [gameItem?.id, urlData.page])
async function getTeamList() {
setisloading(true)
let res = await Fetch(`${ENV.API_SERVER}/api/competitions/${identifier}/my_teams`, {
method: 'get'
})
setisloading(false)
setIsSubmitModel(true)
if (res?.status === 0) {
setTeamlist(res?.data)
form.setFieldsValue({
name: '',
url: '',
id: '',
competition_team_id: res?.data?.[0]?.id,
})
}
}
async function getTeam() {
let res = await Fetch(`${ENV.API_SERVER}/api/competitions/${identifier}/my_teams`, {
method: 'get'
})
if (res?.status === 0) {
setTeamlist(res?.data)
}
}
// 表格头部数据
const columns: any[] = [
{
title: <span style={{ color: "#5F6368" }}></span>,
dataIndex: 'team_name',
width: "120px",
ellipsis: true,
render: (text: any) => <Tooltip placement="topLeft" title={text}>{text || "- -"}</Tooltip>,
isShow: [1, 2],
},
{
title: <span style={{ color: "#5F6368" }}></span>,
dataIndex: 'user_name',
width: "120px",
ellipsis: true,
render: (text: any) => <Tooltip placement="topLeft" title={text}>{text || "- -"}</Tooltip>,
isShow: [1, 2],
},
{
title: <span style={{ color: "#5F6368" }}></span>,
dataIndex: 'name',
ellipsis: true,
render: (text: any, record: any) => text ? <a href={record.url || '#'} target="_blank"><Tooltip placement="topLeft" title={text}>{text}</Tooltip></a> : "--",
isShow: [1],
},
{
title: <span style={{ color: "#5F6368" }}></span>,
dataIndex: 'file_name',
width: modelType == 1 ? "180px" : "",
ellipsis: true,
render: (text: any) => <Tooltip placement="topLeft" title={text}>{text || "- -"}</Tooltip>,
isShow: [1, 2],
},
{
title: <span style={{ color: "#5F6368" }}></span>,
dataIndex: 'updated_at',
width: "180px",
render: (text: any) => text || '- -',
isShow: [1, 2],
},
{
title: <span style={{ color: "#5F6368" }}></span>,
dataIndex: 'result_url',
ellipsis: true,
width: "200px",
align: 'center',
render: (text: any, record: any) => <Row justify={identity ? "center" : "space-between"}>
{!identity && <Button type="link" onClick={() => {
setIsSubmitModel(true)
setRowTable({
name: record.name,
url: record.url,
id: record.id,
competition_team_id: record.competition_team_id,
})
form.setFieldsValue({
name: record.name,
url: record.url,
id: record.id,
competition_team_id: record.competition_team_id,
})
if (record.file_name) {
setFileList([{
uid: "-1", // TODO : 这里目前无法获取到id或者唯一标识暂时只能用-1
name: record.file_name,
status: 'done',
url: record.result_url || "",
}])
}
}}></Button>}
<AsyncButton type="link" disabled={!text} onClick={async () => downLoadLink(record.file_name, text)}>{identity ? "下载文件" : "下载"}</AsyncButton>
{!identity && <Button type="link" onClick={async () => {
Modal.confirm({
title: '提示',
content: '提交作品删除后不可恢复,确认删除该作品',
onOk: async () => {
let res = await Fetch(`${ENV.API_SERVER}/api/competitions/${identifier}/delete_result.json`, {
method: 'Delete',
body: {
result_id: record?.id
}
})
if (res?.status === 0) {
message.info("删除成功")
getResults()
}
}
})
}}></Button>}
</Row>,
isShow: [1, 2],
},
].filter((item: any) => item.isShow.includes(modelType))
// 获取列表数据
const getResults = async () => {
setTableLoading(true)
const data: any = await dispatch({
type: 'competitions/Results',
payload: {
identifier: identifier,
stage_id: gameItem?.id,
module_type: 'worksubmit',
...urlData,
}
})
setTableList(data)
setTableLoading(false)
}
// 更新MD内容
const getUpMDContent = async (data: any) => {
const res: any = await dispatch({
type: 'competitions/updateMdContent',
payload: {
identifier: identifier,
stage_id: gameItem?.id,
competition_module_id: ItemData.id,
content: mdContent,
md_content_id: data?.id,
}
})
res.status == 0 && message.success(res.message);
setIsEdit(false);
await getTabResults();
}
// 作品提交或者编辑
const handleFormFinish = async (values: any) => {
setFormButLoading(true);
let res: any;
if (modelType == 2 && fileList.length == 0) {
message.error("请选择文件");
return;
}
const Data: any = {
login: userinfo?.login,
container_type: "Competition",
file_name: fileList?.[0]?.name,
stage_type: gameItem?.id || null,
container_id: HeaderDetail?.id,
result_id: rowTable?.id,
module_type: 'worksubmit',
competition_team_id: values.competition_team_id
}
if (modelType == 1) {
const res: any = await Fetch(`${ENV.API_SERVER}/api/competitions/${identifier}/check_result_url.json`,
{
method: "GET",
params: {
url: values.url,
stage_id: gameItem?.id,
result_id: rowTable?.id,
competition_team_id: values.competition_team_id
}
}
)
setFormButLoading(false);
if (res?.status != 0) return
Data["name"] = values.name;
Data["url"] = values.url;
}
if (modelType == 1 && fileList.length == 0) {
res = await dispatch({
type: 'competitions/getWorkSubmitUpdateRes',
payload: {
identifier: identifier,
result_id: rowTable?.id,
name: values.name,
url: values.url,
stage_id: gameItem?.id,
result_url: rowTable?.result_url,
module_type: 'worksubmit',
competition_team_id: values.competition_team_id
}
})
} else {
res = await uploadFile(fileList[0], Data)
}
if (res?.status == 0) {
message.success("提交成功");
} else {
message.info(res?.message || "提交失败");
}
setFormButLoading(false);
setIsSubmitModel(false);
setFileList([]);
getResults();
}
// 下载所有作品
const handleAllDownload = async () => {
const res: any = await dispatch({
type: 'competitions/Results',
payload: {
identifier: identifier,
stage_id: gameItem?.id,
page: 1,
per_page: 9999999, // TODO :查询所有列表数据
keyword: "",
module_type: 'worksubmit',
}
})
const DownloadList = res?.results?.filter((item: any) => item?.result_url && item.file_name)
const modal = Modal.info({
width: 460,
title: <div>,<span className="c-red"></span></div>,
content: <div>: <span className="c-blue">{0}</span>/{DownloadList.length}</div>,
maskClosable: false,
className: styles.modal,
onOk: () => {
}
});
const nameLsit: string[] = [];
const addzip = async (data: any, progress: number) => {
try {
const zip = new JSZip();
const response = await fetch(data.result_url, { method: "get" });
const blob = await response.blob();
zip.file(data.file_name, blob);
await zip.generateAsync({ type: "blob" }).then((blob) => {
const getNameFile = (name: string, index: number = 0) => {
if ((index == 0 && nameLsit.includes(name)) || nameLsit.includes(`${name}(${index})`)) {
getNameFile(name, index + 1);
} else {
nameLsit.push(index == 0 ? name : `${name}(${index})`)
zipAll.file(index == 0 ? name + ".zip" : `${name}(${index})` + ".zip", blob);
}
}
getNameFile(`${data?.team_name}-${data?.user_name}`);
})
modal.update({
content: <div>: <span className="c-blue">{progress}</span>/{DownloadList.length}</div>,
})
} catch (error) {
message.error(`${data.file_name}下载失败`);
}
}
if (DownloadList.length > 0) {
let i = 0;
for (let item of DownloadList) {
await addzip(item, ++i);
}
zipAll.generateAsync({ type: "blob" }).then((blob) => {
downLoadLink(HeaderDetail.name, window.URL.createObjectURL(blob));
})
}
modal.destroy()
}
const uploadProps = {
maxCount: 1,
withCredentials: true,
fileList: fileList,
onRemove: () => {
setFileList([]);
},
beforeUpload: (file: any) => {
const fileSize = file.size / 1024 / 1024;
const fileType = file.name.split(".").slice(-1)[0].toLowerCase();
if ((modelType == 1 && fileSize > 150 || modelType == 2 && fileSize / 1024 > 1) || fileSize == 0) {
message.error(`${file.name} 文件无法上传。${fileSize == 0 ? "文件内容不能为空" : `超过文件大小限制(${modelType == 1 ? '150MB' : '1G'})`}`)
return Promise.reject()
}
setFileList([file])
return false
}
};
return (<div className={styles.WorkSubmit}>
{gameItem ?
<Tabs defaultActiveKey={TabResults.stages?.[0]?.id || 1}
destroyInactiveTabPane
tabBarExtraContent={<Row style={{ marginBottom: "10px" }}>
{!identity && StaffDetail.enrolled && <Button type="primary" onClick={() => setIsSubmitModel(true)}></Button>}
{identity && !isEdit && <Button style={{ marginLeft: "10px" }} type="primary" onClick={() => setIsEdit(true)}></Button>}
</Row>}
onChange={(activeKey) => {
const item = TabResults.stages.find((item: any) => item.id == activeKey)
item.children.length > 0 ? setGameItem(item.children[0]) : setGameItem(item)
}}>
{TabResults.stages?.map((item: any, index: number) => <Tabs.TabPane tab={<div style={{ marginBottom: "20px" }}>{item.name}</div>} key={item.id}>
{
isEdit ?
<>
<MarkdownEditor defaultValue={TabResults.rule_contents[index]?.content || ""} onChange={(e: any) => setMdContent(e)} />
<Row>
<AsyncButton type="primary" onClick={() => getUpMDContent(TabResults.rule_contents[index])}></AsyncButton>
<Button style={{ marginLeft: "10px" }} onClick={async () => setIsEdit(false)}></Button>
</Row>
</> : <RenderHtml style={{ marginTop: "10px" }} value={TabResults.rule_contents[index]?.content || ""} />
}
{item.children?.length > 0 && <Tabs defaultActiveKey={item.children?.[0]?.id} destroyInactiveTabPane onChange={(activeKey) => { setGameItem(item.children?.find((item: any) => item.id == activeKey)) }}>
{item.children?.map((ChildItem: any) => <Tabs.TabPane tab={ChildItem.name} key={ChildItem.id} ></Tabs.TabPane>)}
</Tabs>}
</Tabs.TabPane>)}
</Tabs> :
<div>
{(StaffDetail.enrolled || identity) && <Row style={{ marginBottom: "10px", paddingBottom: "10px", borderBottom: "1px solid #eee" }}>
{!identity && StaffDetail.enrolled && <Button style={{ marginLeft: "auto" }} loading={isloading} type="primary" onClick={() => {
getTeamList()
}}></Button>}
{identity && !isEdit && <Button style={{ marginLeft: !identity && StaffDetail.enrolled ? "10px" : "auto" }} type="primary" onClick={() => setIsEdit(true)}></Button>}
</Row>}
{
isEdit ?
<>
<MarkdownEditor defaultValue={TabResults.rule_contents?.[0]?.content || ""} onChange={(e: any) => setMdContent(e)} />
<Row>
<AsyncButton type="primary" onClick={() => getUpMDContent(TabResults.rule_contents?.[0])}></AsyncButton>
<Button style={{ marginLeft: "10px" }} onClick={async () => setIsEdit(false)}></Button>
</Row>
</> : <RenderHtml style={{ marginTop: "10px" }} value={TabResults.rule_contents?.[0]?.content || ""} />
}
</div>}
<Row align="middle" justify="space-between" style={{ marginTop: "21px" }}>
<Row align="middle">
<Input className={styles.search} placeholder="请输入队伍名称或提交人姓名搜索"
suffix={<i className='iconfont icon-sousuo9' onClick={getResults} style={{ color: "#000", cursor: "pointer", fontSize: "14px" }} />}
onChange={(e: any) => {
urlData.keyword = e.target.value
urlData.search = e.target.value
setUrlData(urlData)
}}
style={{ background: "#F6F7F9" }}
bordered={false}
onPressEnter={getResults} />
<div style={{ color: "#9B9B9B", fontSize: "14px", marginLeft: "20px" }}><span style={{ color: "#165DFF" }}>{tableList.total_count}</span></div>
</Row>
{identity && <Row align="middle">
{modelType == 1 && <Button style={{ lineHeight: "32px" }} target="_blank"
href={`/api/competitions/${identifier}/results.xlsx?identifier=${identifier}&stage_id=${gameItem?.id || ""}&module_type=worksubmit`}
icon={<i className='iconfont icon-lianjie3' style={{ fontSize: "16px", color: "#44D7B6" }} />}
className={styles.downBut}></Button>}
<AsyncButton icon={<i className='iconfont icon-wenjian4' style={{ fontSize: "16px", color: "#F6C555" }} />} className={styles.downBut} style={{ marginLeft: "20px" }} onClick={handleAllDownload}></AsyncButton>
</Row>}
</Row>
<Table style={{ marginTop: "17px" }} loading={tableLoading} columns={columns} dataSource={tableList.results} locale={{ emptyText: <NoData /> }} pagination={false} />
<Row style={{ marginTop: "20px" }} align="middle" justify='space-between'>
{
(gameItem?.end_time && gameItem?.start_time || HeaderDetail.start_time && HeaderDetail.end_time) &&
<span className={styles.span}><span>{moment(gameItem?.start_time || HeaderDetail.start_time).format("YYYY-MM-DD HH:mm:ss")}</span> <span>{moment(gameItem?.end_time || HeaderDetail.end_time).format("YYYY-MM-DD HH:mm:ss")}</span></span>
}
<Pagination showQuickJumper hideOnSinglePage
current={urlData.page}
pageSize={urlData.per_page}
onChange={(page) => setUrlData({ ...urlData, page })}
onShowSizeChange={(page, per_page) => setUrlData({ ...urlData, page: 1, per_page })}
total={tableList.total_count || 0} />
</Row>
<Modal centered destroyOnClose
title={<div style={{
fontWeight: "500",
color: "#000000",
marginTop: "10px"
}}></div>}
visible={isSubmitModel}
bodyStyle={{ padding: " 0px 25px 10px 25px" }}
onOk={() => form.submit()} confirmLoading={formButLoading}
onCancel={() => {
setIsSubmitModel(false);
setFileList([]);
setRowTable(null);
}}>
<div className={styles.WorkSubmitDesc}></div>
<Form form={form} colon={false} onFinish={handleFormFinish}>
{modelType == 1 && <><Form.Item label="作品名称" name="name" rules={[{ required: true, message: "请填写作品名称" }]} >
<Input showCount maxLength={60} placeholder="请输入作品名称" />
</Form.Item>
<Form.Item label="作品链接" name="url" rules={[{ required: true, message: "请填写作品链接" }]} >
<Input placeholder="请输入作品链接" />
</Form.Item>
</>}
<Form.Item label="提交战队" name="competition_team_id" rules={[{ required: true, message: "请选择战队" }]} >
<Select>
{teamList?.map((item: any) => <Select.Option key={item?.id} value={item?.id}>{item?.name}</Select.Option>)}
</Select>
</Form.Item>
<Form.Item name="fileList" style={{ paddingLeft: modelType == 1 ? "76px" : "0" }} valuePropName="fileList"
getValueFromEvent={(e: any) => {
if (Array.isArray(e)) return e;
return e?.fileList;
}}>
{modelType == 1 && <Upload {...uploadProps}>
<Row align="middle">
<Button type="primary" ghost icon={<UploadOutlined />}>{fileList.length > 0 ? "更换文件" : "文件上传"}</Button>
<Tooltip placement="right" overlayStyle={{ maxWidth: 600 }}
title={<div onClick={(e) => { e.preventDefault(); e.stopPropagation(); }}>
<p></p>
<p>1. 1</p>
<p>2. 150M</p>
</div>}>
<i onClick={(e) => { e.preventDefault(); e.stopPropagation(); }} className='iconfont icon-tishixiaowenhao ml5' style={{ cursor: 'pointer', color: '#C5C5C5' }} />
</Tooltip>
</Row>
</Upload>}
{modelType == 2 && <Upload.Dragger className={styles.fileList} style={{ background: "#fff", padding: "31px 0px" }} {...uploadProps}>
<p className="ant-upload-drag-icon"><i className='iconfont icon-shangchuan4' style={{ fontSize: "32px", color: "#165DFF" }} /></p>
<p className="ant-upload-text"></p>
</Upload.Dragger>}
</Form.Item>
</Form>
</Modal>
</div>)
}
export default connect((
{
}: {
}) => ({
}))(WorkSubmit)

View File

@ -37,6 +37,7 @@ import env from '@/utils/env';
import ClaModal from '../components/ClaModal';
import SubCompetition from './components/SubCompetition';
import { hongshanId , getHSCount } from '@/utils/hongshan';
import WorkSubmit from './components/WorkSubmit';
interface PageProps extends ConnectProps {
competitions: CompetitionsModelState;
@ -102,6 +103,8 @@ const competitionDetails: FC<PageProps> = ({
const [datas,setdatas]=useState<any>('');
const [visible,setVisible]=useState<any>(false);
const [hsVisible,setHsVisible]=useState<any>(false);
// 作品提交
const [isWorkSubmit, setIsWorkSubmit] = useState<boolean>(false);
const { hongshanInfos } = competitions;
useEffect(()=>{
@ -130,18 +133,18 @@ const competitionDetails: FC<PageProps> = ({
}, [identifier])
async function init() {
const res = await dispatch({
type: 'competitions/getHeader',
payload: {
identifier: identifier
}
})
setStaffDetail(await dispatch({
type: 'competitions/getStaff',
payload: {
identifier: identifier
}
}))
const res = await dispatch({
type: 'competitions/getHeader',
payload: {
identifier: identifier
}
})
setHeaderDetail(res)
setDocumentTitle(res?.name || '竞赛')
}
@ -168,6 +171,7 @@ const competitionDetails: FC<PageProps> = ({
async function getrightdatas(item: any) {
setSeleckjey(item.id);
Selectkey = item.id;
setMenuItem(item);
let data ;
if(item.module_type==='entrance'){
@ -193,10 +197,15 @@ const competitionDetails: FC<PageProps> = ({
setMdTab(false)
setItemData(data);
setshowmake(false);
setentrance(false)
setentrance(false);
setIsWorkSubmit(false);
setModelType(item.module_type);
if (item.module_type === "chart") {
if (item.module_type === "worksubmit") {
setIssee(false);
setIsWorkSubmit(true);
getTabResults();
} else if (item.module_type === "chart") {
setIsRanKing(true)
setIssee(false);
getChartRules();
@ -435,7 +444,6 @@ const competitionDetails: FC<PageProps> = ({
async function getTabResults() {
setTabResults(
await dispatch({
type: 'competitions/TabResults',
@ -666,6 +674,7 @@ async function JoinTeams(name: any) {
message.info('加入战队才能查看');
return
}
// if(item?.item?.has_url){
// window.visible(item?.module_url)
// return
@ -679,13 +688,15 @@ async function JoinTeams(name: any) {
</Menu>
</div>
<div className={styles.flex6} style={{padding:(showmake||entrance)&&0}}>
{isAward ? <Award dispatch={dispatch} userid={user?.userInfo?.user_id} Prize={Prize} Accounts={Accounts} getAccounts={getAccounts} /> : null}
{isRanKing ? <RanKing HeaderDetail={HeaderDetail} userinfo={user.userInfo} Editable={HeaderDetail?.permission?.editable} getCharts={getCharts} getChartRules={getChartRules} Selectkey={Selectkey} ChartRules={ChartRules} ItemData={ItemData} /> : null}
{ISsee ? <SeeItem ref={see} StaffDetail={StaffDetail} HeaderDetail={HeaderDetail} userinfo={user.userInfo} Editable={HeaderDetail?.permission?.editable} ItemData={ItemData} setIssee={setIssee} ModelType={ModelType} dispatch={dispatch} /> : null}
{!ISsee &&!showmake&&!entrance&& !isRanKing && !isAward && !MdTab ? <UpItem userinfo={user.userInfo} ModelType={ModelType} getrightdatas={getrightdatas} dispatch={dispatch} MenuItem={MenuItem} setIssee={setIssee} identifier={identifier} ItemData={ItemData} /> : null}
{isAward ? <Award dispatch={dispatch} userid={user?.eduUserInfo?.user_id} Prize={Prize} Accounts={Accounts} getAccounts={getAccounts} /> : null}
{isRanKing ? <RanKing HeaderDetail={HeaderDetail} userinfo={user.eduUserInfo} Editable={HeaderDetail?.permission?.editable} getCharts={getCharts} getChartRules={getChartRules} Selectkey={Selectkey} ChartRules={ChartRules} ItemData={ItemData} /> : null}
{ISsee ? <SeeItem ref={see} StaffDetail={StaffDetail} HeaderDetail={HeaderDetail} userinfo={user.eduUserInfo} Editable={HeaderDetail?.permission?.editable} ItemData={ItemData} setIssee={setIssee} ModelType={ModelType} dispatch={dispatch} /> : null}
{!ISsee &&!showmake&&!entrance&& !isRanKing && !isAward && !MdTab && !isWorkSubmit ? <UpItem userinfo={user.userInfo} ModelType={ModelType} getrightdatas={getrightdatas} dispatch={dispatch} MenuItem={MenuItem} setIssee={setIssee} identifier={identifier} ItemData={ItemData} /> : null}
{MdTab && <SubmitResult dispatch={dispatch} StaffDetail={StaffDetail} userinfo={user.userInfo} HeaderDetail={HeaderDetail} Editable={HeaderDetail?.permission?.editable} getCharts={getResults} getChartRules={getTabResults} Selectkey={Selectkey} ChartRules={TabResults} ItemData={ItemData} />}
{showmake && <MakeItem loading={itLoading} dispatch={dispatch} StaffDetail={StaffDetail} userinfo={user.userInfo} HeaderDetail={HeaderDetail} Editable={HeaderDetail?.permission?.editable} getCharts={getshixunCharts} getChartRules={getTabResults} Selectkey={Selectkey} ChartRules={TabResults} ItemData={ItemData} />}
{entrance&& <Entrance loading={itLoading} dispatch={dispatch} StaffDetail={StaffDetail} userinfo={user.userInfo} HeaderDetail={HeaderDetail} Editable={HeaderDetail?.permission?.editable} getCharts={getEntrance} getChartRules={getTabResults} Selectkey={Selectkey} ChartRules={TabResults} ItemData={ItemData} />}
{/* isWorkSubmit */}
{isWorkSubmit && <WorkSubmit HeaderDetail={HeaderDetail} userinfo={user.eduUserInfo} StaffDetail={StaffDetail} Editable={HeaderDetail?.permission?.editable} ItemData={MenuItem} TabResults={TabResults} getTabResults={getTabResults} />}
</div>
</div>
<AuthModel />

View File

@ -1,5 +1,12 @@
import Fetch from '@/utils/fetch';
import ENV from '@/utils/env';
// 作品提交-作品编辑 /api/competitions/test22/update_result.json
export async function getWorkSubmitUpdateRes(params: any) {
return Fetch(`/api/competitions/${params.identifier}/update_result.json`, {
method: 'post',
body: params,
});
}
//获取在线竞赛列表
export async function getCompetitionsList(params: any) {
return Fetch('/api/competitions.json', {

View File

@ -1,6 +1,6 @@
export const DEV = {
PROXY_SERVER: "https://data.educoder.net",
API_SERVER: "https://pre-data.educoder.net",
API_SERVER: "https://data.educoder.net",
HS_SERVER: "https://www.osredm.com",
REPORT_SERVER: "http://192.168.1.57:3001",
IMG_SERVER: 'https://data.educoder.net',

View File

@ -2,8 +2,7 @@ import { fetch } from 'dva';
import ENV from './env'
import { notification, message, Modal } from 'antd'
import hash from 'hash.js'
import { useDispatch, getDvaApp, history } from 'umi'
import { reportData } from 'monitor-error-ll'
import { getDvaApp, history } from 'umi'
import { getCookie } from './util';
let modalConfirm: any;
const codeMessage: any = {
@ -127,8 +126,8 @@ export default function request(url: string, option: any, flag?: boolean) {
let newOptions = { ...defaultOptions, ...options }
let eduHeader = {
'X-Edu-Signature':'d81315a984e044dd57456b9e675727b6',
'X-Edu-Timestamp':'1722216586532',
'X-Edu-Signature':'ca213221bc2ffc422ce4378296f34eec',
'X-Edu-Timestamp':'1724377167316',
'X-Edu-Type':'pc',
}