forked from Gitlink/forgeplus-react
1706 lines
53 KiB
TypeScript
Executable File
1706 lines
53 KiB
TypeScript
Executable File
import React, { FC } from 'react'
|
||
import { userInfo } from '@/utils/authority'
|
||
import { Modal, Row, Col, Checkbox, message } from 'antd';
|
||
import { findLocalIp } from '@/components/Exercise/ip';
|
||
import { checkIp } from '@/service/exercise';
|
||
import { requestFullScreen } from '@/utils/fullscreen';
|
||
import { contentType } from './contentType';
|
||
import { useHistory } from 'umi';
|
||
import moment from 'moment';
|
||
import md5 from 'md5'
|
||
import ENV from './env'
|
||
import mediator from '@/components/mediator';
|
||
|
||
export interface exerciseStartParams {
|
||
ip_limit: string,
|
||
ip_bind: boolean,
|
||
inner_ip: string[],
|
||
public_ip: string[],
|
||
exercise_tips: string[],
|
||
open_camera: boolean,
|
||
screen_open: boolean,
|
||
screen_num: number,
|
||
coursesId: number,
|
||
exerciseId: number,
|
||
login: string,
|
||
identity_verify: boolean,
|
||
history: any,
|
||
current_status: number
|
||
};
|
||
|
||
export const ZimuSort = [
|
||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
|
||
'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
|
||
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
||
]
|
||
export const RomanNumber = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX"]
|
||
/**
|
||
*@所有实训tags集合生成
|
||
*status为数组 status=["提交中","补交中"]
|
||
*/
|
||
interface StatusTagsProps {
|
||
status?: any[]
|
||
is_random?: any | string
|
||
temporary?: boolean
|
||
[key: string]: any
|
||
}
|
||
export const StatusTags: FC<StatusTagsProps> = (props) => {
|
||
const tags: any = {
|
||
已截止: {
|
||
class: 'tag-style bg-pink ml10',
|
||
},
|
||
提交中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
进行中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
未发布: {
|
||
class: 'tag-style bgB8B8B8 ml10',
|
||
},
|
||
补交中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
}
|
||
return (
|
||
props.data &&
|
||
props.data.map(function (v: any, k: number) {
|
||
return (
|
||
<span key={k} className={tags[v] && tags[v]['class']}>
|
||
{v}
|
||
</span>
|
||
)
|
||
})
|
||
)
|
||
}
|
||
|
||
/**
|
||
*@教学课堂-作业列表状态名字
|
||
*status为 number
|
||
*/
|
||
export const formatHomeWorkStatusToName = (status: number) => {
|
||
const mapping: any = {
|
||
[-1]: "重做中",
|
||
0: "未开启",
|
||
1: "未通关",
|
||
2: "按时通关"
|
||
}
|
||
|
||
return mapping[status] || "迟交通关"
|
||
}
|
||
|
||
/**
|
||
*@教学课堂-作业列表状态
|
||
*status为 number
|
||
*/
|
||
export const HomeWorkListStatus = (props: { status: number }) => {
|
||
const wStatus: any = {
|
||
[-1]: {
|
||
name: '重做中',
|
||
class: 'c-orange',
|
||
},
|
||
0: {
|
||
name: '未开启',
|
||
class: 'c-black',
|
||
},
|
||
1: {
|
||
name: '未通关',
|
||
class: 'c-red',
|
||
},
|
||
2: {
|
||
name: '按时通关',
|
||
class: 'c-green',
|
||
},
|
||
3: {
|
||
name: '迟交通关',
|
||
class: 'c-orange',
|
||
},
|
||
}
|
||
|
||
return (
|
||
<span className={wStatus?.[props.status]?.['class']}>
|
||
{wStatus?.[props.status]?.['name']}
|
||
</span>
|
||
)
|
||
}
|
||
|
||
/**
|
||
*@教学课堂-作业心情状态
|
||
*status为 number
|
||
*/
|
||
export const HomeWorkDetailStatus = (props: { status: number }) => {
|
||
const wStatus: any = {
|
||
[-1]: {
|
||
name: '重做中',
|
||
class: 'c-orange',
|
||
color: '#999999',
|
||
},
|
||
0: {
|
||
name: '未开启',
|
||
class: 'c-black',
|
||
color: '#999999',
|
||
},
|
||
1: {
|
||
name: '未通关',
|
||
class: 'c-red',
|
||
color: '#d4443d',
|
||
},
|
||
2: {
|
||
name: '按时通关',
|
||
class: 'c-green',
|
||
color: '#57be40',
|
||
},
|
||
3: {
|
||
name: '迟交通关',
|
||
class: 'c-orange',
|
||
color: '#f09143',
|
||
},
|
||
}
|
||
|
||
return (
|
||
<span style={{ marginLeft: '10px', color: '#fff', background: wStatus?.[props.status]?.['color'], borderRadius: '20px', width: "65px", height: '18px', justifyContent: 'center', display: 'inline-flex', lineHeight: '18px' }}>
|
||
{wStatus?.[props.status]?.['name']}
|
||
</span>
|
||
)
|
||
}
|
||
|
||
/**
|
||
*@教学课堂-毕设选题tags集合生成
|
||
*status为数组 status=["提交中","补交中"]
|
||
*/
|
||
export const StatusGraduationProjectTags: FC<StatusTagsProps> = (
|
||
props: any,
|
||
) => {
|
||
const { status } = props
|
||
const tags: any = {
|
||
0: {
|
||
class: 'tag-style bg-blue ml10',
|
||
name: '待选中',
|
||
},
|
||
1: {
|
||
class: 'tag-style bg-blue ml10',
|
||
name: '待确认',
|
||
},
|
||
2: {
|
||
class: 'tag-style bg-pink ml10',
|
||
name: '已确认',
|
||
},
|
||
}
|
||
try {
|
||
return (
|
||
<span className={tags[status]['class']}>{tags[status]['name']}</span>
|
||
)
|
||
} catch (e) {
|
||
console.log('utils.StatusGraduationProjectTags', props.status)
|
||
}
|
||
}
|
||
|
||
export const ExerciseStatus: any = {
|
||
1: "未发布",
|
||
2: "考试中",
|
||
3: "已截止",
|
||
4: "已结束",
|
||
99: "模拟考试中"
|
||
}
|
||
export const PollsStatus: any = { 1: "未发布", 2: "提交中", 3: "已截止", 4: "已结束" }
|
||
/**
|
||
*@教学课堂tags集合生成
|
||
*status为数组 status=["提交中","补交中"]
|
||
*任务状态数组: 未发布、提交中、评阅中、补交中、未开启补交等
|
||
*/
|
||
export const StatusClassroomsTags: FC<StatusTagsProps> = props => {
|
||
let tags: any = {
|
||
模拟考试中: {
|
||
class: 'tag-style bg-light-pink ml10',
|
||
},
|
||
已开启防作弊: {
|
||
class: 'tag-style-fzb ml10 iconfont icon-fangzuobi',
|
||
},
|
||
公开: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
已开启补交: {
|
||
class: 'tag-style bg-green ml10',
|
||
},
|
||
未开启补交: {
|
||
class: 'tag-style bg-pink ml10soft',
|
||
},
|
||
未发布: {
|
||
class: 'tag-style bgB8B8B8 ml10soft',
|
||
},
|
||
未开始: {
|
||
class: 'tag-style bg-c5d6ff ml10soft',
|
||
},
|
||
匿名作品: {
|
||
class: 'tag-style bg-cyan ml10',
|
||
},
|
||
已选择: {
|
||
class: 'tag-style bg-grey-ede ml10',
|
||
},
|
||
已结束: {
|
||
class: 'tag-style bg-grey-ede ml10soft',
|
||
},
|
||
提交中: {
|
||
class: 'tag-style bg-blue ml10soft',
|
||
},
|
||
进行中: {
|
||
class: 'tag-style bg-blue ml10soft',
|
||
},
|
||
匿评中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
申诉中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
考试中: {
|
||
class: 'tag-style bg-light-blue ml10',
|
||
},
|
||
补交中: {
|
||
class: 'tag-style bg-blue ml10soft',
|
||
},
|
||
评阅中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
待选中: {
|
||
class: 'tag-style bg-blue ml10',
|
||
},
|
||
交叉评阅中: {
|
||
class: 'tag-style bg-light-orange ml10',
|
||
},
|
||
已开启交叉评阅: {
|
||
class: 'tag-style bg-lightblue-purple ml10',
|
||
},
|
||
待确认: {
|
||
class: 'tag-style bg-lightblue-purple ml10',
|
||
},
|
||
待处理: {
|
||
class: 'tag-style bg-lightblue-purple ml10',
|
||
},
|
||
私有: {
|
||
class: 'tag-style bg-lightblue-purple ml10',
|
||
},
|
||
未提交: {
|
||
class: 'tag-style bg-lightblue-purple ml10',
|
||
},
|
||
已确认: {
|
||
class: 'tag-style bg-light-pink ml10',
|
||
},
|
||
已发布: {
|
||
class: 'tag-style bg-light-blue ml10',
|
||
},
|
||
已截止: {
|
||
class: 'tag-style bg-light-pink ml10soft',
|
||
},
|
||
开发课程: {
|
||
class: 'tag-style bg-orange ml10',
|
||
},
|
||
已开播: {
|
||
class: 'tag-style-border border-green c-green ml10',
|
||
},
|
||
未开播: {
|
||
class: 'tag-style-border border-light-black ml10',
|
||
},
|
||
// 样式需要调整 作业列表
|
||
按时通关: {
|
||
class: 'tag-style-border border-light-black ml10',
|
||
},
|
||
迟交通关: {
|
||
class: 'tag-style-border border-light-black ml10',
|
||
},
|
||
未通关: {
|
||
class: 'tag-style-border border-light-black ml10',
|
||
},
|
||
未开启: {
|
||
class: 'tag-style-border border-light-black ml10',
|
||
},
|
||
}
|
||
const temporaryTags = {
|
||
未发布: {
|
||
class: 'tag-style bg-C6CED6 ml10soft',
|
||
},
|
||
未开始: {
|
||
class: 'tag-style bg-C1E2FF ml10soft',
|
||
},
|
||
进行中: {
|
||
class: 'tag-style bg-1890FF ml10soft',
|
||
},
|
||
已截止: {
|
||
class: 'tag-style bg-E53333 ml10soft',
|
||
},
|
||
提交中: {
|
||
class: 'tag-style bg-1890FF ml10soft',
|
||
},
|
||
补交中: {
|
||
class: 'tag-style bg-44D7B6 ml10soft',
|
||
},
|
||
}
|
||
if (props.temporary) {
|
||
tags = { ...tags, ...temporaryTags }
|
||
}
|
||
const arr: any = []
|
||
if (props.is_random) {
|
||
arr.push(<span className="tag-style bg-blue ml10">随机</span>)
|
||
}
|
||
try {
|
||
props.status &&
|
||
props.status.map((v: any, k: number) => {
|
||
arr.push(
|
||
<span style={props?.style || []} key={k} className={tags[v] && tags[v]['class']}>
|
||
{v}
|
||
</span>,
|
||
)
|
||
})
|
||
} catch (e) {
|
||
console.log('utils.status.tag:', e, props.status)
|
||
}
|
||
return arr
|
||
}
|
||
export const exerciseTips = (v: number) => {
|
||
if (v === 1) {
|
||
return <span style={{ backgroundColor: '#B8B8B8' }} className="tag-style ml5">未开始</span>
|
||
}
|
||
if (v === 2) {
|
||
return <span style={{ backgroundColor: '#007AFF' }} className="tag-style ml5">考试中</span>
|
||
}
|
||
if (v === 3) {
|
||
return <span style={{ backgroundColor: '#FC2D6B' }} className="tag-style ml5">已结束</span>
|
||
}
|
||
}
|
||
|
||
/**
|
||
*@教学课堂 实训作业状态
|
||
*status值为number status=0
|
||
*任务状态数组: 未发布、提交中、评阅中、补交中、未开启补交等
|
||
*/
|
||
// "work_status": 2, //-1:重做中、 0:未提交、1:未通关,2:按时通关,3:迟交通关
|
||
export const WorkStatus = (props: { status: number }) => {
|
||
const wStatus: any = {
|
||
[-1]: {
|
||
name: '重做中',
|
||
class: 'c-orange',
|
||
},
|
||
0: {
|
||
name: '未提交',
|
||
class: 'c-black',
|
||
},
|
||
1: {
|
||
name: '未通关',
|
||
class: 'c-red',
|
||
},
|
||
2: {
|
||
name: '按时通关',
|
||
class: 'c-green',
|
||
},
|
||
3: {
|
||
name: '迟交通关',
|
||
class: 'c-orange',
|
||
},
|
||
}
|
||
return (
|
||
<span className={wStatus[props.status]?.['class']}>
|
||
{wStatus[props.status]?.['name']}
|
||
</span>
|
||
)
|
||
}
|
||
|
||
|
||
/**
|
||
*@教学课堂 普通/分组作业状态
|
||
*status值为number status=0
|
||
*任务状态数组: 未发布、提交中、评阅中、补交中、未开启补交等
|
||
*/
|
||
// "work_status": 2, //-1:重做中、 0:未提交、1:未通关,2:按时通关,3:迟交通关
|
||
export const CommonWorkStatus = (props: { status: number }) => {
|
||
const wStatus: any = {
|
||
0: {
|
||
name: '未提交',
|
||
class: 'c-black',
|
||
},
|
||
1: {
|
||
name: '按时提交',
|
||
class: 'c-green',
|
||
},
|
||
2: {
|
||
name: '延时提交',
|
||
class: 'c-red',
|
||
}
|
||
}
|
||
return (
|
||
<span className={wStatus[props.status]?.['class']}>
|
||
{wStatus[props.status]?.['name']}
|
||
</span>
|
||
)
|
||
}
|
||
|
||
export const timego = (dateTimeStamp: number) => {
|
||
dateTimeStamp = new Date(dateTimeStamp).getTime()
|
||
let minute: number = 1000 * 60
|
||
let hour: number = minute * 60
|
||
let day = hour * 24
|
||
|
||
let result = ''
|
||
let now = new Date().getTime()
|
||
let diffValue = now - dateTimeStamp
|
||
// console.log("diffValue:",now,dateTimeStamp,diffValue)
|
||
if (diffValue < 0) {
|
||
console.log('时间不对劲,服务器创建时间与当前时间不同步')
|
||
return (result = '刚刚')
|
||
}
|
||
let dayC: number = parseInt(diffValue / day, 10)
|
||
let hourC: number = parseInt(diffValue / hour, 10)
|
||
let minC: number = parseInt(diffValue / minute, 10)
|
||
if (dayC > 30) {
|
||
result = '' + timeformat(dateTimeStamp, 'yyyy-MM-dd')
|
||
} else if (dayC > 1) {
|
||
result = '' + dayC + '天前'
|
||
} else if (dayC == 1) {
|
||
result = '昨天'
|
||
} else if (hourC >= 1) {
|
||
result = '' + hourC + '小时前'
|
||
} else if (minC >= 5) {
|
||
result = '' + minC + '分钟前'
|
||
} else result = '刚刚'
|
||
return result
|
||
}
|
||
/**
|
||
* 格式化时间
|
||
* @param date Date 时间
|
||
* @param format 格式化 "yyyy-MM-dd HH:mm:ss www"=format
|
||
* @returns {string} 格式化后字符串
|
||
*/
|
||
export const timeformat = (date: any, format: string) => {
|
||
if (typeof date == 'string') {
|
||
if (date.indexOf('T') >= 0) {
|
||
date = date.replace('T', ' ')
|
||
}
|
||
date = new Date(Date.parse(date.replace(/-/g, '/')))
|
||
}
|
||
date = new Date(date)
|
||
let o: any = {
|
||
'M+': date.getMonth() + 1,
|
||
'd+': date.getDate(),
|
||
'h+': date.getHours(),
|
||
'm+': date.getMinutes(),
|
||
's+': date.getSeconds(),
|
||
'q+': Math.floor((date.getMonth() + 3) / 3),
|
||
S: date.getMilliseconds(),
|
||
}
|
||
let w = [
|
||
['日', '一', '二', '三', '四', '五', '六'],
|
||
['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
|
||
['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
|
||
]
|
||
if (/(y+)/.test(format)) {
|
||
format = format.replace(
|
||
RegExp.$1,
|
||
(date.getFullYear() + '').substr(4 - RegExp.$1.length),
|
||
)
|
||
}
|
||
if (/(w+)/.test(format)) {
|
||
format = format.replace(RegExp.$1, w[RegExp.$1.length - 1][date.getDay()])
|
||
}
|
||
for (let k in o) {
|
||
if (new RegExp('(' + k + ')').test(format)) {
|
||
format = format.replace(
|
||
RegExp.$1,
|
||
RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length),
|
||
)
|
||
}
|
||
}
|
||
return format
|
||
}
|
||
|
||
/**
|
||
* @时间转换
|
||
* @传值为时间 单位s
|
||
* @返回值 1分40秒
|
||
* @列子 toTimeFormat(100) 返回 1分40秒
|
||
*/
|
||
|
||
export const toTimeFormat = (time: number): string => {
|
||
if (!time || time < 0) return '0秒'
|
||
console.log("time:", time)
|
||
let minute: number = 60
|
||
let hour: number = minute * 60
|
||
let day = hour * 24
|
||
|
||
let dayC: number = time / day
|
||
let hourC: number = time / hour
|
||
let minC: number = time / minute
|
||
let senC: number = time % 60
|
||
if (dayC >= 1) {
|
||
return parseInt(dayC.toString()) + '天' + Math.floor(hourC % 24) + '时' + Math.floor(minC % 60) + "分" + Math.floor(time % 60) + '秒'
|
||
} else if (hourC > 1) {
|
||
return parseInt(hourC.toString()) + '时' + Math.floor(minC % 60) + "分" + Math.floor(time % 60) + '秒'
|
||
} else if (minC >= 1) {
|
||
return parseInt(minC.toString()) + "分" + Math.floor(time % 60) + '秒'
|
||
} else {
|
||
return Math.ceil(time) + '秒'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @校验字符串长度
|
||
*/
|
||
export const validateLength = (str = '', length = 100) => {
|
||
let len = 0
|
||
if (str) {
|
||
len = str.length
|
||
for (let i = 0; i < len; i++) {
|
||
let charCode = str.charCodeAt(i)
|
||
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
|
||
len--
|
||
i++
|
||
}
|
||
}
|
||
}
|
||
return len <= length
|
||
}
|
||
|
||
|
||
export const handleValidatorNickName = (rule: any, value: any, callback: any) => {
|
||
if (value) {
|
||
let iconRule1 = /[`~!@#$%^&*()\-+=<>?:"{}|,.\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/im
|
||
// 判断是否含有emoji表情
|
||
let iconRule2 = /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/ig
|
||
// 如果为true,字符串含有emoji表情 ,false不含
|
||
const iconRule2s = iconRule2.test(value)
|
||
// 如果为true,字符串含有特殊符号 ,false不
|
||
const iconRule1s = iconRule1.test(value)
|
||
|
||
if (iconRule2s === true || iconRule1s === true) {
|
||
callback('2-20位中英文、数字及下划线')
|
||
}
|
||
else if (value.length < 2) {
|
||
callback('2-20位中英文、数字及下划线')
|
||
} else if (value.length >= 21) {
|
||
callback('2-20位中英文、数字及下划线')
|
||
}
|
||
}
|
||
callback()
|
||
}
|
||
export const handleValidatorName = (rule: any, value: any, callback: any) => {
|
||
if (value) {
|
||
let iconRule1 = /[`~!@#$%^&()_\-+=<>?:"{}|,.\/;'\\[\]·~!@#¥%……&()——\-+={}|《》?:“”【】、;‘’,。、]/im
|
||
// 判断是否含有emoji表情
|
||
let iconRule2 = /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/ig
|
||
// 如果为true,字符串含有emoji表情 ,false不含
|
||
const iconRule2s = iconRule2.test(value)
|
||
// 如果为true,字符串含有特殊符号 ,false不
|
||
const iconRule1s = iconRule1.test(value)
|
||
|
||
if (iconRule2s === true || iconRule1s === true) {
|
||
callback('2-10位中英文、数字')
|
||
}
|
||
else if (value.length < 2) {
|
||
callback('2-10位中英文、数字')
|
||
} else if (value.length >= 11) {
|
||
callback('2-10位中英文、数字')
|
||
}
|
||
}
|
||
callback()
|
||
}
|
||
|
||
export const getHiddenName = (name: string) => {
|
||
if (!name) return ''
|
||
let len = name.length - 1
|
||
let str = ""
|
||
for (var i = 0; i < len; i++) { str += "*" }
|
||
const newName = name.substr(0, 1) + str
|
||
return newName
|
||
}
|
||
|
||
export const getBase64 = (img: any, callback: any) => {
|
||
const reader = new FileReader()
|
||
reader.addEventListener('load', () => callback(reader.result))
|
||
reader.readAsDataURL(img)
|
||
}
|
||
|
||
export function setmiyah(logins: any) {
|
||
const opens = "79e33abd4b6588941ab7622aed1e67e8"
|
||
return md5(opens + logins)
|
||
}
|
||
export const getCookie = (key: string) => {
|
||
var arr, reg = RegExp('(^| )' + key + '=([^;]+)(;|$)');
|
||
if (arr = document.cookie.match(reg)) //["username=liuwei;", "", "liuwei", ";"]
|
||
return decodeURIComponent(arr[2]);
|
||
else
|
||
return null;
|
||
}
|
||
// 设置cookie
|
||
export function setCookie(cname: string, cvalue: string, exdays: number) {
|
||
// exdays = exdays || 30;
|
||
var d = new Date();
|
||
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
|
||
var expires = "expires=" + d.toUTCString();
|
||
document.cookie = cname + "=" + cvalue + "; " + expires+";path=/;";
|
||
}
|
||
|
||
|
||
export const delCookie = (name: string) => {
|
||
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/;";
|
||
}
|
||
|
||
|
||
export function downLoadLink(title: string, url: string) {
|
||
let link = document.createElement('a')
|
||
document.body.appendChild(link)
|
||
link.href = url
|
||
if (title) {
|
||
link.title = title
|
||
link.download = title
|
||
}
|
||
//兼容火狐浏览器
|
||
let evt = document.createEvent("MouseEvents")
|
||
evt.initEvent("click", false, false)
|
||
link.dispatchEvent(evt)
|
||
document.body.removeChild(link)
|
||
}
|
||
|
||
/**
|
||
* 获取 blob
|
||
* @param {String} url 目标文件地址
|
||
* @return {Promise}
|
||
*/
|
||
export function getBlob(url: any) {
|
||
return new Promise(resolve => {
|
||
const xhr = new window.XMLHttpRequest();
|
||
|
||
xhr.open('GET', url, true);
|
||
xhr.withCredentials = true;
|
||
xhr.responseType = 'blob';
|
||
xhr.onload = () => {
|
||
if (xhr.status === 200) {
|
||
resolve(xhr.response);
|
||
}
|
||
};
|
||
|
||
xhr.send();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 保存
|
||
* @param {Blob} blob
|
||
* @param {String} filename 想要保存的文件名称
|
||
*/
|
||
export function saveAs(blob: any, filename: any) {
|
||
if (window.navigator.msSaveOrOpenBlob) {
|
||
window.navigator.msSaveBlob(blob, filename);
|
||
} else {
|
||
const link = document.createElement('a');
|
||
const body = document.querySelector('body');
|
||
|
||
link.href = window.URL.createObjectURL(blob);
|
||
link.download = filename;
|
||
|
||
// fix Firefox
|
||
link.style.display = 'none';
|
||
body.appendChild(link);
|
||
|
||
link.click();
|
||
body.removeChild(link);
|
||
|
||
window.URL.revokeObjectURL(link.href);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 下载
|
||
* @param {String} url 目标文件地址
|
||
* @param {String} filename 想要保存的文件名称
|
||
*/
|
||
export function download(url: any, filename: any) {
|
||
// if(url?.indexOf("aliyuncs.com") > -1){
|
||
// downLoadLink(filename,url)
|
||
// }else{
|
||
getBlob(url).then(blob => {
|
||
saveAs(blob, filename);
|
||
});
|
||
// }
|
||
}
|
||
|
||
|
||
|
||
|
||
export function downLoadFileIframe(title: string, url: string) {
|
||
return new Promise((resolve, reject) => {
|
||
var downloadFileUrl = url
|
||
var elemIF = document.createElement("iframe");
|
||
var time: any;
|
||
document.body.appendChild(elemIF);
|
||
elemIF.src = downloadFileUrl;
|
||
elemIF.style.display = "none";
|
||
elemIF.addEventListener("load", function () {
|
||
setTimeout(() => {
|
||
document.body.removeChild(elemIF)
|
||
}, 1000)
|
||
}, true)
|
||
time = setInterval(() => {
|
||
if (getCookie("fileDownload")) {
|
||
delCookie("fileDownload")
|
||
clearInterval(time)
|
||
resolve()
|
||
}
|
||
}, 1000)
|
||
})
|
||
}
|
||
|
||
|
||
export function downLoadFile(title: string, url: string) {
|
||
downLoadLink(title, url)
|
||
}
|
||
|
||
/**
|
||
*@url参数拼接
|
||
*options为对象 {search=1,page:2} to search=1&page=2
|
||
*/
|
||
export const setUrlQuery = (options: { url: string, query: any }) => {
|
||
let { url, query } = options
|
||
if (!url) return ''
|
||
if (query) {
|
||
let queryArr = []
|
||
for (const key in query) {
|
||
if (query.hasOwnProperty(key) && !isUnOrNull(query[key])) {
|
||
if (typeof query[key] === "object") {
|
||
query[key].map((v: any) => {
|
||
queryArr.push(`${key}[]=${v}`)
|
||
})
|
||
} else {
|
||
queryArr.push(`${key}=${query[key]}`)
|
||
}
|
||
}
|
||
}
|
||
if (url.indexOf('?') !== -1) {
|
||
url = `${url}&${queryArr.join('&')}`
|
||
} else {
|
||
url = `${url}?${queryArr.join('&')}`
|
||
}
|
||
console.log('url1111', url);
|
||
|
||
}
|
||
return url
|
||
}
|
||
|
||
export function isPc() {
|
||
let userAgentInfo = navigator.userAgent
|
||
let Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]
|
||
let flag = true
|
||
|
||
for (var v = 0; v < Agents.length; v++) {
|
||
if (userAgentInfo.indexOf(Agents[v]) > 0) {
|
||
flag = false
|
||
break
|
||
}
|
||
}
|
||
return flag
|
||
|
||
}
|
||
|
||
export function isChrome() {
|
||
let userAgentInfo = navigator.userAgent
|
||
let Agents = ['Chrome']
|
||
return Agents.some(item => userAgentInfo.indexOf(item) > -1 ? true : false)
|
||
}
|
||
|
||
export function isChromeOrFirefox() {
|
||
let userAgentInfo = navigator.userAgent
|
||
let Agents = ['Chrome', 'Firefox']
|
||
return Agents.some(item => userAgentInfo.indexOf(item) > -1 ? true : false)
|
||
}
|
||
|
||
export const formatMoney = (value: string | number = '') => value?.toString()?.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||
|
||
export const openNewWindow = (url: string) => {
|
||
let link = document.createElement('a')
|
||
link.target = "_blank"
|
||
document.body.appendChild(link)
|
||
link.href = url
|
||
let evt = document.createEvent("MouseEvents")
|
||
evt.initEvent("click", false, false)
|
||
link.dispatchEvent(evt)
|
||
document.body.removeChild(link)
|
||
}
|
||
|
||
export const formatTextMiddleIntercept = (text: string = '') => {
|
||
if (text.length <= 6) {
|
||
return text
|
||
}
|
||
|
||
return `${text.substring(0, 3)}...${text.substring(text.length - 3, text.length)}`
|
||
}
|
||
|
||
export const HalfPastOne = (): string => {
|
||
let hours = new Date().getHours();
|
||
let minute: any = new Date().getMinutes();
|
||
if (minute >= 30) {
|
||
hours++
|
||
minute = "00"
|
||
} else {
|
||
minute = "30"
|
||
}
|
||
return hours + ':' + minute
|
||
}
|
||
|
||
export const DayHalfPastOne = (reg: string = '-'): string => {
|
||
let hours = new Date().getHours();
|
||
let minute: any = new Date().getMinutes();
|
||
if (minute >= 30) {
|
||
hours++
|
||
minute = "00"
|
||
} else {
|
||
minute = "30"
|
||
}
|
||
return new Date().toLocaleDateString().replace(/\//g, reg) + ' ' + hours + ':' + minute
|
||
}
|
||
|
||
enum Type {
|
||
Number = 'Number',
|
||
String = 'String',
|
||
Boolean = 'Boolean',
|
||
Object = 'Object',
|
||
Array = 'Array',
|
||
Function = 'Function'
|
||
}
|
||
|
||
const type = (obj: any) => {
|
||
const type = Object.prototype.toString.call(obj);
|
||
return type.substring(8, type.length - 1);
|
||
};
|
||
|
||
export const isEmpty = (obj: any) => {
|
||
if (type(obj) === Type.Array) {
|
||
return (obj as any).length === 0;
|
||
}
|
||
if (type(obj) === Type.Object) {
|
||
return Object.keys(obj).length === 0;
|
||
}
|
||
return !obj;
|
||
};
|
||
export const rangeNumber = (start: number, end: number): number[] => {
|
||
const result = [];
|
||
for (let i = start; i < end; i++) {
|
||
result.push(i);
|
||
}
|
||
return result;
|
||
}
|
||
export const middleEllipsis = (text: string, len = 12) => {
|
||
let firstStart = len / 2 - 2
|
||
let endStart = len / 2 + 3
|
||
if (text.length > len) {
|
||
return text.substr(0, firstStart) + '...' + text.substr(endStart, len)
|
||
} else {
|
||
return text
|
||
}
|
||
}
|
||
export const formatRate = (rate: number) => {
|
||
if (rate > 4.5) {
|
||
return 5;
|
||
} else if (rate > 4 && rate <= 4.5) {
|
||
return 4.5;
|
||
} else if (rate > 3.5 && rate <= 4) {
|
||
return 4;
|
||
} else if (rate > 3 && rate <= 3.5) {
|
||
return 3.5;
|
||
} else if (rate > 2.5 && rate <= 3) {
|
||
return 3;
|
||
} else if (rate > 2 && rate <= 2.5) {
|
||
return 2.5;
|
||
} else if (rate > 1.5 && rate <= 2) {
|
||
return 2;
|
||
} else if (rate > 1 && rate <= 1.5) {
|
||
return 1.5;
|
||
} else if (rate > 0.5 && rate <= 1) {
|
||
return 1;
|
||
} else if (rate > 0 && rate <= 0.5) {
|
||
return 0.5;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
export const isUnOrNull = (val: any) => {
|
||
return val === undefined || val === null;
|
||
}
|
||
//获取?号后面的数据
|
||
export function getUrlToken(name: any, str: any) {
|
||
const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, `i`);
|
||
const r = str.substr(1).match(reg);
|
||
if (r != null) return decodeURIComponent(r[2]); return null;
|
||
}
|
||
|
||
|
||
export const getMessagesUrl = (item: any) => {
|
||
switch (item.container_type) {
|
||
case "ApplyUserAuthentication":
|
||
if (item.tiding_type === "Apply") {
|
||
if (item.auth_type === 1) {
|
||
//系统管理页面
|
||
return window.open("/admins/identity_authentications");
|
||
}
|
||
if (item.auth_type === 2) {
|
||
//系统管理页面
|
||
return window.open("/admins/professional_authentications")
|
||
}
|
||
}
|
||
if (item.tiding_type === "System") {
|
||
// 账号管理页-认证信息
|
||
return window.open("/account/certification")
|
||
}
|
||
return;
|
||
case "CancelUserAuthentication":
|
||
// 账号管理页-认证信息
|
||
return window.open("/account/certification")
|
||
case "CancelUserProCertification":
|
||
// 账号管理页-认证信息
|
||
return window.open("/account/certification")
|
||
case "ApplyAddDepartment":
|
||
if (item.tiding_type === "Apply") {
|
||
//部门审批
|
||
return window.open("/admins/department_applies")
|
||
}
|
||
if (item.tiding_type === "System") {
|
||
// 账号管理页/account/profile
|
||
return window.open("/account/profile")
|
||
}
|
||
return;
|
||
case "ApplyAddSchools":
|
||
if (item.tiding_type === "Apply") {
|
||
// 单位审批
|
||
return window.open("/admins/unit_applies")
|
||
}
|
||
if (item.tiding_type === "System") {
|
||
// 账号管理页
|
||
return window.open("/account/profile")
|
||
}
|
||
return;
|
||
case "ApplyAction":
|
||
switch (item.parent_container_type) {
|
||
case "ApplyShixun":
|
||
if (item.tiding_type === "Apply") {
|
||
return window.open("/admins/shixun_authorizations")
|
||
}
|
||
if (item.tiding_type === "System") {
|
||
// 实训详情页 :identifier = identifier
|
||
return window.open(`/shixuns/${item.identifier}/challenges`)
|
||
}
|
||
case "ApplySubject":
|
||
if (item.tiding_type === "Apply") {
|
||
// 实训课程发布
|
||
return window.open("/admins/subject_authorizations")
|
||
}
|
||
if (item.tiding_type === "System") {
|
||
// 课程汇总详情页 :parent_container_id = parent_container_id
|
||
|
||
return window.open(`/paths/${item.parent_container_id}`)
|
||
}
|
||
case "TrialAuthorization":
|
||
if (item.tiding_type === "Apply") {
|
||
// 试用授权页面
|
||
return window.open("/managements/trial_authorization")
|
||
}
|
||
if (item.tiding_type === "System") {
|
||
// 账号管理页
|
||
return window.open("/account/profile")
|
||
}
|
||
}
|
||
return;
|
||
case 'JoinCourse':
|
||
// 课堂详情页 :id =
|
||
return window.open(`/classrooms/${item.belong_container_id}/teachers`)
|
||
case 'StudentJoinCourse':
|
||
// 课堂详情页 :id = container_id
|
||
if (item.tiding_type === 'Apply') {
|
||
return window.open(`/classrooms/${item.belong_container_id}/teachers`);
|
||
}
|
||
if (item.tiding_type === 'System') {
|
||
//教学案例详情 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/students`);
|
||
}
|
||
case 'DealCourse':
|
||
// 课堂详情页 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/`)
|
||
case 'TeacherJoinCourse':
|
||
// 课堂详情页 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/`)
|
||
case 'Course':
|
||
// 课堂详情页 :id = container_id
|
||
if (item.tiding_type === "Delete") {
|
||
|
||
return;
|
||
}
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/`)
|
||
case 'ArchiveCourse':
|
||
// 课堂详情页 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/`)
|
||
case "Shixun":
|
||
return window.open(`/shixuns/${item.identifier}/challenges`)
|
||
case "Subject":
|
||
// 课程汇总详情页 :id = container_id
|
||
return window.open(`/paths/${item.container_id}`)
|
||
case "JournalsForMessage":
|
||
switch (item.parent_container_type) {
|
||
case "Principal":
|
||
// 反馈页 :id = parent_container_id
|
||
// 不用跳了
|
||
return '';
|
||
case "HomeworkCommon":
|
||
//学生作业页 homework = parent_container_id
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/question`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/question`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail?tabs=1`)
|
||
}
|
||
return "";
|
||
case "GraduationTopic":
|
||
// 毕业目标页 parent_container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/graduation_topics/${item.parent_container_id}/detail`)
|
||
case "StudentWorksScore":
|
||
//学生作业页
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/question`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/question`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail?tabs=1`)
|
||
}
|
||
return "";
|
||
}
|
||
case "Memo":
|
||
// 交流问答页 :id = parent_container_id
|
||
return window.open(`/forums/${item.parent_container_id}`);
|
||
case "Message":
|
||
// 交流问答页 :id = parent_container_id
|
||
return window.open(`/forums/`);
|
||
case "Watcher":
|
||
// 用户个人中心页 :id = item.trigger_user.login
|
||
return window.open(`/users/${item.trigger_user.login}/classrooms`)
|
||
case "PraiseTread":
|
||
// 这块太复杂 不好处理
|
||
return '';
|
||
case "Grade":
|
||
//个人中心页 :id = item.trigger_user.login
|
||
// return window.open(`/users/${userInfo()?.login}/classrooms`;
|
||
return "";
|
||
case "JoinProject":
|
||
//项目详情-申请加入项目审核页 :id = container_id
|
||
return window.open( ENV.FORGE + item.project_url)
|
||
// return window.open(`/projects/${item.container_id}`)
|
||
case 'ReporterJoinProject':
|
||
//项目详情页 :id = container_id
|
||
return window.open( ENV.FORGE + item.project_url)
|
||
// return window.open(`/projects/${item.container_id}`)
|
||
case 'DealProject':
|
||
//项目详情页 :id = container_id
|
||
return window.open( ENV.FORGE + item.project_url)
|
||
// return window.open(`/projects/${item.container_id}`)
|
||
case 'ManagerJoinProject':
|
||
//项目详情页 :id = container_id
|
||
return window.open( ENV.FORGE + item.project_url)
|
||
// return window.open(`/projects/${item.container_id}`)
|
||
case "Poll":
|
||
switch (item.parent_container_type) {
|
||
case "CommitPoll":
|
||
// 课堂id belong_container_id
|
||
//课堂-学生已提交问卷列表 :id = container_id
|
||
return window.open(` /classrooms/${item.belong_container_id}/poll/${item.container_id}/detail`)
|
||
default:
|
||
// 课堂-问卷列表 :id = container_id
|
||
return window.open(` /classrooms/${item.belong_container_id}/poll/${item.container_id}/detail`)
|
||
}
|
||
case "Exercise":
|
||
switch (item.parent_container_type) {
|
||
case "CommitExercise":
|
||
// 课堂-学生试卷详情 :id = container_id :user_id = trigger_user.id
|
||
return window.open(` /classrooms/${item.belong_container_id}/exercise/${item.container_id}/detail?tab=0`);
|
||
//记得跳评阅页面
|
||
case "ExerciseScore":
|
||
// 课堂-学生试卷详情 :id = container_id :user_id = trigger_user.id
|
||
return window.open(` /classrooms/${item.belong_container_id}/exercise/${item.container_id}/detail?tab=0`);
|
||
//记得跳评阅页面
|
||
default:
|
||
// 课堂-试卷列表详情 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/exercise/${item.container_id}/detail?tab=0`);
|
||
}
|
||
case 'StudentGraduationTopic':
|
||
//课堂-毕业选题详情 :id = parent_container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/graduation_topics/${item.parent_container_id}/detail`)
|
||
case 'DealStudentTopicSelect':
|
||
//课堂-毕业选题详情 :id = parent_container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/graduation_topics/${item.parent_container_id}/detail`)
|
||
case 'GraduationTask':
|
||
//课堂-毕业任务页 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/graduation_tasks/${item.container_id}`)
|
||
case "GraduationWork":
|
||
//课堂-毕业xx页 :id = container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/graduation_tasks/${item.container_id}`)
|
||
case "GraduationWorkScore":
|
||
// 课堂-毕业xx页 :id = parent_container_id
|
||
return window.open(`/classrooms/${item.belong_container_id}/graduation_tasks/${item.parent_container_id}`)
|
||
case "HomeworkCommon":
|
||
switch (item.parent_container_type) {
|
||
case "AnonymousCommentFail":
|
||
// 课堂-作业列表 homework = container_id
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail?tabs=0`)
|
||
}
|
||
case "HomeworkPublish":
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail?tabs=0`)
|
||
}
|
||
case "AnonymousAppeal":
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail?tabs=0`)
|
||
}
|
||
default:
|
||
// 课堂-作业列表 homework = container_id
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail?tabs=0`)
|
||
}
|
||
}
|
||
case "StudentWork":
|
||
//课堂-作业 :id = container_id
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/review/${item.container_id}`)
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业/classrooms/1208/group_homework/22373/1219130/appraise
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/review/${item.container_id}`)
|
||
}
|
||
if (item.homework_type === "practice") {
|
||
//实训作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/shixun_homework/${item.parent_container_id}/detail`)
|
||
}
|
||
case "StudentWorksScore":
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.trigger_user.id}/review/${item.parent_container_id}`);
|
||
|
||
case "StudentWorksScoresAppeal":
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.trigger_user.id}/review/${item.parent_container_id}`);
|
||
case "ChallengeWorkScore":
|
||
return '';
|
||
case "SendMessage":
|
||
// /managements/mirror_repository
|
||
// return window.open(`/managements/mirror_repository`)
|
||
return window.open(`${ENV.API_SERVER}/admins/mirror_repositories`)
|
||
case "Journal":
|
||
//项目Issue页 :id = parent_container_id
|
||
return window.open(`/issues/${item.parent_container_id}`);
|
||
case "Issue":
|
||
//项目Issue页 :id = container_id
|
||
return window.open(`/issues/${item.container_id}`)
|
||
case "PullRequest":
|
||
// 项目pull request页 :id = parent_container_id
|
||
return window.open( ENV.FORGE + item.project_url)
|
||
// return window.open(`/projects/${item.parent_container_id}/pull_requests`)
|
||
case "Department":
|
||
//账号管理页
|
||
return window.open(`/account/profile`)
|
||
case "Library":
|
||
if (item.tiding_type === 'Apply') {
|
||
// /managements/library_applies
|
||
return window.open(`/admins/library_applies`)
|
||
}
|
||
if (item.tiding_type === 'System') {
|
||
//教学案例详情 :id = container_id
|
||
return window.open(`/moop_cases/${item.container_id}`)
|
||
}
|
||
case "ProjectPackage":
|
||
if (item.tiding_type === "Destroyed") {
|
||
return;
|
||
}
|
||
if (item.tiding_type === "Destroyed_end") {
|
||
return;
|
||
} else {
|
||
if (item.tiding_type === 'Apply') {
|
||
///managements/project_package_applies
|
||
return window.open(`/admins/project_package_applies`)
|
||
}
|
||
// if(item.tiding_type === 'System'){
|
||
//众包详情 :id = container_id
|
||
return window.open(`/crowdsourcing/${item.container_id}`)
|
||
// }
|
||
}
|
||
case "Discuss":
|
||
if (item.parent_container_type === 'Hack' && item.extra) {
|
||
return window.open(`/myproblems/${item.extra}/comment`);
|
||
} else {
|
||
return window.open(`/shixuns/${item.identifier}/shixun_discuss`);
|
||
}
|
||
case "Video":
|
||
if (item.tiding_type === "Apply") {
|
||
return window.open(`/admins/video_applies`);
|
||
} else if (item.tiding_type === "System") {
|
||
return window.open(`/users/${userInfo()?.login}/videos`);
|
||
}
|
||
return '';
|
||
case "PublicCourseStart":
|
||
return window.open(`/classrooms/${item.container_id}/informs`);
|
||
case "SubjectStartCourse":
|
||
return window.open(`/paths/${item.container_id}`);
|
||
case "ResubmitStudentWork":
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}/${item.container_id}/appraise`);
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}/${item.container_id}/appraise`);
|
||
}
|
||
case "AdjustScore":
|
||
//belong_container_id course的id
|
||
if (item.homework_type === "normal") {
|
||
//普通作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/common_homework/${item.parent_container_id}`);
|
||
}
|
||
if (item.homework_type === "group") {
|
||
//分组作业
|
||
return window.open(`/classrooms/${item.belong_container_id}/group_homework/${item.parent_container_id}`);
|
||
}
|
||
case 'LiveLink':
|
||
return window.open(`/classrooms/${item.belong_container_id}/course_videos?open=live`);
|
||
case 'Hack':
|
||
if (item.extra && item.parent_container_type !== 'HackDelete') {
|
||
return window.open(`/problems/${item.extra}/edit`);
|
||
}
|
||
default:
|
||
return
|
||
}
|
||
|
||
}
|
||
|
||
export const checkLocalOrPublicIp = (v: { exerciseId: string, ip: string, ip_bind: boolean, errmsgHide: boolean, ip_limit: string }) => {
|
||
let ip, modal: any;
|
||
return new Promise(async (resolve, reject) => {
|
||
if (v.ip_limit !== 'no' || v.ip_bind)
|
||
ip = await findLocalIp({ ip_limit: v?.ip_limit, ip_bind: v?.ip_bind });
|
||
const res = await checkIp({ id: v.exerciseId, ip: ip })
|
||
if (res.status === 0) {
|
||
resolve(res)
|
||
} else {
|
||
reject(res)
|
||
}
|
||
if (v.errmsgHide) {
|
||
return true;
|
||
}
|
||
if (res.status === -1) {
|
||
modal = Modal.info({
|
||
title: <Row>
|
||
<Col flex="1">提示</Col>
|
||
<Col>
|
||
<span className="iconfont icon-yiguanbi1 current c-grey-c" onClick={() => modal.destroy()}></span>
|
||
</Col>
|
||
</Row>,
|
||
icon: null,
|
||
className: "custom-modal-divider",
|
||
content: <div className="font16 p20">
|
||
您的IP不在考试允许的范围内!
|
||
</div>,
|
||
okText: "我知道了",
|
||
})
|
||
return false;
|
||
} else if (res.status === -2) {
|
||
modal = Modal.info({
|
||
title: <Row>
|
||
<Col flex="1">提示</Col>
|
||
<Col>
|
||
<span className="iconfont icon-yiguanbi1 current c-grey-c" onClick={() => modal.destroy()}></span>
|
||
</Col>
|
||
</Row>,
|
||
icon: null,
|
||
className: "custom-modal-divider",
|
||
content: <div className="font16 p20">
|
||
您已绑定当前考试IP地址:<span className="c-red">{res.ip}</span>
|
||
请使用该IP地址进入考试。
|
||
</div>,
|
||
okText: "我知道了",
|
||
})
|
||
return false;
|
||
}
|
||
})
|
||
}
|
||
|
||
export const startExercise = async (v: exerciseStartParams) => {
|
||
let modal: any;
|
||
if(location.pathname.indexOf("/classrooms/4RW9CYHY") > -1 && !isPc()){
|
||
Modal.info({
|
||
content:"请使用电脑参加考试!"
|
||
})
|
||
return;
|
||
}
|
||
if (v.ip_limit !== 'no' || v.ip_bind) {
|
||
await checkLocalOrPublicIp(v)
|
||
if (!isChrome()) {
|
||
Modal.info({
|
||
icon: null,
|
||
okText: "确定",
|
||
width: 500,
|
||
content: <div className="font16">本次考试已开启防作弊设置,仅支持<span className="c-red">谷歌</span>。<br />请使用<span className="c-red">谷歌</span>浏览器开始考试。</div>
|
||
})
|
||
return;
|
||
}
|
||
};
|
||
if (v.open_camera || v.screen_open || v.ip_limit !== 'no' || v.ip_bind || v.identity_verify) {
|
||
if (!isChromeOrFirefox()) {
|
||
Modal.info({
|
||
icon: null,
|
||
okText: "确定",
|
||
width: 500,
|
||
content: <div className="font16">本次考试已开启防作弊设置,仅支持<span className="c-red">谷歌</span>、<span className="c-red">火狐</span>浏览器。<br />请使用<span className="c-red">谷歌</span>、<span className="c-red">火狐</span>浏览器开始考试。</div>
|
||
})
|
||
return false;
|
||
}
|
||
modal = Modal.info({
|
||
title: <Row>
|
||
<Col flex="1">考试说明</Col>
|
||
<Col>
|
||
<span className="iconfont icon-yiguanbi1 current c-grey-c" onClick={() => modal.destroy()}></span>
|
||
</Col>
|
||
</Row>,
|
||
width: 700,
|
||
icon: null,
|
||
className: "custom-modal-divider",
|
||
content: <div className="font16 p20">
|
||
{
|
||
v.identity_verify && <Row align="middle" justify="start" className="mt20">
|
||
<Col flex="45px"><span className="iconfont icon-kaiqishexiangtou c-blue mr20 font24"></span></Col>
|
||
<Col flex="1">
|
||
进入考试前,请允许摄像头授权,授权后需采集照片认证,认证通过并开启手机录制才可以进入考试。
|
||
{
|
||
!checkIsClientExam() && <a target="_blank" href="https://www.educoder.net/forums/4459">无法调用摄像头?</a>
|
||
}
|
||
</Col>
|
||
</Row>
|
||
}
|
||
{
|
||
v.open_camera && <Row align="middle" justify="start" className="mt20">
|
||
<Col><span className="iconfont icon-kaiqishexiangtou c-blue mr20 font24"></span></Col>
|
||
<Col>
|
||
进入考试后,请允许摄像头授权,授权后打开摄像头方可作答!
|
||
{
|
||
!checkIsClientExam() && <a target="_blank" href="https://www.educoder.net/forums/4459">无法调用摄像头?</a>
|
||
}
|
||
</Col>
|
||
</Row>
|
||
}
|
||
{
|
||
v.screen_open && <Row justify="start" className="mt20">
|
||
<Col flex="24px" className="mr20"><span className="iconfont icon-kaiqifangqieping c-blue font24"></span></Col>
|
||
<Col flex="1">
|
||
当前考试已开启防切屏,切屏超过{v.screen_num}次将强制交卷。(退出全屏将判定为切屏一次,考试过程中请勿退出全屏)
|
||
{
|
||
!checkIsClientExam() && <a target="_blank" href="https://www.educoder.net/forums/4460">浏览器无法自动全屏?</a>
|
||
}
|
||
|
||
</Col>
|
||
</Row>
|
||
}
|
||
{
|
||
(v.inner_ip !== '' || v.public_ip !== '') && v.ip_limit !== 'no' && <Row justify="start" className="mt20">
|
||
<Col flex="24px" className="mr20"><span className="iconfont icon-IP c-blue font24"></span></Col>
|
||
<Col flex="1">
|
||
当前考试已开启IP范围限定。IP地址不在范围内不可参加考试。
|
||
<br />
|
||
{
|
||
!checkIsClientExam() && <>
|
||
<span className="c-red">(只允许在Chrome谷歌浏览器作答,并且需要安装WebRTC Leak Prevent插件)</span><br />
|
||
<a href="https://www.educoder.net/forums/4478" target="_blank">如何安装WebRTC Leak Prevent插件?</a>
|
||
</>
|
||
}
|
||
</Col>
|
||
</Row>
|
||
}
|
||
|
||
{
|
||
v.ip_bind && <Row justify="start" className="mt20">
|
||
<Col flex="24px" className="mr20"><span className="iconfont icon-IPbangding c-blue font24"></span></Col>
|
||
<Col flex="1">
|
||
当前考试已启用考试期间IP绑定。当您开始考试后,将自动绑定IP,考试期间只允许使用唯一的IP进入考试。如遇特殊情况,可向老师申请解除IP绑定。<br />
|
||
{
|
||
!checkIsClientExam() && <>
|
||
<span className="c-red">(只允许在Chrome谷歌浏览器作答,并且需要安装WebRTC Leak Prevent插件)</span><br />
|
||
<a href="https://www.educoder.net/forums/4478" target="_blank">如何安装WebRTC Leak Prevent插件?</a>
|
||
</>
|
||
}
|
||
</Col>
|
||
</Row>
|
||
}
|
||
|
||
<p className="ml40 mt40">
|
||
<Checkbox onChange={(e) => modal.update({ okButtonProps: { disabled: !e.target.checked } })}>我已阅读</Checkbox>
|
||
</p>
|
||
</div>,
|
||
onOk: () => {
|
||
requestFullScreen(document.body)
|
||
if (v.identity_verify && v.current_status === 2) {
|
||
v.history.push(`/classrooms/${v.coursesId}/exercise/${v.exerciseId}/users/${userInfo()?.login}/check`)
|
||
} else {
|
||
v.history.push(`/classrooms/${v.coursesId}/exercise/${v.exerciseId}/users/${userInfo()?.login}`)
|
||
}
|
||
},
|
||
okText: "进入考试",
|
||
okButtonProps: { disabled: true }
|
||
})
|
||
} else {
|
||
if (v.identity_verify && v.current_status === 2) {
|
||
v.history.push(`/classrooms/${v.coursesId}/exercise/${v.exerciseId}/users/${v.login}/check`)
|
||
} else {
|
||
v.history.push(`/classrooms/${v.coursesId}/exercise/${v.exerciseId}/users/${v.login}`)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
export const educationList = [{
|
||
name: "博士研究生",
|
||
id: 8
|
||
}, {
|
||
name: "硕士研究生",
|
||
id: 7
|
||
}, {
|
||
name: "本科",
|
||
id: 6
|
||
}, {
|
||
name: "大专",
|
||
id: 5
|
||
}, {
|
||
name: "中专",
|
||
id: 4
|
||
}, {
|
||
name: "高中",
|
||
id: 3
|
||
}, {
|
||
name: "初中",
|
||
id: 2
|
||
}, {
|
||
name: "小学",
|
||
id: 1
|
||
}, {
|
||
name: "其他",
|
||
id: 9
|
||
}]
|
||
|
||
export const messageInfo = (status: number, date?: any) => {
|
||
const info: any = {
|
||
1: '当前实践项目暂未发布,请联系本课堂教师。',
|
||
2: '当前实践项目不存在,请联系本课堂教师。',
|
||
3: '当前实践项目面向指定单位开放,请联系本课堂教师。',
|
||
4: `当前实践项目将于${date}发布,请等待。`
|
||
}
|
||
const s = info[status];
|
||
message.warn(s);
|
||
}
|
||
|
||
export const base64ToBlob = (code: string, filename: string) => {
|
||
// const parts = code.split(';base64,');
|
||
// const contentType = parts[0].split(':')[1];
|
||
const raw = window.atob(code);
|
||
const rawLength = raw.length;
|
||
const uInt8Array = new Uint8Array(rawLength);
|
||
for (let i = 0; i < rawLength; ++i) {
|
||
uInt8Array[i] = raw.charCodeAt(i);
|
||
}
|
||
console.log("type:", contentType[filename.split(".")?.[1]] || 'application/octet-stream')
|
||
return new Blob([uInt8Array], { type: contentType[filename.split(".")?.[1]] || 'application/octet-stream' });
|
||
}
|
||
|
||
export const downloadFile = (fileName: string, content: string, filename: string) => {
|
||
const blob = base64ToBlob(content, filename); // new Blob([content]);
|
||
if (window.navigator.msSaveOrOpenBlob) {
|
||
navigator.msSaveBlob(blob, fileName);
|
||
} else {
|
||
const link = document.createElement('a');
|
||
link.href = window.URL.createObjectURL(blob);
|
||
link.download = fileName;
|
||
//此写法兼容可火狐浏览器
|
||
document.body.appendChild(link);
|
||
const evt = document.createEvent("MouseEvents");
|
||
evt.initEvent("click", false, false);
|
||
link.dispatchEvent(evt);
|
||
document.body.removeChild(link);
|
||
}
|
||
}
|
||
|
||
|
||
export const trackEvent = (arr: any[]) => {
|
||
if (!!arr.length) {
|
||
try {
|
||
window._czc.push(['_trackEvent', ...arr]);
|
||
window?.gtag('event', arr[1], {
|
||
'event_category': arr[0],
|
||
'event_label': arr[2] || '',
|
||
'value': arr[3] || "",
|
||
"user_id": userInfo()?.login || ""
|
||
});
|
||
} catch (e) {
|
||
console.log("trackEvent:err:", e)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
export const trackEventCustom = (arr: any[]) => {
|
||
if (!!arr.length) {
|
||
try {
|
||
window._czc.push(['_setCustomVar', ...arr]);
|
||
} catch (e) {
|
||
console.log("trackEvent:err:", e)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//图片预览
|
||
export const onPreviewImage = (e: any) => {
|
||
const parentIndexOf = (node: any, parent: any) => {
|
||
if (node.localName === parent) { return node; }
|
||
for (let i = 0, n = node; n = n.parentNode; i++) {
|
||
if (n.localName === parent) { return n; }
|
||
if (n == document.documentElement) { return false; } //找不到目标父节点,防止死循环
|
||
}
|
||
}
|
||
const t = e.target;
|
||
const dom = parentIndexOf(t, 'a');
|
||
if (dom?.href) return;
|
||
if (t.tagName.toUpperCase() === 'IMG') {
|
||
let url = t.src || t.getAttribute('src');
|
||
if (url && url.indexOf('/images/avatars/User') === -1) {
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
mediator.publish('preview-image', url);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 课堂获取目录名
|
||
export const getCategoryName = (data: any, categoryId: number) => {
|
||
if (data) {
|
||
let res = data?.filter((item: any) => item.type === location.pathname.split("/")[3])?.[0]
|
||
if (categoryId)
|
||
return res?.second_category?.filter((item: any) => item.category_id == categoryId)?.[0]?.["category_name"]
|
||
else
|
||
return res?.["name"]
|
||
}
|
||
return null
|
||
}
|
||
|
||
// 绑定手机号码
|
||
export const bindPhone = (obj?: any) => {
|
||
const modal = Modal.confirm({
|
||
title: "完善手机号码",
|
||
content: "开启挑战前,请先绑定手机号码",
|
||
okText: "立即绑定",
|
||
cancelText: "取消",
|
||
onOk: () => {
|
||
location.href = '/account/secure'
|
||
},
|
||
onCancel: () => {
|
||
modal.destroy()
|
||
obj?.onCancel && obj.onCancel()
|
||
}
|
||
})
|
||
}
|
||
|
||
//复制文字,支持window换行
|
||
export const copyTextFuc = (v: string = '', hide: boolean = false) => {
|
||
const input = document.createElement('textarea')
|
||
input.value = v;
|
||
document.body.appendChild(input);
|
||
input.select();
|
||
document.execCommand('Copy');
|
||
if (!hide) {
|
||
message.success('复制成功');
|
||
}
|
||
document.body.removeChild(input);
|
||
}
|
||
|
||
//获取URl参数
|
||
export const getJsonFromUrl = (url?: string) => {
|
||
if (!url) url = window.location.search
|
||
let query = url.substr(1)
|
||
let result: any = {}
|
||
query.split('&').forEach(function (part) {
|
||
let item = part.split('=')
|
||
result[item[0]] = decodeURIComponent(item[1])
|
||
})
|
||
return result
|
||
}
|
||
|
||
// 一维数组转换为二维数组
|
||
export const arrTrans = (num: number, arr: any[]) => {
|
||
if (!arr) return null;
|
||
const iconsArr: number | any[] = [];
|
||
arr.forEach((item: any, index: number) => {
|
||
const page: number = Math.floor(index / num);
|
||
if (!iconsArr[page]) {
|
||
iconsArr[page] = [];
|
||
}
|
||
iconsArr[page].push(item);
|
||
});
|
||
return iconsArr;
|
||
}
|
||
|
||
// 设置网页标题
|
||
export const setDocumentTitle = (title?: string) => {
|
||
if (checkIsClientExam()) {
|
||
document.title = "头歌考试系统"
|
||
} else {
|
||
document.title = title || "forge"
|
||
}
|
||
}
|
||
|
||
// 检查是否C/S考试系统端
|
||
export const checkIsClientExam = () => {
|
||
return window?.localStorage?.isClientExam;
|
||
}
|