import type { AxiosResponse } from "axios"; interface SplitConfig { /** index of sheets */ i: number; /** 覆盖区域的width */ w: number; /** 覆盖区域的height */ h: number; /** 从哪里开始覆盖 左上角为 (0, 0) */ x: number; /** 从哪里开始覆盖 左上角为 (0, 0) */ y: number; } type SingleSheetConfig = SplitConfig; export type PictureSlice = SplitConfig; export interface MarkStore { setting: Setting; groups: Array; status: { /** 为false时不更新以下count字段 */ valid: boolean; /** 个人评卷数量 */ personCount: number; /** 总评卷数量 */ markedCount: number; /** 总数量 */ totalCount: number; /** 问题卷数量 */ problemCount: number; /** 待仲裁卷数量 */ arbitrateCount: number; /**成绩校验,批量校验时,已校验的学生id的集合 */ markedCountStuIds?: any; }; /** 保持数量为3(prefetchCount) */ tasks: Array; /** 用来切换task,还有回看 */ currentTask?: Task; currentQuestion?: Question; currentScore?: number; currentSpecialTag?: string; currentSpecialTagType?: SpecialTag.tagType; /** 是否打开回评侧边栏 */ historyOpen: boolean; historyTasks: Array; /** 删除这些轨迹 */ removeScoreTracks: Array; /** 聚焦这些tracks */ focusTracks: Array; message: string | null; maxModalZIndex: number; /** 缩略图设置滚动到宽度的百分比 */ minimapScrollToX?: number; /** 缩略图设置滚动到高度的百分比 */ minimapScrollToY?: number; /** 是否显示全卷 */ allPaperModal: boolean; /** 是否显示原卷 */ sheetViewModal: boolean; /** 是否全局遮盖 */ globalMask: boolean; } export interface Setting { /** 扫描图片或者多媒体,多媒体只允许 common mode */ examType: "SCAN_IMAGE" | "MULTI_MEDIA"; /** 阅卷模式 TRACK | COMMON */ mode: "TRACK" | "COMMON"; /** 是否允许模式切换,true为不允许 */ forceMode: boolean; /** 是否显示原图功能 */ sheetView: boolean; /** 是否自动跳转 */ autoScroll: boolean; /** 原图遮盖规则 */ sheetConfig: Array; /** 是否开启全零分 */ enableAllZero: boolean; /** 是否允许裁切 */ enableSplit: boolean; /** 图片服务地址 */ fileServer: string; /** 评卷员姓名 */ userName: string; /** 科目信息(试卷和答案功能)*/ subject: Subject; /** 强制标记是否开启 */ forceSpecialTag: boolean; /** 评卷小工具控制字段 */ uiSetting: UISetting; /** 只显示试评名称 TRIAL("试评"), FORMAL("正评"), FINISH("结束"): 结束状态不会在评卷端出现 */ statusValue: "TRIAL" | "FORMAL" | null; /** 问题卷类型 */ problemTypes: Array<{ id: number; name: string }>; /** 当前评卷分组号 */ groupNumber: number; /** 当前评卷分组名称 */ groupTitle: string; /** 推荐老师评卷的数量,到达这个数量提示老师 */ topCount: number; /** 使用裁切整图时的裁切配置 [0,1]|[0,0.3,0.25,0.55], */ splitConfig: Array; /** 预加载任务数量 */ prefetchCount: number; /** 评卷开始时间 */ startTime: number; /** 评卷结束时间 */ endTime: number; /** 是否是未选做类型 */ selective: boolean; /** 可回评数量是否有限制数 */ remarkCount?: any; /** 是否展示双评的轨迹 */ doubleTrack?: boolean; /** 全卷复核页面是否要滑到页面底部才允许点击复核按钮 */ inspectScroll?: boolean; /** 评卷员页头是否展示客观分 */ showObjectiveScore?: boolean; } /** 科目信息(试卷和答案功能) */ interface RawSubject { /** 科目名称 */ name: string; /** 科目编号 */ code: string; /** 学生答案json url */ answerUrl: string; /** 试卷json url */ paperUrl: string; } /** 科目信息(试卷和答案功能)增加前端自定义 questions字段*/ interface Subject extends RawSubject { /** 前端自定义questions字段, 在多媒体阅卷模式下使用 */ questions: Array; } // setting for admin page export interface AdminPageSetting { /** 扫描图片或者多媒体,多媒体只允许 common mode */ examType: "SCAN_IMAGE" | "MULTI_MEDIA"; /** 图片服务地址 */ fileServer: string; /** 管理员姓名 */ userName: string; /** 科目信息 */ subject: Subject; /** 使用裁切整图时的裁切配置 [0,1]|[0,0.3,0.25,0.55], */ splitConfig: Array; enableSplit: boolean; doubleTrack?: boolean; inspectScroll?: boolean; } export interface AdminPageSettingForImport extends AdminPageSetting { studentIds: number[]; tagIds: number[]; inspectCount: number; message: string; } export interface Group { markerId: number; /** 分组编号 */ number: number; /** 分组title */ title: string; /** 总评卷数量 */ markedCount: number; /** 总数量 */ totalCount: number; } interface RawTask { libraryId: number; /** 学生ID */ studentId: number; /** 任务编号 */ secretNumber: string; /** 后端处理是否显示 */ /** 学生名称 */ studentName: string; /** 学生编号 */ studentCode: string; /** 考试编号 */ examNumber: string; /** 一般不要用此处的subject,优先用setting.subject */ subject?: Subject; /** 裁切图url */ sliceUrls: Array; /** 最高显示优先级,有sliceConfig就用sliceConfig,否则使用sheetConfig */ sliceConfig: Array; /** sliceUrls为空,则是多媒体阅卷,显示JSON */ jsonUrl: string; questionList: Array; specialTagList: Array; /** 原图url */ sheetUrls: Array; /** 客观分 复核也用到 */ objectiveScore: number; /** 评卷总分 */ markerScore: number; /** 评卷时间 */ markerTime: number; /** 复核有用 */ inspectTime?: number; /** 是否自评,暂时用不着 */ self: boolean; /** 是否回评 */ previous: boolean; /** 是否是打回 */ rejected: boolean; /** 打回原因 冒号拼接的 */ rejectReason: string; message: string | null; rejectScoreList?: any; headerTagList?: any; } export interface Task extends RawTask { /** 评卷结果,在task第一次被访问时自动添加,watch currentTask */ markResult: MarkResult; /** 前端自用,用于标记阅卷开始时间和计算spent */ __markStartTime: number; } interface RawQuestion { /** 分组序号 */ groupNumber: number; /** 大题号 */ mainNumber: number; /** 小题号 */ subNumber: string; /** 分数间隔 */ intervalScore: number; /** 默认分数 */ defaultScore: number; /** 限制最小分数 */ minScore: number; /** 限制最大分数 */ maxScore: number; /** 题目名称 */ title: string; /** 轨迹列表 */ trackList: Array; /** 得分;null的值时是为打回时可以被评卷修改的;null也是从未评分过的情况,要通过rejected来判断 */ score: number | null; /** 未计分 */ uncalculate: boolean; /** 选做题分组 */ selectiveIndex: number | null; rejected?: boolean; questionName?: string; headerTrack?: any; } export interface Question extends RawQuestion { /** question 在 task 里面的 index ,用来对应 scoreList 的 score */ __index: number; } export interface ColorMap { [key: string]: string; } /** 轨迹数据 */ export interface Track { /** 大题号 */ mainNumber: number; /** 小题号,当前api中只有number // 特殊标记中没有 */ subNumber: string; /** 前端使用,暂时用不着,赋0 */ number: number; /** 第几张图 */ offsetIndex: number; /** 左上角为原点 */ offsetX: number; offsetY: number; /** 相对slice的位置比例 */ positionX: number; positionY: number; /** 评分数 */ score: number; /** 是否此处未作答,未作答时,score默认是-0分 */ unanswered: boolean; markerId?: number; color?: string; isByMultMark?: boolean; } /** 特殊标记数据 */ export interface SpecialTag { /** 第几张图 */ offsetIndex: number; /** 左上角为原点 */ offsetX: number; offsetY: number; /** 相对slice的位置比例 */ positionX: number; positionY: number; /** 特殊标记的字符串,勾叉 */ tagName: string; tagType: "TEXT" | "CIRCLE" | "RIGHT" | "WRONG" | "HALF_RIGTH"; markerId?: number; color?: string; isByMultMark?: boolean; } export interface UISetting { /** 给分面板展示形态 */ "score.board.collapse": boolean; /** 0.2 gap */ /** 试卷缩放比例 */ "answer.paper.scale": number; /** * 给分模式 * "keyboard": 键盘模式 * "mouse": 鼠标模式 * */ "normal.mode": "keyboard" | "mouse"; /** 弹窗显示试卷 */ "paper.modal": boolean; /** 弹窗显示答案 */ "answer.modal": boolean; /** 弹窗显示缩略图 */ "minimap.modal": boolean; /** 弹窗显示特殊字符 */ "specialTag.modal": boolean; /** 弹窗显示快捷键配置 */ "shortCut.modal": boolean; /** 0.1 gap */ /** 分数标记缩放比例 */ "score.fontSize.scale": number; } export interface MarkResult { libraryId: number; studentId: number; statusValue: "TRIAL" | "FORMAL" | null; /** 毫秒单位 */ spent: number; // 轨迹 or 键盘 markerScore: number | null; /** 轨迹列表 */ trackList: Array; /** 给分列表 */ scoreList: Array; /** 轨迹和键盘都需要 */ specialTagList: Array; /** 问题卷 */ problem: boolean; /** 问题卷类型ID */ problemTypeId: number; /** 当前task是否为学生未选做 */ unselective: boolean; } /** 前端自用,用来渲染裁切图 */ export interface SliceImage { /** 当前是 ObjectURL , 因为 DataURL 性能太差 */ url: string; indexInSliceUrls: number; trackList: Array; tagList: Array; // originalImageWidth: number; // 为了兼容原图还原轨迹而添加的属性,当前CommonMarkBody用不到 // originalImageHeight: number; // 为了兼容原图还原轨迹而添加的属性,当前CommonMarkBody用不到 sliceImageWidth: number; sliceImageHeight: number; /** 裁切图在原图中的左上角的x偏移量 */ dx: number; /** 裁切图在原图中的左上角的y偏移量 */ dy: number; /** 在多个图片从高至低排列中累积的高度 */ accumTopHeight: number; /** 当前裁切图有效宽度,大小不一的裁切图时有用。 * 为了能让多张图统一比例的缩放,所以将所有的图的宽度设为一样了。 */ effectiveWidth: number; } export type MarkHistoryOrderBy = | "markerTime" | "inspectTime" | "markerScore" | "seceretNumber" | undefined; export type MarkHistorySortField = "ASC" | "DESC" | undefined; export interface HistoryQueryParams { /** 从1开始 */ pageNumber?: number; pageSize?: number; order?: MarkHistoryOrderBy; sort?: MarkHistorySortField; secretNumber?: string | null; subjectCode?: string; groupNumber?: string; markerId?: string; markerScore?: string; } export interface GetHistory { (historyQuery: HistoryQueryParams): Promise< AxiosResponse | undefined >; } export interface CommonResponse { /** 请求是否成功 */ success: boolean; /** 错误消息 */ message: string; } /** 仲裁用:评卷明细 */ export interface MarkDetail { markerName: string; markerTime: number; totalScore: number; scoreList: string; } //#region 多媒体评卷 export interface RichTextQuestion { /** 题目的综合题号 1-2-4 */ unionOrder: string; body: RichTextJSON; parentBody: RichTextJSON | null; answer: Array | null; objective: boolean | null; options: Array<{ number: number; body: RichTextJSON }> | null; hideAnswer?: boolean; } export interface QuestionForRender extends Omit { studentAnswer: RichTextQuestion["answer"]; standardAnswer: RichTextQuestion["answer"]; score: number | null; totalScore: number; } export interface RichTextJSON { sections: RichTextSectionJSON[]; } export interface RichTextSectionJSON { blocks: RichTextBlockJSON[]; } export interface RichTextBlockJSON { type: "text" | "image" | "audio" | "cloze"; value: string; param: { underline: boolean; bold: boolean; italic: boolean; width: string; height: string; } | null; } export interface StudentAnswer { mainNumber: number; subNumber: string; subIndex: string; answer: Array | null; } /** 云平台试卷格式 */ export type ECSPaperJSON = { mainNumber: number; subNumber: string; body: RichTextJSON; parentBody: RichTextJSON | null; answer: RichTextJSON; }[]; /** 在线考试平台试卷格式 */ export type OExamPaperJSON = OExamPaperJSONQuestionList[]; interface OExamPaperJSONQuestionList { /** 大题号 */ number: number; questions: OExamPaperJSONQuestion[]; } interface OExamPaperJSONQuestion { number: number; body: RichTextJSON; answer: RichTextJSON[] | null; objective: boolean | null; options: Array<{ number: number; body: RichTextJSON }>; subQuestions: OExamPaperJSONQuestion[] | null; /** 1-单选,2-多选,3-判断,4-填空,5-问答,6-套题,7-听力,8-配对题 */ structType: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; } //#endregion