banner图片宽度自适应
|
|
@ -11,6 +11,28 @@ export const Competitions = {
|
|||
//竞赛首页
|
||||
path: '/competitions/exports',
|
||||
component: '@/pages/Competitions/Exports/',
|
||||
},{
|
||||
path: '/competitions/2024/information/:id',
|
||||
component: '@/pages/metting/information/detail',
|
||||
},
|
||||
{
|
||||
path: '/competitions/2024',
|
||||
component: '@/pages/metting/banner',
|
||||
routes: [
|
||||
{
|
||||
path: '/competitions/2024',
|
||||
component: '@/pages/metting/home',
|
||||
},{
|
||||
path: '/competitions/2024/organization',
|
||||
component: '@/pages/metting/organization',
|
||||
},{
|
||||
path: '/competitions/2024/track/:id',
|
||||
component: '@/pages/metting/track',
|
||||
},{
|
||||
path: '/competitions/2024/information',
|
||||
component: '@/pages/metting/information',
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
//竞赛首页
|
||||
|
|
|
|||
|
|
@ -1,264 +1,14 @@
|
|||
import { Paperlibrary } from "./paperlibrary";
|
||||
import { Paths } from './path';
|
||||
import { Classrooms } from './classroom';
|
||||
import { Competitions } from './competitions';
|
||||
import { Forums } from './forums';
|
||||
import { Problemset } from './problemset';
|
||||
import { Shiuns } from './shixuns';
|
||||
import { Users } from './users';
|
||||
import { Question } from './question';
|
||||
import { Engineering } from './engineering';
|
||||
import { Metting } from './metting';
|
||||
|
||||
|
||||
const routes = [
|
||||
// { path: '/detail', component: '@/pages/Editor' },
|
||||
{
|
||||
path: "/",
|
||||
component: "@/layouts/index",
|
||||
routes: [
|
||||
// Paperlibrary,
|
||||
// Paths,
|
||||
// Classrooms,
|
||||
Competitions,
|
||||
// Forums,
|
||||
// Problemset,
|
||||
// Shiuns,
|
||||
// Users,
|
||||
// Question,
|
||||
// Engineering,
|
||||
// {
|
||||
// path: '/educoder-demo',
|
||||
// exact: true,
|
||||
// component: '@/pages/Demo/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/otherlogin',
|
||||
// exact: true,
|
||||
// component: '@/pages/User/OtherLogin',
|
||||
// },
|
||||
// {
|
||||
// path: '/otherloginqq',
|
||||
// exact: true,
|
||||
// component: '@/pages/User/QQLogin',
|
||||
// },
|
||||
// {
|
||||
// path: '/otherloginstart',
|
||||
// exact: true,
|
||||
// component: '@/pages/User/WechatLogin',
|
||||
// },
|
||||
// {
|
||||
// path: '/tasks/:taskId',
|
||||
// exact: true,
|
||||
// component: '@/pages/tasks/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/tasks/:identifier/jupyter/',
|
||||
// exact: true,
|
||||
// component: '@/pages/tasks/Jupyter',
|
||||
// },
|
||||
// {
|
||||
// path: '/myproblems/:id/record-detail/:submitId',
|
||||
// exact: true,
|
||||
// component: '@/pages/MyProblem/RecordDetail',
|
||||
// },
|
||||
// {
|
||||
// path: '/myproblems/:id',
|
||||
// exact: true,
|
||||
// component: '@/pages/MyProblem/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/login',
|
||||
// component: '@/layouts/user',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/login',
|
||||
// component: '@/pages/User/Login',
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/user',
|
||||
// component: '@/layouts/user',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/user/login',
|
||||
// component: '@/pages/User/Login',
|
||||
// },
|
||||
// {
|
||||
// path: '/user/register',
|
||||
// component: '@/pages/User/Register',
|
||||
// },
|
||||
// {
|
||||
// path: '/user/reset-password',
|
||||
// component: '@/pages/User/ResetPassword',
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
|
||||
// {
|
||||
// path: '/account',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/account/:username',
|
||||
// component: '@/pages/Account',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/account/profile',
|
||||
// component: '@/pages/Account/Profile/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/account/profile/edit',
|
||||
// component: '@/pages/Account/Profile/Edit/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/account/certification',
|
||||
// component: '@/pages/Account/Certification/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/account/secure',
|
||||
// component: '@/pages/Account/Secure/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/account/binding',
|
||||
// component: '@/pages/Account/Binding/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/account/Results',
|
||||
// component: '@/pages/Account/Results/index',
|
||||
// },
|
||||
// // {
|
||||
// // path: '/account/teach-group',
|
||||
// // component: '@/pages/Account/TeachGroup/index',
|
||||
// // },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: "/ch/:id",
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: "/ch/rest/edit/:categoryId/:id",
|
||||
// // component:"@/pages/RestFul",
|
||||
// component: "@/pages/RestFul/Edit/index",
|
||||
// exact: true,
|
||||
// }, {
|
||||
// path: "/ch/rest/",
|
||||
// exact: true,
|
||||
// component: "@/pages/RestFul"
|
||||
// }, {
|
||||
// path: "/ch/rest/:id",
|
||||
// component: "@/pages/RestFul",
|
||||
// exact: true,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
|
||||
// {
|
||||
// path: '/order',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/order',
|
||||
// component: '@/pages/User/Detail/Order/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/order/:courseId/information',
|
||||
// component: '@/pages/User/Detail/Order/pages/orderInformation/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/order/:courseId/pay',
|
||||
// component: '@/pages/User/Detail/Order/pages/orderPay/index',
|
||||
// },
|
||||
// {
|
||||
// path: '/order/:orderNum/result',
|
||||
// component: '@/pages/User/Detail/Order/pages/result/index',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/colleges',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/colleges/:id/statistics',
|
||||
// component: '@/pages/Colleges/index',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/help',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/help/:id',
|
||||
// component: '@/pages/Help/Index',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/messages',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/messages/:userId/user_tidings',
|
||||
// component: '@/pages/Messages/Tidings',
|
||||
// },
|
||||
// {
|
||||
// path: '/messages/:userId/private_messages',
|
||||
// component: '@/pages/Messages/Private',
|
||||
// },
|
||||
// {
|
||||
// path: '/messages/:userId/message_detail',
|
||||
// component: '@/pages/Messages/Detail',
|
||||
// }
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/video',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/video/:videoId',
|
||||
// component: '@/pages/Video/Detail/[id]',
|
||||
// }
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: "/terminal",
|
||||
// component: '@/pages/Terminal/'
|
||||
// },
|
||||
// { path: '/detail', component: '@/pages/Editor' },
|
||||
// {
|
||||
// path: '/',
|
||||
// component: '@/layouts/SimpleLayouts',
|
||||
// routes: [
|
||||
// { path: '/', exact: true, component: '@/pages/index' },
|
||||
// { path: '/api/*', component: '@/pages/Api', exact: true },
|
||||
// { path: '/search', exact: true, component: '@/pages/Search/index' },
|
||||
// { path: '/moop_cases', exact: true, component: '@/pages/MoopCases/index' },
|
||||
// { path: '/moop_cases/new', exact: true, component: '@/pages/MoopCases/FormPanel' },
|
||||
// { path: '/moop_cases/:caseId', exact: true, component: '@/pages/MoopCases/InfoPanel' },
|
||||
// { path: '/moop_cases/:caseId/edit', exact: true, component: '@/pages/MoopCases/FormPanel' },
|
||||
// { path: '/moop_cases/:caseId/publish-success', exact: true, component: '@/pages/MoopCases/Success' },
|
||||
// // { path: "/randompaper", exact: true, component: "@/pages/Paperlibrary/Random/Add/index" },
|
||||
// { path: "/randompaper", exact: true, component: "@/pages/Paperlibrary/Random/AddAndEdit/index" },
|
||||
// { path: "/randompaper/edit/:id", exact: true, component: "@/pages/Paperlibrary/Random/AddAndEdit/index" },
|
||||
// // { path: "/randompaper/edit/:id", exact: true, component: "@/pages/Paperlibrary/Random/Edit/index" },
|
||||
// { path: "/randompaper/detail/:id", exact: true, component: "@/pages/Paperlibrary/Random/Detail/index" },
|
||||
// { path: '/403', component: '@/pages/HttpStatus/403' },
|
||||
// { path: '/500', component: '@/pages/HttpStatus/500' },
|
||||
// { path: '/404', component: '@/pages/HttpStatus/404' },
|
||||
// { path: '/iwce', component: '@/pages/HttpStatus/HpcCourse' },
|
||||
// { path: '/iwce/:itemname', component: '@/pages/HttpStatus/HpcCourse' },
|
||||
// { path: '/hpc-course', component: '@/pages/HttpStatus/HpcCourse' },
|
||||
// { path: '/user_agents', component: '@/pages/HttpStatus/UserAgents' },
|
||||
// { path: '/three', component: '@/pages/Three' },
|
||||
// { component: '@/pages/HttpStatus/404' }
|
||||
// ],
|
||||
// }
|
||||
// Metting
|
||||
]
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
export const Metting = {
|
||||
path: '/2024',
|
||||
component: '@/layouts/SimpleLayouts',
|
||||
routes: [
|
||||
{
|
||||
path: '/2024/information/:id',
|
||||
component: '@/pages/metting/information/detail',
|
||||
},
|
||||
{
|
||||
path: '/2024',
|
||||
component: '@/pages/metting/banner',
|
||||
routes: [
|
||||
{
|
||||
path: '/2024',
|
||||
component: '@/pages/metting/home',
|
||||
},{
|
||||
path: '/2024/organization',
|
||||
component: '@/pages/metting/organization',
|
||||
},{
|
||||
path: '/2024/track/:id',
|
||||
component: '@/pages/metting/track',
|
||||
},{
|
||||
path: '/2024/information',
|
||||
component: '@/pages/metting/information',
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
"animate.css": "4.1.1",
|
||||
"antd": "4.6.1",
|
||||
"array-move": "3.0.1",
|
||||
"axios": "^1.6.8",
|
||||
"checkapi.js": "^0.1.2",
|
||||
"code-prettify": "0.1.0",
|
||||
"codemirror": "5.58.2",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import marked, {
|
|||
cleanToc,
|
||||
getMathExpressions,
|
||||
resetMathExpressions,
|
||||
lines,
|
||||
lines
|
||||
} from '@/utils/marked';
|
||||
import 'code-prettify';
|
||||
import Hls from 'hls.js';
|
||||
|
|
@ -37,21 +37,8 @@ export default ({
|
|||
}: IProps) => {
|
||||
let str = String(value);
|
||||
const [data, setData] = useState("")
|
||||
|
||||
|
||||
const html = useMemo(() => {
|
||||
try {
|
||||
const reg = /\(\s+\/api\/attachments\/|\(\/api\/attachments\/|\(\/attachments\/download\//g;
|
||||
const reg2 = /\"\/api\/attachments\/|\"\/attachments\/download\//g;
|
||||
const reg3 = /\(\s+\/files\/uploads\/|\(\/files\/uploads\//g;
|
||||
str = str.replace(reg, "(" + ENV.API_SERVER + "/api/attachments/")
|
||||
.replace(reg2, '"' + ENV.API_SERVER + "/api/attachments/")
|
||||
.replace(reg3, '"' + ENV.API_SERVER + "/files/uploads/")
|
||||
.replaceAll("http://video.educoder", "https://video.educoder")
|
||||
.replaceAll("http://www.educoder.net/api", "https://data.educoder.net/api")
|
||||
.replaceAll("https://www.educoder.net/api", "https://data.educoder.net/api")
|
||||
.replace(/\r\n/g,"\n")
|
||||
str = str.replace(new RegExp("(?<!\\n)\\n(?!\\n)", "g"), " \n")
|
||||
} catch (e) { };
|
||||
let rs = marked(str)
|
||||
|
||||
const math_expressions = getMathExpressions();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
@font-face {
|
||||
font-family: YouSheBiaoTiHei;
|
||||
src: url(../../public/font/YouSheBiaoTiHei-2.ttf);
|
||||
}
|
||||
.loading {
|
||||
position: fixed !important;
|
||||
top: 50% !important;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ interface CompetitionsParamsType {
|
|||
page: number, //第一页开始
|
||||
per_page: number, //每页条数,默认20
|
||||
category: any, //分类筛选,”nearly_published”,”progressing”, “ended”
|
||||
external:string
|
||||
}
|
||||
export interface CompetitionsType {
|
||||
namespace: string;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { getDirList , getBaseInfo } from '../pages/metting/api';
|
||||
|
||||
export default function Page() {
|
||||
const [dirList, setDirList] = useState({});
|
||||
const [mainInfo, setMainInfo] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
getDirList().then((res) => {
|
||||
if (res && res.rows.length > 0) {
|
||||
let idList = {}
|
||||
res.rows.map(e => {
|
||||
idList[e.name] = e.id
|
||||
})
|
||||
setDirList(idList);
|
||||
}
|
||||
});
|
||||
getBaseInfo().then(result => {
|
||||
setMainInfo(result.data);
|
||||
}).catch(console.error())
|
||||
}, []);
|
||||
|
||||
return {
|
||||
dirList,mainInfo
|
||||
};
|
||||
};
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
@import '../../global.less';
|
||||
|
||||
.bg {
|
||||
background: rgba(250, 250, 250, 1);
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 240px;
|
||||
.flex_box_container();
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
background-image: url('../../assets/images/statistics.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
div[class~='ant-row'] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.headerContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 1300px;
|
||||
width: 1300px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.headTitle {
|
||||
flex: 1 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #4cacff;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.headItemTitle {
|
||||
color: #989898;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.headItemValue {
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: 1300px;
|
||||
background-color: #fff;
|
||||
margin: 0px auto;
|
||||
margin-top: 30px;
|
||||
|
||||
ul[class~='ant-pagination'] {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[class~='ant-table-row'] {
|
||||
[class~='ant-table-cell'] {
|
||||
color: #05101a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.basicTitle {
|
||||
line-height: 1.2;
|
||||
padding: 2rem 1.25rem;
|
||||
border-bottom: unset;
|
||||
background: #fff;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.basicHead {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
p {
|
||||
width: 217px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
color: #686868;
|
||||
background: #f5f5f5;
|
||||
border-top: 1px solid #ebebeb;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.basicContent {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.basicItem {
|
||||
width: 217px;
|
||||
text-align: center;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
background: #ffffff;
|
||||
border-top: 1px solid #ebebeb;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
color: #000000;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.basicItemText {
|
||||
color: #000000;
|
||||
margin-left: 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.courseLoading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.maxWidth220 {
|
||||
max-width: 220px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.maxWidth340 {
|
||||
max-width: 340px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.maxWidth175 {
|
||||
max-width: 175px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.maxWidth225 {
|
||||
max-width: 225px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.maxWidth255 {
|
||||
max-width: 255px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.maxWidth105 {
|
||||
max-width: 105px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.colorFFC {
|
||||
color: #ffc107;
|
||||
}
|
||||
|
||||
.colorBlack {
|
||||
color: rgb(5, 16, 26);
|
||||
}
|
||||
|
||||
.colorGreen {
|
||||
color: rgb(23, 162, 184);
|
||||
}
|
||||
|
||||
.color4CA {
|
||||
color: #4cacff;
|
||||
}
|
||||
|
||||
.rankLeft {
|
||||
width: 63%;
|
||||
}
|
||||
|
||||
.rankRight {
|
||||
width: 37%;
|
||||
}
|
||||
|
||||
.flexRow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
|
@ -1,549 +0,0 @@
|
|||
import React, { FC, useEffect, useState } from 'react';
|
||||
import {
|
||||
ShixunsDetailModelState,
|
||||
GlobalSettingModelState,
|
||||
ConnectProps,
|
||||
Loading,
|
||||
connect,
|
||||
Dispatch,
|
||||
useParams
|
||||
} from 'umi';
|
||||
import { Row, Col, Spin, Table ,Pagination} from "antd";
|
||||
import NoData from '@/components/NoData';
|
||||
import {
|
||||
getCollegesStatistics, getShixunReportCount, getShixunTime, getCourseStatistics,
|
||||
getTeacherRanking, getStudentRanking, getShixunChart, getStudentHot
|
||||
} from '@/service/colleges';
|
||||
import {
|
||||
teacherRankingColums, studentRankingColums,
|
||||
getTeacherRankingEchartOption, getStudentRankingEchartOption
|
||||
} from './utils';
|
||||
import ReactEcharts from "echarts-for-react";
|
||||
import styles from "./index.less";
|
||||
import { setDocumentTitle } from '@/utils/util'
|
||||
|
||||
interface PageProps extends ConnectProps {
|
||||
shixunsDetail: ShixunsDetailModelState;
|
||||
globalSetting: GlobalSettingModelState;
|
||||
loading: boolean;
|
||||
dispatch: Dispatch;
|
||||
}
|
||||
|
||||
const CollegesPage: FC<PageProps> = ({
|
||||
shixunsDetail,
|
||||
globalSetting,
|
||||
loading,
|
||||
dispatch,
|
||||
...props
|
||||
}) => {
|
||||
const params = useParams<any>();
|
||||
const [headData, setHeadData] = useState<any>({});
|
||||
const [shixunReportCount, setShixunReportCount] = useState<number>();
|
||||
const [shixunTime, setShixunTime] = useState<number>();
|
||||
const [courseStatistics, setCourseStatistics] = useState<any>();
|
||||
const [teacherRanking, setTeacherRanking] = useState<any>();
|
||||
const [studentRanking, setStudentRanking] = useState<any>();
|
||||
const [shixunChartData, setShixunChartData] = useState<any[]>();
|
||||
const [shixunChartDataName, setshixunChartDataName] = useState<any[]>();
|
||||
const [studentHotValue, setStudentHotValue] = useState<any[]>();
|
||||
const [studentHotName, setStudentHotName] = useState<any[]>();
|
||||
const [page, setPage] = useState<number>(1);
|
||||
const [isLoadingCourse, setIsLoadingCourse] = useState<boolean>(false);
|
||||
const [isLoadingTeacher, setIsLoadingTeacher] = useState<boolean>(false);
|
||||
const [isLoadingStudent, setIsLoadingStudent] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDocumentTitle('学院统计')
|
||||
if (!params.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
getHeadData();
|
||||
getShixunReportCountData();
|
||||
getShixunTimeData();
|
||||
getTeacherRankingData(1, 10);
|
||||
getStudentRankingData(1, 10);
|
||||
getShixunChartData();
|
||||
getStudentHotData();
|
||||
getCourseStatisticsData(1, 10);
|
||||
|
||||
|
||||
}, [params.id]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const getHeadData = async () => {
|
||||
const res = await getCollegesStatistics({ id: params.id });
|
||||
setDocumentTitle(res?.school || '头歌实践教学平台')
|
||||
setHeadData(res || {});
|
||||
}
|
||||
|
||||
const getShixunReportCountData = async () => {
|
||||
const res = await getShixunReportCount({ id: params.id });
|
||||
setShixunReportCount(res?.shixun_report_count || 0);
|
||||
}
|
||||
|
||||
const getShixunTimeData = async () => {
|
||||
const res = await getShixunTime({ id: params.id });
|
||||
setShixunTime(res?.shixun_time || 0);
|
||||
}
|
||||
|
||||
const getCourseStatisticsData = async (page: number, per_page: number) => {
|
||||
setIsLoadingCourse(true);
|
||||
const res = await getCourseStatistics({ id: params.id, page, per_page,...params }).catch(e => setIsLoadingCourse(false));
|
||||
setIsLoadingCourse(false);
|
||||
setCourseStatistics(res || []);
|
||||
}
|
||||
|
||||
const getTeacherRankingData = async (page: number, per_page: number) => {
|
||||
setIsLoadingTeacher(true);
|
||||
const res = await getTeacherRanking({ id: params.id, page, per_page }).catch(e => setIsLoadingTeacher(false));
|
||||
setIsLoadingTeacher(false);
|
||||
setTeacherRanking(res || []);
|
||||
}
|
||||
|
||||
const getStudentRankingData = async (page: number, per_page: number) => {
|
||||
setIsLoadingStudent(true);
|
||||
const res = await getStudentRanking({ id: params.id, page, per_page }).catch(e => setIsLoadingStudent(false));
|
||||
setIsLoadingStudent(false);
|
||||
setStudentRanking(res || []);
|
||||
}
|
||||
|
||||
const getShixunChartData = async () => {
|
||||
const res = await getShixunChart({ id: params.id });
|
||||
setShixunChartData(res?.data || []);
|
||||
setshixunChartDataName(res?.names || []);
|
||||
}
|
||||
|
||||
const getStudentHotData = async () => {
|
||||
const res = await getStudentHot({ id: params.id });
|
||||
setStudentHotValue(res?.values || []);
|
||||
setStudentHotName(res?.names || []);
|
||||
}
|
||||
|
||||
const courseStatisticsColums: any = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
className: styles.maxWidth220,
|
||||
render: (text: any, record: any) => (
|
||||
<a href={`/classrooms/${record.id}/students`} title={record.name} target="_blank">
|
||||
{
|
||||
record.name
|
||||
}
|
||||
</a>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '管理教师',
|
||||
dataIndex: 'teachers',
|
||||
key: 'teachers',
|
||||
align: 'center',
|
||||
className: styles.maxWidth340,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} title={record.teachers}>
|
||||
{
|
||||
record.teachers
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '评测次数',
|
||||
dataIndex: 'times',
|
||||
key: 'evaluating_count',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "evaluating_count" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
className: styles.maxWidth175,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} >
|
||||
{
|
||||
record.evaluating_count
|
||||
}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '学生',
|
||||
key: 'student_count',
|
||||
dataIndex: 'student',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "student_count" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
className: styles.maxWidth225,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} >
|
||||
{
|
||||
record.student_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '实训作业',
|
||||
dataIndex: 'training',
|
||||
key: 'shixun_work_count',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "shixun_work_count" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} >
|
||||
{
|
||||
record.shixun_work_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
|
||||
},
|
||||
{
|
||||
title: '资源',
|
||||
dataIndex: 'resources',
|
||||
key: 'attachments_count',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "attachments_count" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
render: (text: any, record: any) => (
|
||||
|
||||
<span className={styles.colorBlack} >
|
||||
|
||||
{
|
||||
record?.attachments_count
|
||||
}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '帖子',
|
||||
dataIndex: 'posts',
|
||||
key: 'message_count',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "message_count" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} >
|
||||
{
|
||||
record.message_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '其它任务',
|
||||
dataIndex: 'othertasks',
|
||||
key: 'other_work_count',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "other_work_count" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} >
|
||||
{
|
||||
record.other_work_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'states',
|
||||
key: 'states',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span className={record.is_end ? styles.colorBlack : styles.colorFFC}>
|
||||
{
|
||||
record.is_end ?
|
||||
"已结束" :
|
||||
"正在进行"
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '最新活跃时间',
|
||||
dataIndex: 'timemy',
|
||||
key: 'activity_time',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
showSorterTooltip: false,
|
||||
sortOrder:params.sort_name === "activity_time" ? (params.sort === 2 ? "descend" : "ascend") : null,
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorBlack} >
|
||||
{
|
||||
record.activity_time
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
];
|
||||
|
||||
return <section className={styles.bg}>
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerContent}>
|
||||
<div className={styles.headTitle}>{headData?.school}</div>
|
||||
<Row justify="space-around" gutter={[40, 0]}>
|
||||
<Col span={4} className="tc">
|
||||
<p className={styles.headItemTitle}>教师</p>
|
||||
<p className={styles.headItemValue}>{headData?.teachers_count || 0}</p>
|
||||
</Col>
|
||||
<Col span={4} className="tc">
|
||||
<p className={styles.headItemTitle}>学生</p>
|
||||
<p className={styles.headItemValue}>{headData?.students_count || 0}</p>
|
||||
</Col>
|
||||
<Col span={4} className="tc">
|
||||
<p className={styles.headItemTitle}>课堂</p>
|
||||
<p className={styles.headItemValue}>{headData?.courses_count || 0}</p>
|
||||
</Col>
|
||||
<Col span={4} className="tc">
|
||||
<p className={styles.headItemTitle}>共建实训</p>
|
||||
<p className={styles.headItemValue}>{headData?.shixuns_count || 0}</p>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className={styles.wrap}>
|
||||
<div className={styles.basicTitle}>基本使用情况</div>
|
||||
<div className={styles.basicHead}>
|
||||
<p>教师</p>
|
||||
<p>学生</p>
|
||||
<p>课堂</p>
|
||||
<p>共建实训</p>
|
||||
<p>实训报告</p>
|
||||
<p>学员实战时间</p>
|
||||
</div>
|
||||
<div className={styles.basicContent}>
|
||||
<div className={styles.basicItem}>
|
||||
{
|
||||
headData?.teachers_count || headData?.teachers_count === 0 ?
|
||||
<>
|
||||
{headData?.teachers_count}
|
||||
<span className={styles.basicItemText}>人</span>
|
||||
</> :
|
||||
<Spin />
|
||||
}
|
||||
</div>
|
||||
<div className={styles.basicItem}>
|
||||
{
|
||||
headData?.students_count || headData?.students_count === 0 ?
|
||||
<>
|
||||
{headData?.students_count}
|
||||
<span className={styles.basicItemText}>人</span>
|
||||
</> :
|
||||
<Spin />
|
||||
}
|
||||
</div>
|
||||
<div className={styles.basicItem}>
|
||||
{
|
||||
headData?.courses_count || headData?.courses_count === 0 ?
|
||||
<>
|
||||
{headData?.courses_count}
|
||||
<span className={styles.basicItemText}>个</span>
|
||||
</> :
|
||||
<Spin />
|
||||
}
|
||||
</div>
|
||||
<div className={styles.basicItem}>
|
||||
{
|
||||
headData?.shixuns_count || headData?.shixuns_count === 0 ?
|
||||
<>
|
||||
{headData?.shixuns_count}
|
||||
<span className={styles.basicItemText}>个</span>
|
||||
</> :
|
||||
<Spin />
|
||||
}
|
||||
</div>
|
||||
<div className={styles.basicItem}>
|
||||
{
|
||||
shixunReportCount || shixunReportCount === 0 ?
|
||||
<>
|
||||
{shixunReportCount}
|
||||
<span className={styles.basicItemText}>个</span>
|
||||
</> :
|
||||
<Spin />
|
||||
}
|
||||
</div>
|
||||
<div className={styles.basicItem}>
|
||||
{
|
||||
shixunTime || shixunTime === 0 ?
|
||||
<>
|
||||
{shixunTime}
|
||||
<span className={styles.basicItemText}>分钟</span>
|
||||
</> :
|
||||
<Spin />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.wrap}>
|
||||
<div className={styles.basicTitle}>课堂</div>
|
||||
{
|
||||
!courseStatistics &&
|
||||
<div className={styles.courseLoading}>
|
||||
<Spin tip="正在加载..." />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
courseStatistics &&
|
||||
(
|
||||
courseStatistics?.courses?.length ?
|
||||
<Table
|
||||
columns={courseStatisticsColums}
|
||||
dataSource={courseStatistics?.courses}
|
||||
loading={isLoadingCourse}
|
||||
onChange={(a, b, c: any)=>{
|
||||
params.sort_name=c?.columnKey;
|
||||
if (c.order === 'ascend') params['sort'] = 1;
|
||||
if (c.order === 'descend') params['sort'] = 2;
|
||||
if (!c.order) {
|
||||
params['sort'] = 1
|
||||
};
|
||||
setPage(1);
|
||||
getCourseStatisticsData(1,10);
|
||||
}}
|
||||
pagination={false}
|
||||
// pagination={{
|
||||
// current: page,
|
||||
// pageSize: 10,
|
||||
// showQuickJumper: true,
|
||||
// showSizeChanger: false,
|
||||
// total: courseStatistics?.course_count,
|
||||
// onChange: (page, pageSize) => {
|
||||
// setPage(page);
|
||||
// getCourseStatisticsData(page, 10);
|
||||
// }
|
||||
// }}
|
||||
/> :
|
||||
|
||||
<NoData />
|
||||
)
|
||||
}
|
||||
<Pagination current={page}
|
||||
style={{marginTop:'20px'}}
|
||||
pageSize={10} showQuickJumper
|
||||
showSizeChanger={false}
|
||||
total={courseStatistics?.course_count}
|
||||
onChange={(page,pagesize)=>{
|
||||
setPage(page);
|
||||
getCourseStatisticsData(page, 10);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={`${styles.wrap} ${styles.flexRow}`}>
|
||||
<div className={styles.rankLeft}>
|
||||
<div className={styles.basicTitle}>教师排名</div>
|
||||
{
|
||||
!teacherRanking &&
|
||||
<div className={styles.courseLoading}>
|
||||
<Spin tip="正在加载..." />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
teacherRanking &&
|
||||
(
|
||||
teacherRanking?.teachers?.length ?
|
||||
<Table
|
||||
columns={teacherRankingColums}
|
||||
dataSource={teacherRanking?.teachers}
|
||||
loading={isLoadingTeacher}
|
||||
pagination={false}
|
||||
/> :
|
||||
<NoData />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className={styles.rankRight}>
|
||||
<div className={styles.basicTitle}>在线实训情况</div>
|
||||
{
|
||||
!shixunChartData &&
|
||||
<div className={styles.courseLoading}>
|
||||
<Spin tip="正在加载..." />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
shixunChartData &&
|
||||
(
|
||||
shixunChartData?.length ?
|
||||
<ReactEcharts
|
||||
option={getTeacherRankingEchartOption(shixunChartData, shixunChartDataName)}
|
||||
style={{ height: 600 }}
|
||||
opts={{ renderer: 'svg' }}
|
||||
/> :
|
||||
<NoData />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={`${styles.wrap} ${styles.flexRow}`}>
|
||||
<div className={styles.rankLeft}>
|
||||
<div className={styles.basicTitle}>学生排名</div>
|
||||
{
|
||||
!studentRanking &&
|
||||
<div className={styles.courseLoading}>
|
||||
<Spin tip="正在加载..." />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
studentRanking &&
|
||||
(
|
||||
studentRanking?.teachers?.length ?
|
||||
<Table
|
||||
columns={studentRankingColums}
|
||||
dataSource={studentRanking?.teachers}
|
||||
loading={isLoadingStudent}
|
||||
pagination={false}
|
||||
/> :
|
||||
<NoData />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className={styles.rankRight}>
|
||||
<div className={styles.basicTitle}>最热评测</div>
|
||||
{
|
||||
!studentHotName &&
|
||||
<div className={styles.courseLoading}>
|
||||
<Spin tip="正在加载..." />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
studentHotName &&
|
||||
(
|
||||
studentHotName?.length ?
|
||||
<ReactEcharts
|
||||
option={getStudentRankingEchartOption(studentHotName, studentHotValue)}
|
||||
style={{ height: 600 }}
|
||||
opts={{ renderer: 'svg' }}
|
||||
/> :
|
||||
<NoData />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
};
|
||||
|
||||
export default connect(({
|
||||
shixunsDetail,
|
||||
loading,
|
||||
globalSetting
|
||||
}: {
|
||||
shixunsDetail: ShixunsDetailModelState;
|
||||
loading: Loading;
|
||||
globalSetting: GlobalSettingModelState;
|
||||
}) => ({
|
||||
shixunsDetail,
|
||||
globalSetting,
|
||||
loading: loading.models.index,
|
||||
}))(CollegesPage);
|
||||
|
|
@ -1,351 +0,0 @@
|
|||
import React from 'react';
|
||||
import ENV from '@/utils/env';
|
||||
import styles from './index.less';
|
||||
|
||||
|
||||
|
||||
export const teacherRankingColums: any = [
|
||||
{
|
||||
title: '排名',
|
||||
dataIndex: 'ranking',
|
||||
key: 'ranking',
|
||||
align: 'center',
|
||||
render: (text: any, record: any, index: number) => (
|
||||
index + 1
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
className: styles.maxWidth105,
|
||||
render: (text: any, record: any) => (
|
||||
<a href={`/users/${record.login}`} title={record.name} target="_blank">
|
||||
{
|
||||
record.name
|
||||
}
|
||||
</a>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '管理课堂',
|
||||
dataIndex: 'classroom',
|
||||
key: 'classroom',
|
||||
align: 'center',
|
||||
className: styles.maxWidth175,
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.course_count
|
||||
}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '已发布实训作业',
|
||||
key: 'assignment',
|
||||
dataIndex: 'assignment',
|
||||
align: 'center',
|
||||
className: styles.maxWidth255,
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.shixun_work_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '未发布实训作业',
|
||||
dataIndex: 'released',
|
||||
key: 'released',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.un_shixun_work_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
|
||||
},
|
||||
{
|
||||
title: '学生数',
|
||||
dataIndex: 'studentnumber',
|
||||
key: 'studentnumber',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.student_count
|
||||
}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '完成率',
|
||||
dataIndex: 'completionrate',
|
||||
key: 'completionrate',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.complete_rate + "%"
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '发布实训',
|
||||
dataIndex: 'releasetraining',
|
||||
key: 'releasetraining',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.color4CA}>
|
||||
{
|
||||
record.publish_shixun_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const renderStudentRanking = (key: number) => {
|
||||
const image = `${ENV.IMG_SERVER}/images/educoder/competition/${key}.png`;
|
||||
const mapping: any = {
|
||||
1: <img width="18px" height="22px" className="mt5" src={image} />,
|
||||
2: <img width="18px" height="22px" className="mt5" src={image} />,
|
||||
3: <img width="18px" height="22px" className="mt5" src={image} />,
|
||||
}
|
||||
|
||||
return mapping[key] || key;
|
||||
}
|
||||
|
||||
export const studentRankingColums: any = [
|
||||
{
|
||||
title: '排名',
|
||||
dataIndex: 'ranking',
|
||||
key: 'ranking',
|
||||
align: 'center',
|
||||
className: "edu-txt-center font-14",
|
||||
width: '100px',
|
||||
render: (text: any, record: any, index: number) => (
|
||||
<span>
|
||||
{
|
||||
renderStudentRanking(index + 1)
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
className: styles.maxWidth105,
|
||||
render: (text: any, record: any) => (
|
||||
<a href={`/users/${record.login}`} title={record.name} target="_blank">
|
||||
{
|
||||
record.name
|
||||
}
|
||||
</a>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '学号',
|
||||
dataIndex: 'studentid',
|
||||
key: 'studentid',
|
||||
align: 'center',
|
||||
className: styles.maxWidth175,
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.student_id
|
||||
}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '完成实训',
|
||||
key: 'training',
|
||||
dataIndex: 'training',
|
||||
align: 'center',
|
||||
className: styles.maxWidth225,
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.shixun_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '在学实训',
|
||||
dataIndex: 'learning',
|
||||
key: 'learning',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.study_shixun_count
|
||||
}
|
||||
</span>
|
||||
)
|
||||
|
||||
},
|
||||
{
|
||||
title: '金币',
|
||||
dataIndex: 'goldcoin',
|
||||
key: 'goldcoin',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span>
|
||||
{
|
||||
record.grade
|
||||
}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '经验值',
|
||||
dataIndex: 'empirical',
|
||||
key: 'empirical',
|
||||
align: 'center',
|
||||
render: (text: any, record: any) => (
|
||||
<span className={styles.colorGreen}>
|
||||
{
|
||||
record.experience
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
];
|
||||
|
||||
export const getTeacherRankingEchartOption = (data: any[] = [], dataName: any[] = []) => {
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: "{d}% <br/>"
|
||||
},
|
||||
legend: {
|
||||
bottom: 50,
|
||||
left: 'center',
|
||||
data: dataName
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '65%',
|
||||
center: ['50%', '35%'],
|
||||
selectedMode: 'single',
|
||||
data: data,
|
||||
itemStyle: {
|
||||
emphasis: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export const getStudentRankingEchartOption = (names: any[] = [], values: any[] = []) => {
|
||||
const colorList = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967'];
|
||||
|
||||
return {
|
||||
backgroundColor: '#fff',
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '8%',
|
||||
bottom: '15%',
|
||||
containLabel: true
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
show: "true",
|
||||
trigger: 'item',
|
||||
formatter: '{c0}',
|
||||
backgroundColor: 'rgba(0,0,0,0.7)', // 背景
|
||||
padding: [8, 10], //内边距
|
||||
extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
|
||||
axisPointer: { // 坐标轴指示器,坐标轴触发有效
|
||||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#CCCCCC'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#CCCCCC'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#656565',
|
||||
fontWeight: 'normal',
|
||||
fontSize: '12'
|
||||
},
|
||||
formatter: '{value}'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#cccccc'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
inside: false,
|
||||
textStyle: {
|
||||
color: '#656565',
|
||||
fontWeight: 'normal',
|
||||
fontSize: '12'
|
||||
}
|
||||
},
|
||||
data: names
|
||||
},
|
||||
series: [{
|
||||
name: '',
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
show: true,
|
||||
color: function (params: any) {
|
||||
return colorList[params.dataIndex]
|
||||
},
|
||||
barBorderRadius: 50,
|
||||
borderWidth: 0,
|
||||
borderColor: '#333'
|
||||
}
|
||||
},
|
||||
barGap: '0%',
|
||||
barCategoryGap: '50%',
|
||||
data: values
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ const competitionsIndexPage: FC<PageProps> = ({
|
|||
// getHomeNotice();
|
||||
dispatch({
|
||||
type: 'competitions/getList',
|
||||
payload: { ...competitions.listParams},
|
||||
payload: { ...competitions.listParams,external:"gitlink"},
|
||||
});
|
||||
}, [competitions.name]);
|
||||
useEffect(() => {
|
||||
|
|
@ -412,6 +412,7 @@ const competitionsIndexPage: FC<PageProps> = ({
|
|||
competitions.listParams.page = 1;
|
||||
competitions.listParams.category = v;
|
||||
competitions.listParams.page = 1;
|
||||
competitions.listParams.external = "gitlink";
|
||||
dispatch({
|
||||
type: 'competitions/getList',
|
||||
payload: { ...competitions.listParams },
|
||||
|
|
|
|||
|
|
@ -1,186 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { Input, Form, Button, Checkbox, Upload, message, Modal } from 'antd'
|
||||
import { InboxOutlined } from '@ant-design/icons'
|
||||
import ENV from '@/utils/env'
|
||||
import { Tag } from '../index'
|
||||
import MarkdownEditor from '@/components/markdown-editor'
|
||||
|
||||
const CheckboxGroup = Checkbox.Group
|
||||
const { Dragger } = Upload
|
||||
|
||||
function getBase64(img: any, callback: any) {
|
||||
const reader = new FileReader()
|
||||
reader.addEventListener('load', () => callback(reader.result))
|
||||
reader.readAsDataURL(img)
|
||||
}
|
||||
|
||||
interface IMoopCase {
|
||||
callback: any
|
||||
tags: Array<Tag>
|
||||
initialValues: any
|
||||
removeAttachment: (id: any) => Promise<boolean>
|
||||
}
|
||||
|
||||
export default ({ callback, tags = [], initialValues = {}, removeAttachment }: IMoopCase) => {
|
||||
const [uploadUrl, setUploadUrl] = useState<string>('')
|
||||
const [form] = Form.useForm()
|
||||
function onSubmit(values: any) {
|
||||
const { cover_id, attachment_ids, ...rest } = values
|
||||
callback({
|
||||
...rest,
|
||||
cover_id: cover_id?.map((item: any) => item.response ? item.response.id : item.uid)[cover_id?.length -1],
|
||||
attachment_ids: attachment_ids ? attachment_ids?.map((item: any) => item.response ? item.response.id : item.uid) : []
|
||||
})
|
||||
}
|
||||
|
||||
function normFile(e) {
|
||||
if (Array.isArray(e)) {
|
||||
return e
|
||||
}
|
||||
return e && e.fileList
|
||||
}
|
||||
const uploadProps = {
|
||||
multiple: true,
|
||||
beforeUpload: (file: any) => {
|
||||
const isLt150M = file.size / 1024 / 1024 < 100
|
||||
if (!isLt150M) {
|
||||
message.error('该文件无法上传。超过文件大小限制(100MB),建议上传到百度云等其它共享工具里,然后再txt文档里给出链接以及共享密码并上传')
|
||||
return isLt150M
|
||||
}
|
||||
},
|
||||
action: `${ENV.API_SERVER}/api/attachments.json`,
|
||||
onRemove: (file: any) => {
|
||||
Modal.confirm({
|
||||
centered: true,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
content: '是否确认删除?',
|
||||
onOk: () => {
|
||||
return removeAttachment(file.response ? file.response.id : file.uid)
|
||||
},
|
||||
onCancel: () => {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeCoverUrl(info: any) {
|
||||
if (info.file.status === 'done') {
|
||||
getBase64(info.file.originFileObj, (imageUrl: string) =>
|
||||
setUploadUrl(imageUrl)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const uploadCoverProps = {
|
||||
showUploadList: false,
|
||||
withCredentials:true,
|
||||
action: `${ENV.API_SERVER}/api/attachments.json`,
|
||||
|
||||
onChange: onChangeCoverUrl
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (initialValues.title) {
|
||||
form.setFieldsValue(initialValues)
|
||||
if(initialValues.cover_id.length>0){
|
||||
setUploadUrl( ENV.IMG_SERVER + initialValues.cover_id[0].url)
|
||||
}
|
||||
}
|
||||
}, [initialValues])
|
||||
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
initialValues={initialValues}
|
||||
className="moop-panel"
|
||||
onFinish={onSubmit}
|
||||
>
|
||||
<Form.Item
|
||||
label="标题"
|
||||
name="title"
|
||||
extra={<p className='tip'>简明扼要介绍文档/视频所包含的主要的内容</p>}
|
||||
rules={[{ required: true, message: '请输入标题' }]}
|
||||
>
|
||||
<Input placeholder='例如:软件工程教学案例' />
|
||||
</Form.Item>
|
||||
|
||||
<div className="flex-container">
|
||||
<Form.Item
|
||||
label="作者"
|
||||
name="author_name"
|
||||
rules={[{ required: true, message: '请输入作者名称' }]}
|
||||
>
|
||||
<Input placeholder='请输入姓名' style={{ marginRight: 20, width: 200 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="author_school_name"
|
||||
rules={[{ required: true, message: '请输入作者单位名称' }]}
|
||||
>
|
||||
<Input placeholder='请输入作者单位名称' style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item name="tag_ids" label='标签' rules={[{ required: true, message: '请选择一个标签' }]} >
|
||||
<CheckboxGroup>
|
||||
{tags.map(t => <Checkbox key={t.id} value={t.id} > {t.name} </Checkbox>)}
|
||||
</CheckboxGroup>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name='publish' valuePropName="checked">
|
||||
<Checkbox>是否申请发布</Checkbox>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
||||
name="content"
|
||||
label='描述'
|
||||
valuePropName='defaultValue'
|
||||
rules={[{ required: true, message: '请输入描述内容' }]}
|
||||
>
|
||||
<MarkdownEditor id='moop_cases_content' height={400} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="attachment_ids" valuePropName="fileList" getValueFromEvent={normFile} >
|
||||
<Dragger {...uploadProps} >
|
||||
<p className='c-blue' style={{ marginBottom: 10, fontSize: 18 }} >上传附件</p>
|
||||
<p className='c-grey-c'>从我的电脑选择要上传的文档:按住CTRL可以上传多份文档。单个文件最大限制:100MB</p>
|
||||
</Dragger>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name='cover_id' label='封面图' extra='上传尺寸:120*90 px' getValueFromEvent={normFile} valuePropName="fileList"
|
||||
rules={[{ required: true, message: "请上传封面图" }]}
|
||||
>
|
||||
<Upload {...uploadCoverProps}>
|
||||
{uploadUrl ? <img src={uploadUrl} width={120} /> : <a title='上传封面图' className='upload-cover'> <InboxOutlined /> </a>}
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
|
||||
<div className="desc">
|
||||
<h3>审核说明</h3>
|
||||
<p> 平台管理员将对每天新上传的文档进行审核,审核通过的文档将公开显示,否则将私有化或移除 </p>
|
||||
</div>
|
||||
|
||||
<div className="desc">
|
||||
<h3>温馨提示</h3>
|
||||
<ul style={{ padding: 0 }}>
|
||||
<li>1.请勿上传已设置加密口令的文档资源;</li>
|
||||
<li>2.可以上传符合教学案例标准的文档资料,如
|
||||
<a href="https://www.educoder.net/courses/1309/boards/5909/messages/34799" target='_blank'> 案例入库标准 </a> 、<a href='https://www.educoder.net/courses/1309/boards/5909/messages/34798' target='_blank'>案例使用说明书</a>以及其他资料等,上传支持的文件最大容量:100MB;</li>
|
||||
<li>3.请确保上传内容无侵权或违反国家关于互联网政策的不良行为;</li>
|
||||
<li>4.请使用Chrome,Firefox,Safari,IE11(及以上版本)浏览器;</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<Form.Item style={{ marginTop: 10 }}>
|
||||
<Button type="primary" htmlType="submit" >
|
||||
提交
|
||||
</Button>
|
||||
</Form.Item>
|
||||
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
.moop-panel {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
padding: 30px;
|
||||
|
||||
.tip {
|
||||
margin-top: 10px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.upload-cover {
|
||||
width: 120px;
|
||||
height: 90px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
border: 1px dashed #ccc;
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
import React, { useEffect, useReducer } from 'react'
|
||||
import { Spin } from 'antd'
|
||||
import '../InfoPanel/index.less'
|
||||
import './index.less'
|
||||
|
||||
import { Tag } from '../index'
|
||||
|
||||
import { Link, useParams, useHistory } from 'umi'
|
||||
import MoopForm from './MoopForm'
|
||||
import { getMoopCase, getLibraryTags, removeAttachment, addMoopCase, updateMoopCase } from './service'
|
||||
|
||||
interface IState {
|
||||
loading: boolean
|
||||
data: any
|
||||
tags: Array<Tag>
|
||||
}
|
||||
|
||||
const initialState: IState = {
|
||||
loading: false,
|
||||
data: {},
|
||||
tags: []
|
||||
}
|
||||
|
||||
enum Types {
|
||||
GET_DATA,
|
||||
SET_LOADING,
|
||||
GET_TAGS
|
||||
}
|
||||
|
||||
function reducer(state: IState, action: any) {
|
||||
switch (action.type) {
|
||||
case Types.GET_DATA:
|
||||
return { ...state, ...action.payload }
|
||||
case Types.GET_TAGS:
|
||||
return { ...state, tags: action.payload }
|
||||
case Types.SET_LOADING:
|
||||
return { ...state, loading: action.payload }
|
||||
default:
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const { caseId } = useParams()
|
||||
const history = useHistory()
|
||||
const [state, dispatch] = useReducer(reducer, initialState)
|
||||
const { loading, tags, data } = state
|
||||
|
||||
useEffect(() => {
|
||||
async function init() {
|
||||
const response = await getLibraryTags()
|
||||
dispatch({
|
||||
type: Types.GET_TAGS,
|
||||
payload: response.library_tags
|
||||
})
|
||||
}
|
||||
init()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false
|
||||
async function init() {
|
||||
dispatch({ type: Types.SET_LOADING, payload: false })
|
||||
let response = await getMoopCase(caseId)
|
||||
const { author_name, author_school_name, content, cover, attachments, status, title, tags } = response
|
||||
if (!didCancel) {
|
||||
if (response.status === 404) {
|
||||
history.push('/moop_cases')
|
||||
} else {
|
||||
dispatch({
|
||||
type: Types.GET_DATA,
|
||||
payload:
|
||||
{
|
||||
data: {
|
||||
title,
|
||||
author_name,
|
||||
author_school_name,
|
||||
content,
|
||||
tag_ids: tags.map((item: any) => item.id),
|
||||
publish: status === 'published',
|
||||
attachment_ids: attachments.map((item: any) => {
|
||||
return {
|
||||
uid: item.id,
|
||||
id: item.id,
|
||||
name: item.title,
|
||||
url: item.url,
|
||||
filesize: item.filesize,
|
||||
status: 'done'
|
||||
}
|
||||
}),
|
||||
cover_id:cover?.id?[{
|
||||
uid: cover?.id,
|
||||
id: cover?.id,
|
||||
name: cover?.title,
|
||||
url: cover?.url,
|
||||
filesize: cover?.filesize,
|
||||
status: 'done'
|
||||
}]:[],
|
||||
},
|
||||
loading: false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!didCancel && caseId) {
|
||||
init()
|
||||
}
|
||||
return () => {
|
||||
didCancel = true
|
||||
}
|
||||
}, [caseId])
|
||||
|
||||
async function onUpdateCase(values: any) {
|
||||
if (caseId) {
|
||||
await updateMoopCase(caseId, values)
|
||||
history.push(`/moop_cases/${caseId}/publish-success`)
|
||||
} else {
|
||||
const { id } = await addMoopCase(values)
|
||||
if (id) {
|
||||
history.push(`/moop_cases/${id}/publish-success`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const moopFormProps = {
|
||||
initialValues: data,
|
||||
tags,
|
||||
removeAttachment,
|
||||
callback: onUpdateCase
|
||||
}
|
||||
return (
|
||||
<Spin spinning={loading} delay={500}>
|
||||
<div className="moop-info">
|
||||
<div className="crumb">
|
||||
<Link to='/moop_cases'>教学案例 > </Link>
|
||||
<span>新建</span>
|
||||
</div>
|
||||
<div className="title">
|
||||
<h2>上传教学案例</h2>
|
||||
<Link to='/moop_cases'>返回</Link>
|
||||
</div>
|
||||
<MoopForm {...moopFormProps} />
|
||||
</div>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { get, post, del, put } from '@/utils/fetch'
|
||||
|
||||
export function getMoopCase(id: number) {
|
||||
return get(`libraries/${id}.json`)
|
||||
}
|
||||
|
||||
export function getLibraryTags() {
|
||||
return get('library_tags.json')
|
||||
}
|
||||
|
||||
export async function removeAttachment(id: number) {
|
||||
const response = await del(`attachments/${id}.json`)
|
||||
return response.status === 0
|
||||
}
|
||||
|
||||
export function addMoopCase(params: any) {
|
||||
return post(`libraries.json`, params)
|
||||
}
|
||||
|
||||
export function updateMoopCase(id: number, params: any) {
|
||||
return put(`libraries/${id}.json`, params)
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
.moop-info {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
|
||||
.crumb {
|
||||
margin: 10px 0 20px 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 22px;
|
||||
line-height: 40px;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
a {
|
||||
font-size: 14px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moop-info-body {
|
||||
padding: 30px;
|
||||
background: #fff;
|
||||
|
||||
.attachment {
|
||||
list-style: none;
|
||||
margin: 10px 0 0 0;
|
||||
padding: 0;
|
||||
|
||||
.iconfont {
|
||||
color: #29bd8b;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
|
||||
span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sum {
|
||||
width: 100%;
|
||||
color: #999;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
|
||||
span:first-child {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 16px;
|
||||
flex: 1 0 auto;
|
||||
|
||||
.flex-container > span {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moop-sub-title {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
border-radius: 25px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.praise {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background-color: #4cacff;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
margin: 20px auto;
|
||||
cursor: pointer;
|
||||
line-height: 22px;
|
||||
border: 0px solid transparent;
|
||||
outline: none;
|
||||
display: block;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: #bcd1e3;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
import React, { useReducer, useEffect } from 'react'
|
||||
import { Spin, Button, Popconfirm } from 'antd'
|
||||
import { useParams, Link, useHistory } from 'umi'
|
||||
import { get, post, del } from '@/utils/fetch'
|
||||
import { Tag } from '../index'
|
||||
import Env from '@/utils/env'
|
||||
import RenderHtml from '@/components/RenderHtml'
|
||||
import './index.less'
|
||||
import '../label.css'
|
||||
|
||||
interface State {
|
||||
data: any,
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
data: undefined,
|
||||
}
|
||||
|
||||
export enum Types {
|
||||
GET_DATA = 'get-data',
|
||||
PRAISE = 'on-praise'
|
||||
}
|
||||
|
||||
function reducer(state: State, action: any) {
|
||||
switch (action.type) {
|
||||
case Types.GET_DATA:
|
||||
return { ...state, data: action.payload }
|
||||
case Types.PRAISE:
|
||||
return { ...state, data: action.payload }
|
||||
default:
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState)
|
||||
const { data } = state
|
||||
const { caseId } = useParams()
|
||||
const history = useHistory()
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false
|
||||
async function init() {
|
||||
const response = await get(`libraries/${caseId}.json`)
|
||||
if (!didCancel) {
|
||||
if (response.status === 404) {
|
||||
history.push('/moop_cases')
|
||||
} else {
|
||||
|
||||
dispatch({
|
||||
type: Types.GET_DATA,
|
||||
payload: response,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!didCancel) {
|
||||
init()
|
||||
}
|
||||
return () => {
|
||||
didCancel = true
|
||||
}
|
||||
}, [caseId])
|
||||
|
||||
async function onPraise() {
|
||||
await post(`praise_tread/like.json`, {
|
||||
object_id: caseId,
|
||||
object_type: "library"
|
||||
})
|
||||
let rs = { ...data }
|
||||
rs.operation.user_praised = true
|
||||
rs.praise_count += 1
|
||||
|
||||
dispatch({
|
||||
type: Types.PRAISE,
|
||||
payload: rs
|
||||
})
|
||||
}
|
||||
|
||||
async function onDeleteCase() {
|
||||
await del(`/libraries/${caseId}.json`)
|
||||
history.push('/moop_cases')
|
||||
}
|
||||
|
||||
return (
|
||||
<Spin spinning={!data} delay={500}>
|
||||
{data ?
|
||||
<section className='moop-info'>
|
||||
<div className="crumb">
|
||||
<Link to='/moop_cases'>教学案例 > </Link>
|
||||
<span>{data.title}</span>
|
||||
</div>
|
||||
<div className="title">
|
||||
<h2>
|
||||
{data.title}
|
||||
{data.tags?.map((tag: Tag, index: number) =>
|
||||
<span className={'label-' + index} key={tag.id}>{tag.name}</span>
|
||||
)}
|
||||
</h2>
|
||||
<Link to='/moop_cases'>返回</Link>
|
||||
</div>
|
||||
<div className="moop-info-body">
|
||||
|
||||
<div className="moop-sub-title">
|
||||
<img src={`${Env.IMG_SERVER}/images/${data.creator?.image_url}`} alt="cover" width={50} />
|
||||
<div className="desc">
|
||||
<div className="flex-container">
|
||||
<span>{data.creator?.name}</span>
|
||||
{data.operation?.can_editable ?
|
||||
<Link to={`/moop_cases/${data.id}/edit`} style={{ marginRight: 10 }}>
|
||||
<Button type='ghost'>编辑</Button>
|
||||
</Link>
|
||||
: null}
|
||||
{data.operation?.can_deletable ?
|
||||
<Popconfirm
|
||||
placement="bottomRight"
|
||||
title="是否确认删除?"
|
||||
onConfirm={onDeleteCase}
|
||||
>
|
||||
<Button type='dashed'>删除</Button>
|
||||
</Popconfirm>
|
||||
: null}
|
||||
</div>
|
||||
<div className="sum">
|
||||
<span>{data.creator?.school_name}</span>
|
||||
<span>编码:{data.uuid}</span>
|
||||
<span>发布时间:{data.published_at}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>作者:{`${data.author_name} / ${data.author_school_name}`}</p>
|
||||
<RenderHtml value={data.content} />
|
||||
<ul className="attachment">
|
||||
{
|
||||
data.attachments?.map(
|
||||
(item: any) =>
|
||||
<li key={item.id}>
|
||||
<a href={item.url}>
|
||||
<i className="iconfont icon-fujian"></i>
|
||||
<span>{item.title}</span>
|
||||
<span>{item.filesize}</span>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<button className="praise" disabled={data.operation?.user_praised} onClick={onPraise}>
|
||||
{
|
||||
data.operation?.user_praised ?
|
||||
<span>已赞</span> :
|
||||
<span>
|
||||
<i className="iconfont icon-dianzan"></i>
|
||||
</span>
|
||||
}
|
||||
<span>{data.praise_count}</span>
|
||||
</button>
|
||||
</div>
|
||||
</section> : null}
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
.moop-case-success {
|
||||
width: 1200px;
|
||||
height: 570px;
|
||||
margin: 20px auto 40px auto;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
|
||||
.notice {
|
||||
margin: 20px auto;
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 24px;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
img {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import React from 'react'
|
||||
import OkUrl from './ok.png'
|
||||
import { Button } from 'antd'
|
||||
import { Link, useParams } from 'umi'
|
||||
import './index.less'
|
||||
|
||||
export default () => {
|
||||
const { caseId } = useParams()
|
||||
return (
|
||||
<div className="moop-case-success">
|
||||
<img src={OkUrl} alt="ok" width={100} />
|
||||
<p>恭喜!</p>
|
||||
<p>提交成功</p>
|
||||
<div className="notice">
|
||||
平台正在审核您的申请,审核结果将以平台消息的形势通知您
|
||||
</div>
|
||||
<div>
|
||||
<Button type='ghost' size='large' style={{ marginRight: 20 }} ><Link to={`/moop_cases/${caseId}`}>查看已上传文档</Link></Button>
|
||||
<Button type='primary' size='large' ><Link to='/moop_cases/new'>继续上传</Link></Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
|
@ -1,134 +0,0 @@
|
|||
@import '../../global.less';
|
||||
.moop-case {
|
||||
// img {
|
||||
// display: block;
|
||||
// max-width: 100%;
|
||||
// }
|
||||
|
||||
.banner {
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
.flex_box_container();
|
||||
.flex_box_center();
|
||||
img {
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.moop-title {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
padding: 20px 30px;
|
||||
|
||||
span {
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.moop-main {
|
||||
width: 1200px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
padding: 0px 10px;
|
||||
color: #4cacff;
|
||||
border: 1px solid #4cacff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.moop-search {
|
||||
width: 300px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.search-input-container {
|
||||
padding: 20px 30px;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
a {
|
||||
color: #05101a;
|
||||
margin-right: 30px;
|
||||
line-height: 20px;
|
||||
font-size: 16px;
|
||||
|
||||
&.active {
|
||||
color: #4cacff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-footer {
|
||||
padding-bottom: 30px;
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.case-list {
|
||||
width: 1200px;
|
||||
margin: 20px auto 0 auto;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
background: #fff;
|
||||
padding: 20px 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 22px;
|
||||
line-height: 40px;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 4px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.detail {
|
||||
display: flex;
|
||||
color: #333;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sum {
|
||||
color: #ccc;
|
||||
|
||||
span {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,236 +0,0 @@
|
|||
import React, { useEffect, useReducer,FC } from 'react'
|
||||
import { get } from '@/utils/fetch'
|
||||
import './index.less'
|
||||
import './label.css'
|
||||
import { Spin, Input, Pagination } from 'antd'
|
||||
import {
|
||||
GlobalSettingModelState,
|
||||
ConnectProps,
|
||||
connect,
|
||||
Link,
|
||||
UserModelState,
|
||||
} from 'umi';
|
||||
import Env from '@/utils/env'
|
||||
import { isLogin } from '@/utils/authority'
|
||||
import bgUrl from './teach-case-bg.jpg';
|
||||
const Search = Input.Search
|
||||
|
||||
interface PageProps extends Partial<ConnectProps> {
|
||||
user: UserModelState;
|
||||
globalSetting: GlobalSettingModelState;
|
||||
}
|
||||
|
||||
type State = {
|
||||
loading: boolean,
|
||||
page: number,
|
||||
count: number,
|
||||
list: any,
|
||||
type: string,
|
||||
keyword: string,
|
||||
}
|
||||
|
||||
export type Tag = { id: number, name: string }
|
||||
|
||||
const initialState: State = {
|
||||
loading: false,
|
||||
type: 'all',
|
||||
page: 1,
|
||||
count: 0,
|
||||
list: [],
|
||||
keyword: ''
|
||||
}
|
||||
|
||||
export enum Types {
|
||||
GET_LIST,
|
||||
CHANGE_KEYWORD,
|
||||
CHANGE_PAGE,
|
||||
CHANGE_TYPE,
|
||||
SET_LOADING
|
||||
}
|
||||
|
||||
function reducer(state: State, action: any) {
|
||||
switch (action.type) {
|
||||
case Types.GET_LIST:
|
||||
return { ...state, ...action.payload }
|
||||
case Types.CHANGE_PAGE:
|
||||
return { ...state, page: action.payload }
|
||||
case Types.CHANGE_KEYWORD:
|
||||
return { ...state, ...action.payload }
|
||||
case Types.CHANGE_TYPE:
|
||||
return { ...state, ...action.payload }
|
||||
case Types.SET_LOADING:
|
||||
return { ...state, loading: action.payload }
|
||||
default:
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
|
||||
const MoopCases: FC<PageProps> = ({
|
||||
user,
|
||||
globalSetting,
|
||||
dispatch
|
||||
}) => {
|
||||
// const MoopCases = () => {
|
||||
const [state, setState] = useReducer(reducer, initialState)
|
||||
const { loading, page, list, keyword, type, count } = state
|
||||
|
||||
//出现页面右侧悬浮按钮
|
||||
useEffect(() => {
|
||||
dispatch({
|
||||
type: 'globalSetting/onlyShowBackTopToggle',
|
||||
payload: false
|
||||
});
|
||||
return () => {
|
||||
dispatch({
|
||||
type: 'globalSetting/onlyShowBackTopToggle',
|
||||
payload: true
|
||||
});
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false
|
||||
async function init() {
|
||||
setState({
|
||||
type: Types.SET_LOADING,
|
||||
payload: true,
|
||||
})
|
||||
const response = await get(`libraries.json`, {
|
||||
keyword,
|
||||
page,
|
||||
type,
|
||||
})
|
||||
const { libraries, count } = response
|
||||
if (!didCancel) {
|
||||
setState({
|
||||
type: Types.GET_LIST,
|
||||
payload: {
|
||||
count,
|
||||
list: libraries,
|
||||
loading: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
if (!didCancel) {
|
||||
init()
|
||||
}
|
||||
return () => {
|
||||
didCancel = true
|
||||
}
|
||||
}, [page, keyword, type])
|
||||
|
||||
function onSetKeyword(value: string) {
|
||||
setState({
|
||||
type: Types.CHANGE_KEYWORD, payload: {
|
||||
keyword: value,
|
||||
page: 1,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onChangeType(e: React.MouseEvent<HTMLElement>): void {
|
||||
setState({ type: Types.CHANGE_TYPE, payload: { type: (e.target as any).id, page: 1 } })
|
||||
}
|
||||
|
||||
function onPageChange(value: number) {
|
||||
document.body.scrollIntoView()
|
||||
setState({
|
||||
type: Types.CHANGE_PAGE,
|
||||
payload: value,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="moop-case">
|
||||
<section className={"banner"}>
|
||||
<img src={Env.IMG_SERVER + '/' + globalSetting?.setting?.moop_cases_banner_url} alt='bg' />
|
||||
</section>
|
||||
<section className='moop-main'>
|
||||
<div className="moop-title">
|
||||
<span>教学案例</span>
|
||||
<Link to='/moop_cases/new' className="btn-ghost">发布案例</Link>
|
||||
</div>
|
||||
<div className="search-input-container">
|
||||
<div className="flex-container">
|
||||
<a id='all' onClick={onChangeType} className={type === 'all' ? 'active' : ''}>全部</a>
|
||||
{isLogin() ?
|
||||
<a id="mine" onClick={onChangeType} className={type === 'mine' ? 'active' : ''}>我的</a> : null
|
||||
}
|
||||
</div>
|
||||
<Search
|
||||
className='moop-search'
|
||||
defaultValue={keyword}
|
||||
placeholder="输入教学案例标题、作者、单位进行检索"
|
||||
onSearch={onSetKeyword}
|
||||
></Search>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<Spin spinning={loading} delay={500}>
|
||||
<CaseList data={list} />
|
||||
</Spin>
|
||||
|
||||
<div className="search-footer">
|
||||
{count > 20 ?
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
current={page}
|
||||
onChange={onPageChange}
|
||||
pageSize={20}
|
||||
showSizeChanger={false}
|
||||
total={count}
|
||||
></Pagination> : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CaseList({ data }: { data: any }) {
|
||||
return (
|
||||
<ul className="case-list">
|
||||
{
|
||||
data.map((item: any) =>
|
||||
<li key={item.id}>
|
||||
<a href={`/moop_cases/${item.id}`} target='_blank'>
|
||||
<img src={`${Env.IMG_SERVER}${item.cover_url}`} width={120} alt={item.title} />
|
||||
<div className="info">
|
||||
<h2>
|
||||
{item.title}
|
||||
{item.tags?.map((tag: Tag, index: number) =>
|
||||
<span className={'label-' + index} key={tag.id}>{tag.name}</span>
|
||||
)}
|
||||
</h2>
|
||||
<div className="detail">
|
||||
<div className="flex-container">
|
||||
<span>{`${item.author_name} ${item.author_school_name}`}</span>
|
||||
</div>
|
||||
<div className="sum">
|
||||
<span> <i className="fa fa-eye"></i> {item.visited_count} 浏览 </span>
|
||||
<span> <i className="fa fa-thumbs-o-up"></i> {item.praise_count} 赞 </span>
|
||||
<span> <i className="fa fa-download"></i> {item.download_count} 下载 </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default connect(
|
||||
({
|
||||
user,
|
||||
globalSetting,
|
||||
}: {
|
||||
user: UserModelState;
|
||||
globalSetting: GlobalSettingModelState;
|
||||
}) => ({
|
||||
user,
|
||||
globalSetting,
|
||||
}),
|
||||
)(MoopCases);
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
[class^='label-'] {
|
||||
cursor: pointer;
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
padding: 0 9px;
|
||||
width: 68px;
|
||||
text-align: center;
|
||||
border-radius: 9px;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.label-0 {
|
||||
background: #fc2b6a;
|
||||
}
|
||||
|
||||
.label-1 {
|
||||
background: #ff781b;
|
||||
}
|
||||
|
||||
.label-2 {
|
||||
background: #4cacff;
|
||||
}
|
||||
|
||||
.label-3 {
|
||||
background: #36c53c;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 239 KiB |
|
|
@ -52,9 +52,6 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div style="position: absolute;top: -2000px;">
|
||||
<img src="https://ali-cdn.educoder.net/images/avatars/LaboratorySetting/1nav?t=1609921874" title="头歌" />
|
||||
</div>
|
||||
<div id="root">
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
|
||||
import http from './index'
|
||||
|
||||
import { config } from './info';
|
||||
|
||||
/**
|
||||
* 获取基础信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getBaseInfo(params) {
|
||||
return http({
|
||||
url: `/api/zone/open/zoneKey/${config.zoneKey}`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会议议程主会场(指定新闻列表)
|
||||
* @param {*} cateId 指定专栏id
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getDocList(cateId, params) {
|
||||
return http({
|
||||
url: `/api/cms/doc/open/dir/${cateId}/docList`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会议议程分会场(指定新闻列表内容)
|
||||
* @param {*} cateId 指定专栏id
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getSubAgenda(cateId, params) {
|
||||
return http({
|
||||
url: `/api/cms/doc/open/dir/${cateId}/docContentList`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取会议指南(专区首页文章列表
|
||||
* @returns
|
||||
*/
|
||||
export function gethomePageDocList() {
|
||||
return http({
|
||||
url: `/api/cms/doc/open/zone/${config.zoneId}/homePageDocList`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取与会嘉宾
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberList() {
|
||||
return http({
|
||||
url: `/api/zone/open/${config.zoneId}/member/homePageList`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 合作伙伴
|
||||
* @returns
|
||||
*/
|
||||
export function getPartnerList() {
|
||||
return http({
|
||||
url: `/api/zone/open/${config.zoneId}/partners/list`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组织机构
|
||||
* @returns
|
||||
*/
|
||||
export function getOrganization(){
|
||||
return http({
|
||||
url:`/api/zone/open/${config.zoneId}/member/overviewList`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章详情
|
||||
* @param {*} id 文章id
|
||||
* @returns
|
||||
*/
|
||||
export function getDocDetail(id){
|
||||
return http({
|
||||
url:`/api/cms/doc/open/${id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有栏目列表
|
||||
* @returns
|
||||
*/
|
||||
export function getDirList(){
|
||||
return http({
|
||||
url:`/api/cms/doc/open/zone/${config.zoneId}/dirList`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import './index.less';
|
||||
import MenuBanner from './menu';
|
||||
import SubBanner from '../img/subBanner.png';
|
||||
import { useModel } from 'umi';
|
||||
|
||||
|
||||
function Banner(props) {
|
||||
const { mainInfo } = useModel('defaultConfig');
|
||||
return(
|
||||
<div className='mainroot'>
|
||||
<div className='mainBanner'>
|
||||
<div className="header">
|
||||
<img src={mainInfo?.bannerList} />
|
||||
<div className='bannerContent'><MenuBanner /></div>
|
||||
</div>
|
||||
</div>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Banner;
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
.bannerContent{
|
||||
position: absolute;
|
||||
bottom: -41px;
|
||||
width: 100%;
|
||||
height: 76px;
|
||||
.banners{
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
padding:0px 40px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.09);
|
||||
a{
|
||||
img{
|
||||
margin-right: 18px;
|
||||
}
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #252B3A;
|
||||
padding-right: 100px;
|
||||
&.active{
|
||||
color: #6233DE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.mainroot{
|
||||
background: url('../img/back.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
.mainBanner{
|
||||
padding-bottom: 41px;
|
||||
width: 100%;
|
||||
.header {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
position: relative;
|
||||
font-size: 15px;
|
||||
width: 100%;
|
||||
&>img{
|
||||
width: 100%;
|
||||
max-height: 300px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
import './index.less';
|
||||
import { useState , useEffect } from 'react';
|
||||
import {useLocation , Link} from 'umi';
|
||||
import { menu } from '../info';
|
||||
|
||||
function Menu(props) {
|
||||
const location = useLocation();
|
||||
|
||||
const matchItem = (item) => {
|
||||
if(location.pathname.indexOf("/track/")>-1){
|
||||
return item.indexOf("/track/") > -1
|
||||
}else{
|
||||
return item === location.pathname
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<ul className='banners'>
|
||||
{
|
||||
menu && menu?.length > 0 && menu.map((i,k)=>{
|
||||
return(
|
||||
<Link to={i.link} key={k} className={`${matchItem(i.link) ? `active` : ``}`}><img src={require(`../img/logo${k+1}${matchItem(i.link) ? "-color":""}.png`)} />{i.name}</Link>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
export default Menu;
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
import { useRef, useState, useEffect } from 'react';
|
||||
import {
|
||||
Link , useModel
|
||||
}from 'umi';
|
||||
import './index.less';
|
||||
import { getBaseInfo, getPartnerList , gethomePageDocList , getDocDetail } from '../api.js';
|
||||
import Left from '../img/left.png';
|
||||
import Right from '../img/right.png';
|
||||
import Arrow from '../img/arrow.png';
|
||||
import ArrowPurple from '../img/arrowPurple.png';
|
||||
import Diamond from '../img/liu.png';
|
||||
import Number1 from '../img/number1.png';
|
||||
import Number2 from '../img/number2.png';
|
||||
import Number3 from '../img/number3.png';
|
||||
import Team from '../img/team.png';
|
||||
import trackBack from '../img/track.png';
|
||||
import trackBack2 from '../img/track2.png';
|
||||
import Dynamics from '../img/dynamics.png';
|
||||
import Dynamicsicon from '../img/dynamicsicon.png';
|
||||
|
||||
|
||||
function Home(){
|
||||
const [ partner, setPartner ] = useState([]);
|
||||
const [newsList, setNewsList] = useState([]);
|
||||
const [ visits , setVisits ] = useState(0);
|
||||
const { mainInfo } = useModel('defaultConfig');
|
||||
|
||||
useEffect(()=>{
|
||||
getPartner();
|
||||
getNewsList();
|
||||
getVisit();
|
||||
},[])
|
||||
|
||||
// 获取浏览次数
|
||||
const getVisit=()=>{
|
||||
getDocDetail(656).then(res=>{
|
||||
res && setVisits(res?.data?.visits);
|
||||
}).catch(console.error())
|
||||
}
|
||||
|
||||
|
||||
// 合作单位
|
||||
const getPartner = () => {
|
||||
getPartnerList().then(res => {
|
||||
setPartner(res.rows);
|
||||
}).catch(console.error())
|
||||
}
|
||||
// 资讯
|
||||
const getNewsList = () => {
|
||||
gethomePageDocList().then(res => {
|
||||
setNewsList(res.rows)
|
||||
})
|
||||
}
|
||||
return(
|
||||
<div className="page headpage">
|
||||
{/* <div className="banner">
|
||||
<img src={ Banner } alt=""/>
|
||||
</div> */}
|
||||
<div className='part'>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>赛事简介</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>EVENT INTRODUCTION</span></p>
|
||||
<div className='homeDesc'>{mainInfo.introductionContent}</div>
|
||||
{/* <a className='applicationBtn hoverBtn'>立即报名<img src={Arrow} width={19}/></a> */}
|
||||
<ul className='numbersData'>
|
||||
<li>
|
||||
<span className='number'><em>{visits}</em>次</span>
|
||||
<div className='line'><img src={Diamond} alt="" width={23} /></div>
|
||||
<span className='btn'>浏览次数</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='number'><em>0</em>人</span>
|
||||
<div className='line'><img src={Diamond} alt="" width={23} /></div>
|
||||
<span className='btn'>报名人数</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='number'>¥<em>1000,000</em></span>
|
||||
<div className='line'><img src={Diamond} alt="" width={23} /></div>
|
||||
<span className='btn'>奖金总数</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className='part'>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>大赛流程</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>COMPETITION PROCESS</span></p>
|
||||
<ul className='team'>
|
||||
<li>
|
||||
<p className='t-title'><img src={Team} width={33}/><span>热身赛</span><img src={Number1} width={80}/></p>
|
||||
<p className='t-desc'>正式比赛前的预备赛事,帮助选手熟悉流程和参赛项目</p>
|
||||
<p className='t-time'>2024年 5月16日-6月30日</p>
|
||||
</li>
|
||||
<li>
|
||||
<p className='t-title'><img src={Team} width={33}/><span>初 赛</span><img src={Number2} width={97}/></p>
|
||||
<p className='t-desc'>完成整体赛事后的线上选拔出三等奖及入围一、二等奖的优秀团队</p>
|
||||
<p className='t-time'>2024年 7月1日-8月31日</p>
|
||||
</li>
|
||||
<li>
|
||||
<p className='t-title'><img src={Team} width={33}/><span>决 赛</span><img src={Number3} width={95}/></p>
|
||||
<p className='t-desc'>通过线下的现场演示/答辩,最终决出一、二等奖的胜者</p>
|
||||
<p className='t-time'>2024年 9月1日-9月20日</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className='part'>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>大赛赛道</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>COMPETITION TRACK</span></p>
|
||||
<div className='track'>
|
||||
<li>
|
||||
<img src={trackBack} alt="" className='backimg'/>
|
||||
<div className='trackContent'>
|
||||
<div className='flex1'>
|
||||
<p className='tracktitle'><span>贡献:</span>开源项目贡献赛道</p>
|
||||
<p style={{opacity:"0.71"}}>参赛队伍解决开源项目疑修,提交代码,创新应用并移植工具,凭贡献获奖。</p>
|
||||
</div>
|
||||
<a className='applicationBtn' href='/competitions/2024/track/633'>查看详情<img src={ArrowPurple} width={19}/></a>
|
||||
<span className='money'>¥ 69,000</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<img src={trackBack2} alt="" className='backimg'/>
|
||||
<div className='trackContent'>
|
||||
<div className='flex1'>
|
||||
<p className='tracktitle'><span>挑战:</span>开源任务挑战赛道</p>
|
||||
<p style={{opacity:"0.71"}}>根据指定任务汇聚优秀算法和解决方案,可持续优化更新,结合性能和效果评奖。</p>
|
||||
</div>
|
||||
<a className='applicationBtn' href='/competitions/2024/track/634'>查看详情<img src={ArrowPurple} width={19}/></a>
|
||||
<span className='money'>¥ 69,000</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<img src={trackBack2} alt="" className='backimg'/>
|
||||
<div className='trackContent'>
|
||||
<div className='flex1'>
|
||||
<p className='tracktitle'><span>教学:</span>开源案例教学赛道</p>
|
||||
<p style={{opacity:"0.71"}}>在线汇聚高校实践教学案例,助力实践教学创新,依据案例质量与应用成效评奖。</p>
|
||||
</div>
|
||||
<a className='applicationBtn' href='/competitions/2024/track/635'>查看详情<img src={ArrowPurple} width={19}/></a>
|
||||
<span className='money'>¥ 69,000</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<img src={trackBack} alt="" className='backimg'/>
|
||||
<div className='trackContent'>
|
||||
<div className='flex1'>
|
||||
<p className='tracktitle'><span>评注:</span>开源代码评注赛道</p>
|
||||
<p style={{opacity:"0.71"}}>研读开源项目代码,撰写技术评注、代码注释及缺陷报告,按数量、质量及贡献评奖。</p>
|
||||
</div>
|
||||
<a className='applicationBtn' href='/competitions/2024/track/636'>查看详情<img src={ArrowPurple} width={19}/></a>
|
||||
<span className='money'>¥ 69,000</span>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
<div className='part'>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>赛事动态</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>EVENT DYNAMICS</span></p>
|
||||
{
|
||||
newsList && newsList.length > 0 &&
|
||||
<div className='dynamics'>
|
||||
<ul className='dynamicsNews'>
|
||||
{ newsList.map((i, k) => {
|
||||
return k < 3 ?
|
||||
<li>
|
||||
<p className='uper'><img src={Dynamicsicon} width={26}/>{ i.name }</p>
|
||||
<p className='under'>
|
||||
<span>{i.publishTime}</span>
|
||||
<Link to={`/competitions/2024/information/${ i.id }`} className='applicationBtn'>查看详情<img src={Arrow} width={19}/></Link>
|
||||
</p>
|
||||
</li>
|
||||
: ''
|
||||
})}
|
||||
</ul>
|
||||
<div className='dynamicsImg'>
|
||||
<img src={Dynamics} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<a className='applicationBtn hoverBtn' href="/competitions/2024/information" style={{marginTop:32}}>更多资讯<img src={Arrow} width={19}/></a>
|
||||
</div>
|
||||
<div className='part'>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>合作伙伴</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>PARTNERS</span></p>
|
||||
<div className="partner-content">
|
||||
{
|
||||
partner.map((e, k) => {
|
||||
return (
|
||||
e.zonePartnersList.length > 0 && e.typeName.indexOf("高校") === -1 ?
|
||||
<div className="partner-type" key={ k }>
|
||||
<div className="type-title">
|
||||
<span>{ e.typeName }</span>
|
||||
</div>
|
||||
<div className="type-content">
|
||||
{
|
||||
e.zonePartnersList.map((i, subK) => {
|
||||
return <a key={ subK } href={ i.link } target="_blank">
|
||||
<div>
|
||||
<img src={ i.logo } alt=""/>
|
||||
</div>
|
||||
</a>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
:''
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Home;
|
||||
|
|
@ -0,0 +1,427 @@
|
|||
.page.headpage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
.banner {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// object-fit: cover;
|
||||
}
|
||||
}
|
||||
.part{
|
||||
text-align: center;
|
||||
width: 1200px;
|
||||
}
|
||||
.homeMaintitle{
|
||||
font-size: 48px;
|
||||
position: relative;
|
||||
margin:54px auto 0px;
|
||||
width: 224px;
|
||||
img{
|
||||
width: 12px;
|
||||
position: absolute;
|
||||
&:first-child{
|
||||
left: -12px;
|
||||
}
|
||||
&:last-child{
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
span{
|
||||
margin:0px 22px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
.homeSubtitle{
|
||||
margin-top: 12px;
|
||||
text-align: center;
|
||||
span{
|
||||
font-size: 16px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
background: -webkit-linear-gradient(76deg, rgba(24,163,168,0.77) 0%, #2E89FF 51%, rgba(158,3,127,0.77) 100%);
|
||||
background: linear-gradient(76deg, rgba(24,163,168,0.77) 0%, #2E89FF 51%, rgba(158,3,127,0.77) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent; /* 针对WebKit浏览器 */
|
||||
color: transparent; /* 兼容其他浏览器 */
|
||||
letter-spacing: 2px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
.homeDesc{
|
||||
width: 1200px;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #040E29;
|
||||
line-height: 40px;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 34px;
|
||||
text-align: left;
|
||||
text-indent: 2em;
|
||||
}
|
||||
.applicationBtn{
|
||||
margin-top:20px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
padding:0px 24px;
|
||||
color: #fff;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
display: inline-block;
|
||||
img{
|
||||
margin:0px 0px 4px 15px;
|
||||
}
|
||||
}
|
||||
.numbersData{
|
||||
display: flex;
|
||||
padding:50px 0px;
|
||||
position: relative;
|
||||
&::before{
|
||||
content: "";
|
||||
height: 3px;
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
left: calc(1200px / 6 + 10px);
|
||||
right: calc(1200px / 6 - 10px);
|
||||
position: absolute;
|
||||
top:50%;
|
||||
margin-top: 3.5px;
|
||||
}
|
||||
li{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
span.number{
|
||||
font-family: YouSheBiaoTiHei;
|
||||
font-weight: 400;
|
||||
font-size: 28px;
|
||||
color: #040E29;
|
||||
line-height: 40px;
|
||||
em{
|
||||
font-size: 50px;
|
||||
background: -webkit-linear-gradient(103deg, #5950F3 0%, #6B16CA 100%);
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent; /* 针对WebKit浏览器 */
|
||||
color: transparent; /* 兼容其他浏览器 */
|
||||
margin-right:12px;
|
||||
padding:0px 10px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
span.btn{
|
||||
width: 140px;
|
||||
height: 50px;
|
||||
line-height: 46px;
|
||||
background: #F6F7FA;
|
||||
box-shadow: 0px 0px 10px 1px rgba(7,70,165,0.11);
|
||||
border-radius: 9px 9px 9px 9px;
|
||||
border: 2px solid #FFFFFF;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #040E29;
|
||||
text-align: center;
|
||||
}
|
||||
&>.line{
|
||||
margin:40px 0px 27px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
img{
|
||||
position: absolute;
|
||||
margin-left: -12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.team{
|
||||
display: flex;
|
||||
margin-top: 67px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
li{
|
||||
height: 198px;
|
||||
padding:20px 30px;
|
||||
box-sizing: border-box;
|
||||
background: #F6F7FA;
|
||||
box-shadow: 0px 0px 10px 1px rgba(7,70,165,0.11);
|
||||
border-radius: 22px 22px 22px 22px;
|
||||
border: 2px solid #FFFFFF;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
margin-right: 80px;
|
||||
transition: 0.2s;
|
||||
&:last-child{
|
||||
margin-right: 0px;
|
||||
}
|
||||
&:hover{
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
.t-title{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
span{
|
||||
display: block;
|
||||
margin-right: auto;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #040E29;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
.t-desc{
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #040E29;
|
||||
line-height: 26px;
|
||||
text-align: left;
|
||||
margin-bottom: 18px;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
.t-time{
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #4C2795;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
.track{
|
||||
margin-top: 18px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 1200px;
|
||||
margin-bottom: 42px;
|
||||
li{
|
||||
list-style-type: none;
|
||||
height: 175px;
|
||||
margin: 39px 40px 0px 0px;
|
||||
background: linear-gradient( 92deg, #9356E4 0%, #5D3E9A 100%);
|
||||
border-radius: 12px;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
width:calc( 50% - 20px);
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #FFFFFF;
|
||||
line-height: 28px;
|
||||
position: relative;
|
||||
.backimg{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
width: 80%;
|
||||
}
|
||||
&:nth-child(2n){
|
||||
margin-right: 0px;
|
||||
}
|
||||
&:nth-child(2){
|
||||
background: linear-gradient( 92deg, #4779EC 0%, #11317A 100%);
|
||||
}
|
||||
&:nth-child(3){
|
||||
background: linear-gradient( 92deg, #088592 0%, #0D569C 100%);
|
||||
}
|
||||
&:nth-child(4){
|
||||
background: linear-gradient( 92deg, #736CF0 0%, #3C1E85 100%);
|
||||
}
|
||||
.trackContent{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding:28px 27px 28px 39px ;
|
||||
.money{
|
||||
font-weight: 400;
|
||||
font-size: 36px;
|
||||
color: #FFFFFF;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
letter-spacing: 2px;
|
||||
font-family:'Alimama ShuHeiTi';
|
||||
width: 194px;
|
||||
text-align: right;
|
||||
}
|
||||
.tracktitle{
|
||||
font-weight: 400;
|
||||
font-size: 22px;
|
||||
color: #FFFFFF;
|
||||
line-height: 38px;
|
||||
height: 38px;
|
||||
margin-bottom: 22px;
|
||||
span{
|
||||
font-weight: bold;
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
.applicationBtn{
|
||||
background: #fff;
|
||||
color: #6233DE;
|
||||
margin-left: 32px;
|
||||
display: none;
|
||||
margin-top: 0px;
|
||||
}
|
||||
&:hover{
|
||||
.applicationBtn{display: block;}
|
||||
.money{display: none;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.flex1{
|
||||
flex: 1;
|
||||
}
|
||||
.dynamics{
|
||||
display: flex;
|
||||
max-width: 1200px;
|
||||
margin-top:60px;
|
||||
justify-content: space-between;
|
||||
.dynamicsNews{
|
||||
width: 40%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
li{
|
||||
background: #F6F7FA;
|
||||
box-shadow: 0px 0px 10px 1px rgba(7,70,165,0.11);
|
||||
border-radius: 13px;
|
||||
border: 2px solid #FFFFFF;
|
||||
text-align: left;
|
||||
padding:22px 12px 18px 38px;
|
||||
.uper{
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #040E29;
|
||||
line-height: 26px;
|
||||
height: 48px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
img{
|
||||
margin-right: 10px;
|
||||
float: left;
|
||||
margin-top:3px ;
|
||||
}
|
||||
}
|
||||
.under{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #040E29;
|
||||
height: 20px;
|
||||
margin-bottom: 0px;
|
||||
.applicationBtn{
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
padding:0px 11px;
|
||||
margin-left: auto;
|
||||
margin-top: 0px;
|
||||
opacity: 0;
|
||||
transition: 0.8s;
|
||||
img{
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover .applicationBtn{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.dynamicsImg{
|
||||
width: calc( 60% - 32px);
|
||||
img{
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
.partner-content {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 50px;
|
||||
.partner-type {
|
||||
width:fit-content;
|
||||
.type-title {
|
||||
line-height: 28px;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #151313;
|
||||
letter-spacing: 5px;
|
||||
margin-bottom: 30px;
|
||||
text-align: left;
|
||||
span{
|
||||
position: relative;
|
||||
&::before{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
height: 2px;
|
||||
width: 32px;
|
||||
content: "";
|
||||
bottom:-7px;
|
||||
background: linear-gradient( 90deg, #5374B4 0%, #853CB8 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.type-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
div {
|
||||
margin-right: 42px;
|
||||
padding: 6px;
|
||||
background-color:#ffffff;
|
||||
border-radius:4px;
|
||||
box-shadow:0px 0px 6px rgba(28, 48, 175, 0.03);
|
||||
height: 83px;
|
||||
width: 163px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 35px;
|
||||
border:1px solid #fff;
|
||||
&:hover{
|
||||
border-color: #6233DE;
|
||||
}
|
||||
}
|
||||
a{
|
||||
&:nth-child(6n) div{
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
img {
|
||||
max-height: 55px;
|
||||
max-width: 130px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.hoverBtn:hover{
|
||||
opacity: 0.77;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 368 B |
|
After Width: | Height: | Size: 517 B |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 4.8 MiB |
|
After Width: | Height: | Size: 998 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 871 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 998 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 856 B |
|
After Width: | Height: | Size: 619 B |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 28 KiB |
|
|
@ -0,0 +1,41 @@
|
|||
import axios from 'axios';
|
||||
import { message , notification } from 'antd';
|
||||
|
||||
function beforeFetch(){
|
||||
if (window.location.href.indexOf('localhost') < 0) {
|
||||
axios.defaults.withCredentials = true;
|
||||
}
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: 'https://gateway.gitlink.org.cn',
|
||||
timeout: 1800000, // 请求超时时间
|
||||
});
|
||||
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response||{};
|
||||
if(res && res.data && res.data.code === 404){
|
||||
message.error("错误链接!");
|
||||
window.location.href = '/nopage';
|
||||
return Promise.reject('error');
|
||||
}else if(res && res.data && res.data.code === 500){
|
||||
message.error(res.data.msg);
|
||||
return Promise.reject('error');
|
||||
}else{
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
// notification.open({
|
||||
// message: "提示",
|
||||
// description: error.message,
|
||||
// });
|
||||
// return Promise.reject(error);
|
||||
}
|
||||
)
|
||||
return service;
|
||||
}
|
||||
|
||||
const service = beforeFetch();
|
||||
export default service;
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
export const menu = [
|
||||
{
|
||||
name: '首页',
|
||||
link: '/competitions/2024',
|
||||
},
|
||||
{
|
||||
name: '组织架构',
|
||||
link: '/competitions/2024/organization',
|
||||
},
|
||||
{
|
||||
name: '赛事安排',
|
||||
link: '/competitions/2024/track/633',
|
||||
},
|
||||
{
|
||||
name: '赛事动态',
|
||||
link: '/competitions/2024/information',
|
||||
}
|
||||
]
|
||||
|
||||
export const defaultPage = {
|
||||
'/register': 300,
|
||||
'/contact': 299
|
||||
}
|
||||
|
||||
export const information = {
|
||||
title: '大会资讯',
|
||||
desc: '方便您第一时间收集各会议论坛信息,解读大会通知资讯',
|
||||
category: [
|
||||
{
|
||||
title: '赛事安排',
|
||||
eng: 'Event arrangement',
|
||||
anchor: 'forum',
|
||||
},
|
||||
{
|
||||
title: '赛事动态',
|
||||
eng: 'Event dynamics',
|
||||
anchor: 'guide',
|
||||
},
|
||||
{
|
||||
title: '赛题发布',
|
||||
eng: 'Competition question release',
|
||||
anchor: 'notice',
|
||||
}
|
||||
]
|
||||
}
|
||||
export const config = {
|
||||
// zoneKey: 'kydhgw',
|
||||
// zoneId: 6,
|
||||
zoneKey:"KYDS7th",
|
||||
zoneId:11
|
||||
}
|
||||
|
||||
export const hidenMemberType = ['与会嘉宾', '院士嘉宾']
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import './index.less'
|
||||
import RenderHtml from '@/components/RenderHtml'
|
||||
import { useLocation, useParams } from 'umi';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { Breadcrumb , Divider } from 'antd';
|
||||
import views from '../img/views.png'
|
||||
import { useEffect } from 'react';
|
||||
import { getDocDetail } from '../api'
|
||||
import { useState } from 'react';
|
||||
import { defaultPage } from '../info'
|
||||
|
||||
|
||||
function Detail() {
|
||||
const location = useLocation();
|
||||
const { id } = location.pathname.includes('information') ? useParams() : { id: defaultPage[location.pathname] };
|
||||
const [ detail, setDetail ] = useState({});
|
||||
const [ cmsDir , setCmsDir ] = useState(undefined);
|
||||
const [ content , setContent]=useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
getDetail();
|
||||
},[id])
|
||||
|
||||
const getDetail = () => {
|
||||
getDocDetail(id).then(res => {
|
||||
setDetail(res.data);
|
||||
setCmsDir(res.data.cmsDir);
|
||||
setContent(Base64.decode(res.data.content));
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
return <div className="detail">
|
||||
{
|
||||
detail &&
|
||||
<div className="detail-content">
|
||||
{
|
||||
location.pathname.includes('information') && <Breadcrumb separator=">">
|
||||
{ cmsDir && <Breadcrumb.Item href="/competitions/2024/information">{ cmsDir.name }</Breadcrumb.Item> }
|
||||
<Breadcrumb.Item>正文</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
}
|
||||
<div className="detail-info">
|
||||
{
|
||||
location.pathname.includes('information') && <>
|
||||
<div className="info-text-main">
|
||||
<p className="info-name">{ detail.name }</p>
|
||||
<ul className="info-ul-value">
|
||||
{ cmsDir && <li>发布于{ cmsDir.createdAt }</li> }
|
||||
{ detail.visits && <li><img src={ views } alt="" className="mr5" />{ detail.visits }</li> }
|
||||
</ul>
|
||||
</div>
|
||||
<Divider dashed={true} />
|
||||
</>
|
||||
}
|
||||
{
|
||||
content ?
|
||||
<RenderHtml className="informations_detail imageLayerParent" value={ content } url={ location } />
|
||||
:
|
||||
<span>暂无详情~</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
export default Detail
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
import './index.less'
|
||||
import { Spin, Divider , Input } from 'antd';
|
||||
import { useState , useEffect } from 'react';
|
||||
import { information } from '../info';
|
||||
import { getDocList } from '../api'
|
||||
import empty from '../img/empty.png';
|
||||
import { useModel , Link } from 'umi';
|
||||
import Left from '../img/left.png';
|
||||
import Right from '../img/right.png';
|
||||
import SubBanner from '../img/subBanner.png';
|
||||
import Search from '../img/search.png';
|
||||
import { throttle } from '@/utils/mettingUtil';
|
||||
|
||||
function Information() {
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
const [ informationList , setInformationList ] = useState([]);
|
||||
const { dirList } = useModel('defaultConfig');
|
||||
const [ tabKey , setTabKey ] = useState(0);
|
||||
const [ positionNum ,setPositionNum ] = useState([]);
|
||||
const [ showAnchor , setShowAnchor ] = useState(false);
|
||||
const[ title ,setTitle] = useState(undefined);
|
||||
const[ searchTitle ,setSearchTitle] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if (location.pathname === '/competitions/2024/information') {
|
||||
window.addEventListener('scroll', throttleHandleScroll);
|
||||
return ComponentWillUnmount;
|
||||
} else {
|
||||
ComponentWillUnmount()
|
||||
}
|
||||
},[location.pathname,positionNum])
|
||||
|
||||
function ComponentWillUnmount() {
|
||||
window.removeEventListener("scroll", throttleHandleScroll);
|
||||
}
|
||||
|
||||
|
||||
function handleScroll() {
|
||||
let scrollTop = document.documentElement.scrollTop; //滚动条滚动高度
|
||||
setShowAnchor(scrollTop > 362);
|
||||
if(scrollTop < 362) setTabKey(0);
|
||||
if(positionNum && positionNum.length>0){
|
||||
for(let i=0;i<positionNum.length;i++){
|
||||
if(i>0 && scrollTop <= positionNum[i] && scrollTop > positionNum[i-1] ){
|
||||
setTabKey(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const throttleHandleScroll = throttle(handleScroll, 100)
|
||||
|
||||
useEffect(()=>{
|
||||
if ( JSON.stringify(dirList) !== '{}' ) {
|
||||
getAllLists();
|
||||
}
|
||||
let anchor = document.getElementsByClassName("anchor");
|
||||
if(anchor && anchor.length>1){
|
||||
let arr = [];
|
||||
for(let i=0;i<anchor.length;i++){
|
||||
arr.push(anchor[i].getBoundingClientRect().top)
|
||||
}
|
||||
setPositionNum(arr);
|
||||
}
|
||||
},[dirList,searchTitle])
|
||||
|
||||
const getAllLists = () => {
|
||||
setIsSpin(true);
|
||||
const requestList = [];
|
||||
information.category.map(e => {
|
||||
dirList[e.title] && requestList.push(getList(dirList[e.title], e.anchor,searchTitle))
|
||||
})
|
||||
Promise.all(requestList).then(res => {
|
||||
let totalList = {}
|
||||
res.map(e => {
|
||||
totalList[e.name] = e.list
|
||||
})
|
||||
setInformationList(totalList)
|
||||
setIsSpin(false)
|
||||
})
|
||||
}
|
||||
|
||||
const getList = (id, name,title) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
getDocList(id).then(res => {
|
||||
let list = res.rows;
|
||||
list = title ? list.filter(i=>i.name.indexOf(title)>-1 || i.summary.indexOf(title)>-1) : list;
|
||||
list.forEach(e => {
|
||||
if (e.publishTime) {
|
||||
let time = e.publishTime.split('/');
|
||||
e.date1 = `${time[0]}年${time[1]}月`;
|
||||
e.date2 = `${time[2]}日`;
|
||||
} else {
|
||||
e.date1 = e.date2 = '-'
|
||||
}
|
||||
})
|
||||
resolve({ name, list: list });
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const scrollToAnchor = (anchorName) => {
|
||||
if (anchorName) {
|
||||
let anchorElement = document.getElementById(anchorName);
|
||||
if(anchorElement) { anchorElement.scrollIntoView({block: 'start', behavior: 'smooth'}); }
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="information">
|
||||
{/* {
|
||||
information.category &&
|
||||
<div className="tab">
|
||||
<div className='tabPanel'>
|
||||
{
|
||||
information.category.map((e, k) => {
|
||||
return <div key={ k } onClick={() => { scrollToAnchor(e.anchor);setTabKey(k) }} className={`tab-item ${k===tabKey?"active":""}`}>{ e.title }</div>
|
||||
})
|
||||
}
|
||||
<Input
|
||||
className="searchInput"
|
||||
value={ title }
|
||||
// onBlur={ (e) => { setTitle(e.target.value) } }
|
||||
onChange={ (e) => { setTitle(e.target.value) } }
|
||||
onPressEnter={()=>{setSearchTitle(title)}}
|
||||
placeholder="请搜索文章标题关键词"
|
||||
suffix={<img src={Search} width={16}/>}
|
||||
style={{width:"213px"}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
} */}
|
||||
<div className="tabPanel">
|
||||
<Input
|
||||
className="searchInput"
|
||||
value={ title }
|
||||
// onBlur={ (e) => { setTitle(e.target.value) } }
|
||||
onChange={ (e) => { setTitle(e.target.value) } }
|
||||
onPressEnter={()=>{setSearchTitle(title)}}
|
||||
placeholder="请搜索文章标题关键词"
|
||||
suffix={<img src={Search} width={16}/>}
|
||||
style={{width:"213px"}}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
information.category && showAnchor &&
|
||||
<div className='anchorPart' style={{top:362,left:(document.documentElement.clientWidth-1200)/2-125}}>
|
||||
{
|
||||
information.category.map((e,k)=>{
|
||||
return <li key={ k } className={`${k===tabKey?"active":""}`} onClick={() => { scrollToAnchor(e.anchor);}}>{ e.title }</li>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<Spin spinning={isSpin}>
|
||||
{
|
||||
information.category.map((e) => {
|
||||
return <div className="content" key={ e.anchor }>
|
||||
<div className="anchor" id={ e.anchor }></div>
|
||||
{/* <div className="content-title">
|
||||
<p>{ e.title }</p>
|
||||
<p>{ e.eng }</p>
|
||||
</div> */}
|
||||
<div style={{textAlign:"center",paddingTop:18,paddingBottom:50}}>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>{ e.title }</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>{ e.eng.toUpperCase() }</span></p>
|
||||
</div>
|
||||
<div className="content-wrapper">
|
||||
{
|
||||
informationList[e.anchor] && informationList[e.anchor].length > 0 ? informationList[e.anchor].map(( e, k ) => {
|
||||
return <div className="content-item" key={ k }>
|
||||
<div className="item-left">{ e.date2 }</div>
|
||||
<div className="item-right">
|
||||
<p className="time">{ e.date1 }</p>
|
||||
<Divider style={{ color: 'rgba(9, 37, 77, 0.1)', margin: '0px' }}/>
|
||||
<Link to={ `/competitions/2024/information/${ e.id }` } className="item-title task-hide">{ e.name }</Link>
|
||||
<p className="item-desc task-hide-2">{ e.summary }</p>
|
||||
<a href={ `/competitions/2024/information/${ e.id }` } className="read-more">阅读全文 <span>→</span></a>
|
||||
</div>
|
||||
</div>
|
||||
}):
|
||||
<img className="empty" src={ empty } alt="" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</Spin>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Information
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
.information {
|
||||
.anchorPart{
|
||||
width: 115px;
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
box-shadow: 0px 0px 12px 1px rgba(107,136,204,0.06);
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
z-index: 11;
|
||||
padding:12px 0px;
|
||||
li{
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
padding:0px 15px;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #1F2329;
|
||||
cursor: pointer;
|
||||
&.active{
|
||||
color: #6233DE;
|
||||
}
|
||||
&.active::after{
|
||||
width: 2px;
|
||||
height: 29px;
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
border-radius: 0px 0px 0px 0px;
|
||||
left: 0px;
|
||||
content: "";
|
||||
top: 8px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
.homeMaintitle{
|
||||
font-size: 48px;
|
||||
position: relative;
|
||||
margin: 0px auto;
|
||||
width: 224px;
|
||||
img{
|
||||
width: 12px;
|
||||
position: absolute;
|
||||
&:first-child{
|
||||
left: -12px;
|
||||
}
|
||||
&:last-child{
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
span{
|
||||
margin:0px 22px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
.ant-spin-container {
|
||||
background: url('../img/back.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
position: relative;
|
||||
font-size: 15px;
|
||||
width: 100%;
|
||||
&>img{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
object-fit: cover;
|
||||
}
|
||||
// .title {
|
||||
// font-size: 30px;
|
||||
// }
|
||||
// .desc {
|
||||
// margin-top: 19px;
|
||||
// opacity: 80%;
|
||||
// }
|
||||
|
||||
}
|
||||
.tab {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height:62px;
|
||||
background-color:#ffffff;
|
||||
}
|
||||
.tabPanel{
|
||||
width: 1200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin:35px auto 0px;
|
||||
position: relative;
|
||||
height: 32px;
|
||||
.tab-item {
|
||||
margin: 0 69px;
|
||||
cursor: pointer;
|
||||
height:62px;
|
||||
line-height:62px;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
&.active::after{
|
||||
position: absolute;
|
||||
width: 67px;
|
||||
height: 2px;
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
border-radius: 0px 0px 0px 0px;
|
||||
content: "";
|
||||
left: 50%;
|
||||
margin-left: -33px;
|
||||
bottom: 0px;
|
||||
}
|
||||
&.active,&:hover{
|
||||
color: #6233DE;
|
||||
}
|
||||
}
|
||||
.searchInput{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
background-color: #fff;
|
||||
&:hover,&.ant-input-affix-wrapper:focus{
|
||||
border-color: #6233DE!important;
|
||||
box-shadow: 0 0 0 2px rgba(98, 51, 222, 0.1)!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.anchor {
|
||||
position: absolute;
|
||||
top: -50px;
|
||||
}
|
||||
.content {
|
||||
width: 1200px;
|
||||
margin: auto;
|
||||
position: relative;
|
||||
padding:50px 0px;
|
||||
.content-title {
|
||||
width: 531px;
|
||||
height: 157px;
|
||||
background: url('../img/info-title-bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
p:first-child {
|
||||
font-family: Alimama ShuHeiTi;
|
||||
color: #0e1015;
|
||||
font-size: 40px;
|
||||
margin-top: 60px;
|
||||
}
|
||||
p:last-child {
|
||||
font-family:PingFang SC;
|
||||
color: #0d41c5;
|
||||
font-size: 15px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
.content-wrapper {
|
||||
.content-item {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
.item-left {
|
||||
font-family: PingFang SC;
|
||||
font-weight: 700;
|
||||
color: #6233DE;
|
||||
font-size: 24px;
|
||||
margin-right: 30px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.item-right {
|
||||
flex: 1;
|
||||
.time {
|
||||
color: #5F6577;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.item-title {
|
||||
font-weight: 700;
|
||||
color: #252b3a;
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
display: block;
|
||||
&:hover{
|
||||
color: #6233DE;
|
||||
}
|
||||
}
|
||||
.item-desc {
|
||||
color: #49454F;
|
||||
font-size: 16px;
|
||||
line-height: 32px;
|
||||
margin-top: 20px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.read-more {
|
||||
float: right;
|
||||
color: #6233DE;
|
||||
font-size: 15px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
span{
|
||||
transition: 0.2s;
|
||||
display: block;
|
||||
}
|
||||
&:hover>span {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail{
|
||||
background: url('../img/information-detail-bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
padding-bottom: 60px;
|
||||
.detail-content {
|
||||
width: 1200px;
|
||||
margin: 0px auto;
|
||||
padding: 30px 0px;
|
||||
}
|
||||
.ant-breadcrumb {
|
||||
a {
|
||||
color: #0d41c5;
|
||||
}
|
||||
}
|
||||
.detail-info{
|
||||
background-color:#fefefe;
|
||||
border-radius:4px;
|
||||
box-shadow:0px 0px 15px rgba(30, 47, 162, 0.06);
|
||||
padding:30px 35px 50px;
|
||||
margin-top: 28px;
|
||||
.info-text-main{
|
||||
.info-name{
|
||||
color:#1f2329;
|
||||
font-size:22px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 14px!important;
|
||||
word-break: break-all;
|
||||
}
|
||||
.info-ul-value{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
li{
|
||||
color:#4c5876;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-right: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
img {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.homeSubtitle{
|
||||
margin-top: 12px;
|
||||
text-align: center;
|
||||
span{
|
||||
font-size: 16px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
background: -webkit-linear-gradient(76deg, rgba(24,163,168,0.77) 0%, #2E89FF 51%, rgba(158,3,127,0.77) 100%);
|
||||
background: linear-gradient(76deg, rgba(24,163,168,0.77) 0%, #2E89FF 51%, rgba(158,3,127,0.77) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent; /* 针对WebKit浏览器 */
|
||||
color: transparent; /* 兼容其他浏览器 */
|
||||
letter-spacing: 2px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { Tooltip } from 'antd'
|
||||
import './index.less'
|
||||
|
||||
function MemberItem(props) {
|
||||
const { className, data } = props
|
||||
|
||||
return <div className={ `${ className } member-item` }>
|
||||
{
|
||||
data.name && <>
|
||||
<img src={ data.imageUrl } alt="" className="head-img"/>
|
||||
<span className="task-hide">{ data.name }</span>
|
||||
<Tooltip title={ data.introduction }>
|
||||
<p className="task-hide-2">{ data.introduction }</p>
|
||||
</Tooltip>
|
||||
<div className="line"></div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
export default MemberItem
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
.member-item {
|
||||
width: 200px;
|
||||
height: 315px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-bottom: 1.5px solid linear-gradient(90deg,#08428e 0%,#019765 100%);
|
||||
margin-bottom: 35px;
|
||||
.head-img {
|
||||
width: 200px;
|
||||
height: 250px;
|
||||
border: 2px solid #ffffff;
|
||||
object-fit: cover;
|
||||
background-color: #B6B6BB;
|
||||
}
|
||||
span {
|
||||
position: absolute;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
bottom: 78px;
|
||||
left: -40px;
|
||||
width:84px;
|
||||
line-height: 29px;
|
||||
background-image:url('../img/orz1.png');
|
||||
background-size: 100% 100%;
|
||||
text-align: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
p {
|
||||
margin-top: 15px;
|
||||
color: #252b3a;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
.line {
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
width: 100%;
|
||||
height: 1.5px;
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
import './index.less'
|
||||
import { Spin } from 'antd';
|
||||
import React,{ useState , useEffect } from 'react';
|
||||
import MemberItem from '../memberitem'
|
||||
import { getOrganization , getPartnerList , getDocList , getDocDetail } from '../api.js';
|
||||
import { hidenMemberType } from '../info';
|
||||
import { Base64 } from 'js-base64';
|
||||
import RenderHtml from '@/components/RenderHtml'
|
||||
import orz2 from '../img/orz2.png';
|
||||
import Logo from '../img/logo.png';
|
||||
import Team from '../img/team.png';
|
||||
import Left from '../img/left.png';
|
||||
import Right from '../img/right.png';
|
||||
|
||||
function Organization() {
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
const [ organization, setOrganization ] = useState([])
|
||||
const [ partner, setPartner ] = useState([]);
|
||||
const [ orz , setOrz ] = useState([]);
|
||||
|
||||
useEffect(()=>{
|
||||
getList();
|
||||
getPartner();
|
||||
Init();
|
||||
},[])
|
||||
|
||||
const getPartner = () => {
|
||||
getPartnerList().then(res => {
|
||||
let rows = res?.rows.length > 0 ? res?.rows.filter(i=>i.typeName.includes("高校")):[];
|
||||
setPartner(rows);
|
||||
}).catch(console.error())
|
||||
}
|
||||
|
||||
const getList = () => {
|
||||
setIsSpin(true);
|
||||
getOrganization().then(res => {
|
||||
let rows = res?.rows;
|
||||
rows = rows.map(i=>{
|
||||
let members= i.zoneMemberList && i.zoneMemberList.length>0 ? i.zoneMemberList.filter(e=>e.memberLevel !== "主席"):i.zoneMemberList;
|
||||
return {...i,unPresident:members.length>0?members.map(e=>{return e.name}):[]}
|
||||
})
|
||||
setOrganization(rows);
|
||||
setIsSpin(false);
|
||||
})
|
||||
}
|
||||
|
||||
const Init=()=>{
|
||||
getDocList(658).then(res => {
|
||||
if( res?.rows?.length > 0){
|
||||
let arr = [];
|
||||
for(let i=0;i<res?.rows.length;i++){
|
||||
let e = res?.rows[i];
|
||||
arr.push(getDetailForId(e.id));
|
||||
}
|
||||
Promise.all(arr).then(res=>{
|
||||
setOrz(res)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const getDetailForId = (id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
getDocDetail(id).then(res => {
|
||||
let detail = res.data;
|
||||
resolve({detail:detail});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return <div className="organization">
|
||||
<div className='orzLogo'>
|
||||
<img src={Logo} alt="" height={84}/>
|
||||
<div className='orzDesc'>
|
||||
<img src={orz2} alt="" width={138}/>
|
||||
<div className='descCon'>
|
||||
<img src={Team} width={33}/>CCF开源发展委员会是一个致力于推动开源文化、技术、教育和产业发展的专业组织。重点聚焦共同打造开源、开放、中立的产学研协同开源创新服务平台,探索建立CCF开源项目孵化机制,培育原始开源创新项目,依托CCF联接科教资源、产业资源和社会资源等,形成产、教、研联动的开源创新模式,推动CCF开源品牌建设和开源社区运营,为CCF会员乃至全球开源创新实践者提供高水平的开源创新服务,助力我国开源生态建设的发展。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className='homeMaintitle' style={{margin:"50px auto 0px"}}><img src={Left} /><span>组织架构</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>ORGANIZARIONAL STRUCTURE</span></p>
|
||||
<Spin spinning={isSpin}>
|
||||
{/* {
|
||||
organization && organization.length > 0 && organization.map((i, k) => {
|
||||
if (!hidenMemberType.includes(i.typeName)) {
|
||||
return <div className="module" key={ k }>
|
||||
<p className='homeMaintitle'><img src={Left} /><span>{ i.typeName }</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>{subtitle[k]}</span></p>
|
||||
<p className="module-desc">{ i.typeIntroduction }</p>
|
||||
{
|
||||
i.zoneMemberList && i.zoneMemberList.length > 0 && <div className="module-content">
|
||||
{
|
||||
i.zoneMemberList.map(( e, subK ) => {
|
||||
return e.memberLevel === "主席" && <MemberItem key={ subK } className={`module-item`} data={ e } ></MemberItem>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{
|
||||
i.unPresident && i.unPresident.length>0 && <p className='membersSub'><img src={Team} width={33} />{i.typeName}委员:{ i.unPresident.join("、")}</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
})
|
||||
} */}
|
||||
{
|
||||
orz && orz.length > 0 && orz.map((i,k)=>{
|
||||
let detail = i.detail;
|
||||
return(
|
||||
<>
|
||||
<p className='orzTitle'><img src={Team} width={33} style={{marginRight:13}}/>{detail.name}</p>
|
||||
<div className="module" key={ k }>
|
||||
{
|
||||
detail.content ?
|
||||
<RenderHtml className="informations_detail imageLayerParent" value={ Base64.decode(detail.content) } url={ location } />
|
||||
:
|
||||
""
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Spin>
|
||||
{
|
||||
partner?.length > 0 ?
|
||||
<div style={{textAlign:"center",paddingTop:68,paddingBottom:50}}>
|
||||
<p className='homeMaintitle' style={{width:224,margin:"0px auto"}}><img src={Left} /><span>合作高校</span><img src={Right} /></p>
|
||||
<p className="homeSubtitle"><span>PARTNERS</span></p>
|
||||
<div className='partnersLogo'>
|
||||
{
|
||||
partner.map((i,k)=>{
|
||||
return i.zonePartnersList && i.zonePartnersList.length >0 ? i.zonePartnersList.map((e,key)=>{
|
||||
return(
|
||||
<a key={k}><img src={e.logo} alt=""/></a>
|
||||
)
|
||||
})
|
||||
:""
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Organization
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
.organization {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
padding-bottom: 60px;
|
||||
.ant-spin-nested-loading {
|
||||
width: 1200px;
|
||||
}
|
||||
.homeMaintitle{
|
||||
font-size: 48px;
|
||||
position: relative;
|
||||
margin-bottom: 0px;
|
||||
img{
|
||||
width: 12px;
|
||||
position: absolute;
|
||||
&:first-child{
|
||||
left: -12px;
|
||||
}
|
||||
&:last-child{
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
span{
|
||||
margin:0px 22px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
.homeSubtitle{
|
||||
margin-top: 12px;
|
||||
text-align: center;
|
||||
span{
|
||||
font-size: 16px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
background: -webkit-linear-gradient(76deg, rgba(24,163,168,0.77) 0%, #2E89FF 51%, rgba(158,3,127,0.77) 100%);
|
||||
background: linear-gradient(76deg, rgba(24,163,168,0.77) 0%, #2E89FF 51%, rgba(158,3,127,0.77) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent; /* 针对WebKit浏览器 */
|
||||
color: transparent; /* 兼容其他浏览器 */
|
||||
letter-spacing: 2px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
.back-img {
|
||||
width: 100%;
|
||||
img{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
.orzLogo{
|
||||
padding-top:48px;
|
||||
text-align: center;
|
||||
.orzDesc{
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
min-height: 170px;
|
||||
margin-top: 30px;
|
||||
&>img{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top:-18px;
|
||||
z-index: 1;
|
||||
}
|
||||
.descCon{
|
||||
position: absolute;
|
||||
background: #F6F7FA;
|
||||
box-shadow: 0px 0px 10px 1px rgba(7,70,165,0.11);
|
||||
border-radius: 10px 10px 10px 10px;
|
||||
border: 2px solid #FFFFFF;
|
||||
padding:20px 50px 20px 110px;
|
||||
line-height: 34px;
|
||||
text-align: left;
|
||||
left: 50px;
|
||||
text-align: justify;
|
||||
font-size: 15px;
|
||||
color: #040E29;
|
||||
img{
|
||||
float: left;
|
||||
margin-right: 8px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.orzTitle{
|
||||
font-family: YouSheBiaoTiHei;
|
||||
font-weight: 400;
|
||||
font-size: 38px;
|
||||
color: #0A0A0A;
|
||||
letter-spacing: 3px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.module {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 24px;
|
||||
background: #F6F7FA;
|
||||
box-shadow: 0px 0px 10px 1px rgba(7,70,165,0.11);
|
||||
border-radius: 22px;
|
||||
padding:20px 40px;
|
||||
margin-bottom: 35px;
|
||||
border: 2px solid #FFFFFF;
|
||||
.module-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family:Alimama ShuHeiTi;
|
||||
color:#0e1015;
|
||||
font-size:34px;
|
||||
margin-bottom: 30px;
|
||||
span {
|
||||
margin: 0 30px;
|
||||
position: relative;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -3px;
|
||||
left: -10px;
|
||||
opacity: 9%;
|
||||
width: 100%;
|
||||
height: 11px;
|
||||
background-color: #0d41c5;
|
||||
}
|
||||
}
|
||||
img {
|
||||
width: 48px;
|
||||
height: 21px;
|
||||
&:last-child {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.module-desc {
|
||||
color: #252b3a;
|
||||
font-size: 15px;
|
||||
margin-bottom: 37px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.module-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.module-item {
|
||||
margin-right: 55px;
|
||||
margin-left: 55px;
|
||||
margin-bottom: 32px;
|
||||
&:nth-child(4n) {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-carousel{
|
||||
width: 1200px;
|
||||
}
|
||||
.membersSub{
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #040E29;
|
||||
line-height: 40px;
|
||||
img{
|
||||
float: left;
|
||||
margin: 5px 10px 0px 0px;
|
||||
}
|
||||
}
|
||||
.partnersLogo{
|
||||
display: flex!important;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 54px;
|
||||
width: 1200px;
|
||||
a{
|
||||
margin-right: 42px;
|
||||
padding: 6px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 0px 6px rgba(28, 48, 175, 0.03);
|
||||
height: 83px;
|
||||
width: 163px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 35px;
|
||||
border:1px solid #fff;
|
||||
&:hover{
|
||||
border-color: #6233DE;
|
||||
}
|
||||
&:nth-child(6n){
|
||||
margin-right: 0px;
|
||||
}
|
||||
img{
|
||||
max-height: 55px;
|
||||
max-width: 130px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
import './index.less'
|
||||
import { useState , useEffect } from 'react';
|
||||
import RenderHtml from '@/components/RenderHtml';
|
||||
import { useParams , Link } from 'umi';
|
||||
import { getDocDetail } from '../api';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { throttle } from '@/utils/mettingUtil';
|
||||
|
||||
function Track(props) {
|
||||
const [ tabKey , setTabKey ] = useState(0);
|
||||
const [ content , setContent]=useState(undefined);
|
||||
const [ dealContent , setDealContent]=useState(undefined);
|
||||
const [ showAnchor , setShowAnchor ] = useState(false);
|
||||
const [ anchor , setAnchor ] = useState(false);
|
||||
const [ menu , setMenu]=useState([]);
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(()=>{
|
||||
if (location.pathname.indexOf('/competitions/2024/track')>-1) {
|
||||
window.addEventListener('scroll', throttleHandleScroll);
|
||||
return ComponentWillUnmount;
|
||||
} else {
|
||||
ComponentWillUnmount()
|
||||
}
|
||||
},[location.pathname])
|
||||
|
||||
function ComponentWillUnmount() {
|
||||
window.removeEventListener("scroll", throttleHandleScroll);
|
||||
}
|
||||
function handleScroll() {
|
||||
let scrollTop = document.documentElement.scrollTop; //滚动条滚动高度
|
||||
setShowAnchor(scrollTop > 320);
|
||||
if(scrollTop < 320){setAnchor("")}
|
||||
}
|
||||
const throttleHandleScroll = throttle(handleScroll, 100)
|
||||
|
||||
useEffect(()=>{
|
||||
if(id){
|
||||
setTabKey(id);
|
||||
getDetail();
|
||||
}
|
||||
},[id])
|
||||
|
||||
|
||||
const getDetail = () => {
|
||||
getDocDetail(id).then(res => {
|
||||
let content = Base64.decode(res.data.content);
|
||||
setContent(content);
|
||||
})
|
||||
}
|
||||
|
||||
const scrollToAnchor = (anchorName) => {
|
||||
if (anchorName) {
|
||||
let anchorElement = document.getElementById(anchorName);
|
||||
if(anchorElement) { setAnchor(anchorName);anchorElement.scrollIntoView({block: 'start', behavior: 'smooth'}); }
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
if(content){
|
||||
let c = content;
|
||||
const hTagsRegex = /<h([1-6])(.*?)>(.*?)<\/h\1>/g;
|
||||
let match;
|
||||
let list = [];
|
||||
while ((match = hTagsRegex.exec(content))) {
|
||||
list.push({level:+match[1],id:match[3]})
|
||||
c = c.replace(`${match[0]}`, `<div id="${match[3]}"></div>${match[0]}`);
|
||||
}
|
||||
setMenu(list);
|
||||
setDealContent(c);
|
||||
}
|
||||
}, [content]);
|
||||
return(
|
||||
<div className='track'>
|
||||
<div className='tabPanel'>
|
||||
<div className="tab">
|
||||
<Link key={ 633 } to='/competitions/2024/track/633' className={`tab-item ${tabKey === "633" ?"active":""}`}>开源项目贡献赛道</Link>
|
||||
<Link key={ 634 } to='/competitions/2024/track/634' className={`tab-item ${tabKey === "634" ?"active":""}`}>开源任务挑战赛道</Link>
|
||||
<Link key={ 635 } to='/competitions/2024/track/635' className={`tab-item ${tabKey === "635" ?"active":""}`}>开源案例教学赛道</Link>
|
||||
<Link key={ 636 } to='/competitions/2024/track/636' className={`tab-item ${tabKey === "636" ?"active":""}`}>开源代码评注赛道</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="detail-info">
|
||||
{/* <div className="info-text-main">
|
||||
<p className="info-name">{ detail.name }</p>
|
||||
<ul className="info-ul-value">
|
||||
{ cmsDir && <li>发布于{ cmsDir.createdAt }</li> }
|
||||
{ detail && detail.visits && <li><img src={ views } alt="" className="mr5" />{ detail.visits }</li> }
|
||||
</ul>
|
||||
</div>
|
||||
<Divider dashed={true} /> */}
|
||||
{
|
||||
menu?.length > 0 && showAnchor ?
|
||||
<ul className='menuPanel' style={{top:320,left:(document.documentElement.clientWidth-1200)/2-225}}>
|
||||
{
|
||||
menu.map((i,k)=>{
|
||||
return <li key={k} style={{paddingLeft:`${i.level*10}px`}} className={`${anchor ===i.id?"active":""}`}><a onClick={()=>scrollToAnchor(i.id)}>{i?.id}</a></li>
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
:""
|
||||
}
|
||||
{
|
||||
dealContent ?
|
||||
<RenderHtml className="informations_detail imageLayerParent" value={ dealContent } url={ location } />
|
||||
:
|
||||
<span>暂无详情~</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Track;
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
.track{
|
||||
padding-bottom: 40px;
|
||||
position: relative;
|
||||
.tabPanel{
|
||||
text-align: center;
|
||||
padding:35px 0px 0px;
|
||||
}
|
||||
.tab {
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left:40px;
|
||||
.tab-item {
|
||||
margin-right: 78px;
|
||||
font-weight: 400;
|
||||
font-size: 17px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
color: #040E29;
|
||||
border-radius: 4px;
|
||||
padding:0px 10px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
&.active{
|
||||
color: #fff;
|
||||
background: linear-gradient( 103deg, #5950F3 0%, #6B16CA 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail-info{
|
||||
width: 1200px;
|
||||
border-radius:4px;
|
||||
box-shadow:0px 0px 15px rgba(30, 47, 162, 0.06);
|
||||
padding:30px 35px 50px;
|
||||
margin:28px auto 0px;
|
||||
background-color: #fff;
|
||||
.menuPanel{
|
||||
position: fixed;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
width: 200px;
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
padding:12px 0px;
|
||||
box-shadow: 0px 0px 12px 1px rgba(107, 136, 204, 0.06);
|
||||
li{
|
||||
position: relative;
|
||||
&.active::before{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
content: "";
|
||||
background: linear-gradient(103deg, #5950F3 0%, #6B16CA 100%);
|
||||
}
|
||||
&.active,&:hover{
|
||||
a{
|
||||
color: #6B16CA;
|
||||
}
|
||||
}
|
||||
a{
|
||||
font-size: 14px;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #1F2329;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 145px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.info-text-main{
|
||||
.info-name{
|
||||
color:#1f2329;
|
||||
font-size:22px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 14px!important;
|
||||
word-break: break-all;
|
||||
}
|
||||
.info-ul-value{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
li{
|
||||
color:#4c5876;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-right: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
img {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,8 +172,6 @@ export default function request(url: string, option: any, flag?: boolean) {
|
|||
Authorization:token
|
||||
}
|
||||
}
|
||||
console.log("1:",url);
|
||||
console.log("2:",newOptions.headers);
|
||||
|
||||
const expirys = options.expirys && 60
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export function getTocContent() {
|
|||
|
||||
const tokenizer = {
|
||||
heading(src: string) {
|
||||
const cap = headingRegex.exec(src)
|
||||
const cap = headingRegex.exec(src);
|
||||
if (cap) {
|
||||
return {
|
||||
type: 'heading',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
export function throttle(fn, delay){
|
||||
let timer = null; // 使用定时器实现
|
||||
return function (){
|
||||
let _this = this; // 当前 this 保存,以免后续处理中 this 丢失
|
||||
if(!timer){
|
||||
fn.apply(_this, arguments);
|
||||
timer = setTimeout(function (){
|
||||
timer = null;
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
yarn.lock
|
|
@ -4682,6 +4682,15 @@ aws4@^1.8.0:
|
|||
resolved "https://registry.npmmirror.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3"
|
||||
integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==
|
||||
|
||||
axios@^1.6.8:
|
||||
version "1.6.8"
|
||||
resolved "https://registry.npmmirror.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
|
||||
integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.6"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
babel-core@7.0.0-bridge.0:
|
||||
version "7.0.0-bridge.0"
|
||||
resolved "https://registry.npmmirror.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
|
||||
|
|
@ -8001,7 +8010,7 @@ flv.js@1.5.0:
|
|||
es6-promise "^4.2.5"
|
||||
webworkify "^1.5.0"
|
||||
|
||||
follow-redirects@^1.0.0:
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.15.6:
|
||||
version "1.15.6"
|
||||
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
|
||||
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
|
||||
|
|
@ -8070,6 +8079,15 @@ form-data@^3.0.0:
|
|||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
|
|
@ -13395,6 +13413,11 @@ proxy-addr@~2.0.5, proxy-addr@~2.0.7:
|
|||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
prr@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||
|
|
|
|||