OJ在线评测系统 前端创建题目(增) 更新题目(改) 题目列表(查) 以及做题页面的开发 基于VUECLI脚手架画界面

devtools/2024/9/29 18:23:51/

目录

前端创建页面的开发一

创建一个路由

用acro design写

前端创建页面的开发二

题目管理页面

搜索

最終效果

题目更新页面的开发

携带参数的那种

修改路由

页码更新细节

我们先处理菜单项的权限控制和权限隐藏

在这里改

属性绑定一个函数

可以参考聚合搜索项目状态改变和url状态同步

就会触发loadData函数

当分页页号改变时 触发@page-change事件 通过改变searchParams的数值

然后

题目列表搜索页

代码

设置路由

做题页面

代码

路由


前端创建页面的开发一

创建一个路由

  {path: "/add/question",name: "创建题目",component: AddQuestionView,meta: {access: ACCESS_ENUM.USER,},},

用acro design写

<template><div id="addQuestionView" style="max-width: 800px; margin: 0 auto"><h2 style="margin-bottom: 16px">创建题目</h2><a-form :model="form" label-align="left"><a-form-item label="标题"><a-input v-model="form.title" placeholder="" /></a-form-item><a-form-item label="标签"><a-input-tag v-model="form.tags" placeholder="请选择标签" allow-clear /></a-form-item><a-form-item label="题目内容"><MdEditor :value="form.content" :handle-change="onContentChange" /></a-form-item><a-form-item label="答案"><MdEditor :value="form.answer" :handle-change="onAnswerChange" /></a-form-item><a-form-item label="判题配置一"><div><a-form-item label="时间限制"><a-input-numberv-model="form.judgeConfig.timeLimit"placeholder="请输入时间限制"mode="button"min="0"size="large"/></a-form-item></div></a-form-item><a-form-item label="判题配置二"><div><a-form-item label="内存限制"><a-input-numberv-model="form.judgeConfig.memoryLimit"placeholder="请输入内存限制"mode="button"min="0"size="large"/></a-form-item></div></a-form-item><a-form-item label="判题配置三"><div><a-form-item label="堆栈限制"><a-input-numberv-model="form.judgeConfig.stackLimit"placeholder="请输入堆栈限制"mode="button"min="0"size="large"/></a-form-item></div></a-form-item><a-form-item label="测试用例配置"><!-- 使用表格布局或者 flex 布局 --><table><tbody><tr v-for="(judgeCaseItem, index) of form.judgeCase" :key="index"><td><a-form-item :label="`输入用例-${index}`" no-style><a-inputv-model="judgeCaseItem.input"placeholder="请输入测试输入用例"/></a-form-item></td><td><a-form-item :label="`输出用例-${index}`" no-style><a-inputv-model="judgeCaseItem.output"placeholder="请输入测试输出用例"/></a-form-item></td><td><a-button status="danger" @click="handleDelete(index)">删除</a-button></td></tr></tbody></table><div style="margin-top: 16px"><a-button @click="handleAdd" type="outline" status="success">新增测试用例</a-button></div></a-form-item><a-form-item style="text-align: center"><a-button type="primary" style="min-width: 200px" @click="doSubmit">提交</a-button></a-form-item></a-form></div>
</template><script setup lang="ts">
import { onMounted, ref } from "vue";
import MdEditor from "@/components/MdEditor.vue";
import { QuestionControllerService } from "../../../generated";
import message from "@arco-design/web-vue/es/message";
import { useRoute } from "vue-router";const route = useRoute();
// 如果页面地址包含 update,视为更新页面
const updatePage = route.path.includes("update");let form = ref({title: "",tags: [],answer: "",content: "",judgeConfig: {memoryLimit: 1000,stackLimit: 1000,timeLimit: 1000,},judgeCase: [{input: "",output: "",},],
});/*** 根据题目 id 获取老的数据*/
const loadData = async () => {const id = route.query.id;if (!id) {return;}const res = await QuestionControllerService.getQuestionByIdUsingGet(id as any);if (res.code === 0) {form.value = res.data as any;// json 转 js 对象if (!form.value.judgeCase) {form.value.judgeCase = [{input: "",output: "",},];} else {form.value.judgeCase = JSON.parse(form.value.judgeCase as any);}if (!form.value.judgeConfig) {form.value.judgeConfig = {memoryLimit: 1000,stackLimit: 1000,timeLimit: 1000,};} else {form.value.judgeConfig = JSON.parse(form.value.judgeConfig as any);}if (!form.value.tags) {form.value.tags = [];} else {form.value.tags = JSON.parse(form.value.tags as any);}} else {message.error("加载失败," + res.message);}
};onMounted(() => {loadData();
});const doSubmit = async () => {console.log(form.value);// 区分更新还是创建if (updatePage) {const res = await QuestionControllerService.updateQuestionUsingPost(form.value);if (res.code === 0) {message.success("更新成功");} else {message.error("更新失败," + res.message);}} else {const res = await QuestionControllerService.addQuestionUsingPost(form.value);if (res.code === 0) {message.success("创建成功");} else {message.error("创建失败," + res.message);}}
};/*** 新增判题用例*/
const handleAdd = () => {form.value.judgeCase.push({input: "",output: "",});
};/*** 删除判题用例*/
const handleDelete = (index: number) => {form.value.judgeCase.splice(index, 1);
};const onContentChange = (value: string) => {form.value.content = value;
};const onAnswerChange = (value: string) => {form.value.answer = value;
};
</script><style scoped>
#addQuestionView {
}
</style>

前端创建页面的开发二

开发的是其他增删改查页面

题目管理页面

查看

搜索

<template><div id="manageQuestionView"><a-table:ref="tableRef":columns="columns":data="dataList":pagination="{showTotal: true,pageSize: searchParams.pageSize,current: searchParams.current,total,}"@page-change="onPageChange"><template #optional="{ record }"><a-space><a-button type="primary" @click="doUpdate(record)"> 修改</a-button><a-button status="danger" @click="doDelete(record)">删除</a-button></a-space></template></a-table></div>
</template><script setup lang="ts">
import { onMounted, ref, watchEffect } from "vue";
import {Page_Question_,Question,QuestionControllerService,
} from "../../../generated";
import message from "@arco-design/web-vue/es/message";
import * as querystring from "querystring";
import { useRouter } from "vue-router";const tableRef = ref();const dataList = ref([]);
const total = ref(0);
const searchParams = ref({pageSize: 10,current: 1,
});const loadData = async () => {const res = await QuestionControllerService.listQuestionByPageUsingPost(searchParams.value);if (res.code === 0) {dataList.value = res.data.records;total.value = res.data.total;} else {message.error("加载失败," + res.message);}
};/*** 监听 searchParams 变量,改变时触发页面的重新加载*/
watchEffect(() => {loadData();
});/*** 页面加载时,请求数据*/
onMounted(() => {loadData();
});// {id: "1", title: "A+ D", content: "新的题目内容", tags: "["二叉树"]", answer: "新的答案", submitNum: 0,…}const columns = [{title: "题目id",dataIndex: "id",},{title: "标题",dataIndex: "title",},{title: "内容",dataIndex: "content",},{title: "标签",dataIndex: "tags",},{title: "答案",dataIndex: "answer",},{title: "提交数",dataIndex: "submitNum",},{title: "通过数",dataIndex: "acceptedNum",},{title: "判题配置",dataIndex: "judgeConfig",},{title: "判题用例",dataIndex: "judgeCase",},{title: "创建者",dataIndex: "userId",},{title: "创建时间",dataIndex: "createTime",},{title: "操作",slotName: "optional",},
];const onPageChange = (page: number) => {searchParams.value = {...searchParams.value,current: page,};
};const doDelete = async (question: Question) => {const res = await QuestionControllerService.deleteQuestionUsingPost({id: question.id,});if (res.code === 0) {message.success("删除成功");loadData();} else {message.error("删除失败");}
};const router = useRouter();const doUpdate = (question: Question) => {router.push({path: "/update/question",query: {id: question.id,},});
};
</script><style scoped>
#manageQuestionView {
}
</style>

最終效果

题目更新页面的开发

写一个动态路由

携带参数的那种

const router = useRouter();const doUpdate = (question: Question) => {router.push({path: "/update/question",query: {id: question.id,},});
};

修改路由

  {path: "/update/question",name: "更新题目",component: AddQuestionView,meta: {access: ACCESS_ENUM.USER,hideInMenu: true,},},

页码更新细节

我们的管理题目页面不能分页

我们先处理菜单项的权限控制和权限隐藏

在这里改

在组件里面定义属性

属性绑定一个函数

const onPageChange = (page: number) => {searchParams.value = {...searchParams.value,current: page,};
};

可以参考聚合搜索项目状态改变和url状态同步

当我们的属性改变了

就会触发loadData函数

当分页页号改变时 触发@page-change事件 通过改变searchParams的数值

并且通过watchEffect监听searchParams的改变

然后执行loadData重新加载速度

实现页号变化时触发数据的重新加载

然后

/*** 监听 searchParams 变量,改变时触发页面的重新加载*/
watchEffect(() => {loadData();
});

题目列表搜索页

代码

<template><div id="questionsView"><a-form :model="searchParams" layout="inline"><a-form-item field="title" label="名称" style="min-width: 240px"><a-input v-model="searchParams.title" placeholder="请输入名称" /></a-form-item><a-form-item field="tags" label="标签" style="min-width: 240px"><a-input-tag v-model="searchParams.tags" placeholder="请输入标签" /></a-form-item><a-form-item><a-button type="primary" @click="doSubmit">提交</a-button></a-form-item></a-form><a-divider size="0" /><a-table:ref="tableRef":columns="columns":data="dataList":pagination="{showTotal: true,pageSize: searchParams.pageSize,current: searchParams.current,total,}"@page-change="onPageChange"><template #tags="{ record }"><a-space wrap><a-tag v-for="(tag, index) of record.tags" :key="index" color="green">{{ tag }}</a-tag></a-space></template><template #acceptedRate="{ record }">{{`${record.submitNum ? record.acceptedNum / record.submitNum : "0"}% (${record.acceptedNum}/${record.submitNum})`}}</template><template #createTime="{ record }">{{ moment(record.createTime).format("YYYY-MM-DD") }}</template><template #optional="{ record }"><a-space><a-button type="primary" @click="toQuestionPage(record)">做题</a-button></a-space></template></a-table></div>
</template><script setup lang="ts">
import { onMounted, ref, watchEffect } from "vue";
import {Page_Question_,Question,QuestionControllerService,QuestionQueryRequest,
} from "../../../generated";
import message from "@arco-design/web-vue/es/message";
import * as querystring from "querystring";
import { useRouter } from "vue-router";
import moment from "moment";const tableRef = ref();const dataList = ref([]);
const total = ref(0);
const searchParams = ref<QuestionQueryRequest>({title: "",tags: [],pageSize: 8,current: 1,
});const loadData = async () => {const res = await QuestionControllerService.listQuestionVoByPageUsingPost(searchParams.value);if (res.code === 0) {dataList.value = res.data.records;total.value = res.data.total;} else {message.error("加载失败," + res.message);}
};/*** 监听 searchParams 变量,改变时触发页面的重新加载*/
watchEffect(() => {loadData();
});/*** 页面加载时,请求数据*/
onMounted(() => {loadData();
});// {id: "1", title: "A+ D", content: "新的题目内容", tags: "["二叉树"]", answer: "新的答案", submitNum: 0,…}const columns = [{title: "题号",dataIndex: "id",},{title: "题目名称",dataIndex: "title",},{title: "标签",slotName: "tags",},{title: "通过率",slotName: "acceptedRate",},{title: "创建时间",slotName: "createTime",},{slotName: "optional",},
];const onPageChange = (page: number) => {searchParams.value = {...searchParams.value,current: page,};
};const router = useRouter();/*** 跳转到做题页面* @param question*/
const toQuestionPage = (question: Question) => {router.push({path: `/view/question/${question.id}`,});
};/*** 确认搜索,重新加载数据*/
const doSubmit = () => {// 这里需要重置搜索页号searchParams.value = {...searchParams.value,current: 1,};
};
</script><style scoped>
#questionsView {max-width: 1280px;margin: 0 auto;
}
</style>

设置路由

  {path: "/questions",name: "浏览题目",component: QuestionsView,},

做题页面

代码

<template><div id="viewQuestionView"><a-row :gutter="[24, 24]"><a-col :md="12" :xs="24"><a-tabs default-active-key="question"><a-tab-pane key="question" title="题目"><a-card v-if="question" :title="question.title"><a-descriptionstitle="判题条件":column="{ xs: 1, md: 2, lg: 3 }"><a-descriptions-item label="时间限制">{{ question.judgeConfig.timeLimit ?? 0 }}</a-descriptions-item><a-descriptions-item label="内存限制">{{ question.judgeConfig.memoryLimit ?? 0 }}</a-descriptions-item><a-descriptions-item label="堆栈限制">{{ question.judgeConfig.stackLimit ?? 0 }}</a-descriptions-item></a-descriptions><MdViewer :value="question.content || ''" /><template #extra><a-space wrap><a-tagv-for="(tag, index) of question.tags":key="index"color="green">{{ tag }}</a-tag></a-space></template></a-card></a-tab-pane><a-tab-pane key="comment" title="评论" disabled> 评论区</a-tab-pane><a-tab-pane key="answer" title="答案"> 暂时无法查看答案</a-tab-pane></a-tabs></a-col><a-col :md="12" :xs="24"><a-form :model="form" layout="inline"><a-form-itemfield="language"label="编程语言"style="min-width: 240px"><a-selectv-model="form.language":style="{ width: '320px' }"placeholder="选择编程语言"><a-option>java</a-option><a-option>cpp</a-option><a-option>go</a-option><a-option>html</a-option></a-select></a-form-item></a-form><CodeEditor:value="form.code as string":language="form.language":handle-change="changeCode"/><a-divider size="0" /><a-button type="primary" style="min-width: 200px" @click="doSubmit">提交代码</a-button></a-col></a-row></div>
</template><script setup lang="ts">
import { onMounted, ref, watchEffect, withDefaults, defineProps } from "vue";
import message from "@arco-design/web-vue/es/message";
import CodeEditor from "@/components/CodeEditor.vue";
import MdViewer from "@/components/MdViewer.vue";import {QuestionControllerService,QuestionSubmitAddRequest,QuestionVO,
} from "../../../generated";interface Props {id: string;
}const props = withDefaults(defineProps<Props>(), {id: () => "",
});const question = ref<QuestionVO>();const loadData = async () => {const res = await QuestionControllerService.getQuestionVoByIdUsingGet(props.id as any);if (res.code === 0) {question.value = res.data;} else {message.error("加载失败," + res.message);}
};const form = ref<QuestionSubmitAddRequest>({language: "java",code: "",
});/*** 提交代码*/
const doSubmit = async () => {if (!question.value?.id) {return;}const res = await QuestionControllerService.doQuestionSubmitUsingPost({...form.value,questionId: question.value.id,});if (res.code === 0) {message.success("提交成功");} else {message.error("提交失败," + res.message);}
};/*** 页面加载时,请求数据*/
onMounted(() => {loadData();
});const changeCode = (value: string) => {form.value.code = value;
};
</script><style>
#viewQuestionView {max-width: 1400px;margin: 0 auto;
}#viewQuestionView .arco-space-horizontal .arco-space-item {margin-bottom: 0 !important;
}
</style>

路由

  {path: "/view/question/:id",name: "在线做题",component: ViewQuestionView,props: true,meta: {access: ACCESS_ENUM.USER,hideInMenu: true,},},

http://www.ppmy.cn/devtools/118821.html

相关文章

大模型增量训练--基于transformer制作一个大模型聊天机器人

针对夸夸闲聊数据集&#xff0c;利用UniLM模型进行模型训练及测试&#xff0c;更深入地了解预训练语言模型的使用方法&#xff0c;完成一个生成式闲聊机器人任务。 项目主要结构如下&#xff1a; data 存放数据的文件夹 dirty_word.txt 敏感词数据douban_kuakua_qa.txt 原始语…

LDRA Testbed(TBrun)软件单元测试_常见问题及处理

系列文章目录 LDRA Testbed软件静态分析_操作指南 LDRA Testbed软件静态分析_自动提取静态分析数据生成文档 LDRA Testbed软件静态分析_Jenkins持续集成(自动静态分析并用邮件自动发送分析结果) LDRA Testbed软件静态分析_软件质量度量 LDRA Testbed软件静态分析_常见问题及…

kibana开启访问登录认证

编辑es配置文件&#xff0c;添加以下内容开启es认证 vim /etc/elasticsearch/elasticsearch.yml http.cors.enabled: true http.cors.allow-origin: "*" http.cors.allow-headers: Authorization xpack.security.enabled: true xpack.security.transport.ssl.enable…

线上报名小程序怎么做

在这个数字化、智能化的时代&#xff0c;信息技术的发展正以前所未有的速度改变着我们的生活。无论是学习、工作还是娱乐&#xff0c;互联网都成为了我们不可或缺的一部分。而在线上报名这一领域&#xff0c;小程序的出现更是为广大用户带来了前所未有的便捷与高效。今天&#…

Linux——k8s组件

kubernetes 使用1.31.1 版本搭建集群核心组件&#xff0c;选择flannel 网络插件为整体集群的运行提供网络通信功能。 flannel 网络插件 kube-flannel kube-flannel-ds-9fgml 1/1 Running 1 (18m ago) 2d21h kube-flannel kube-flannel-ds-ghwbq …

Hive数仓操作(一)

Hive 介绍 Hive 是一个基于 Hadoop 的数据仓库工具&#xff0c;旨在简化大规模数据集的管理和分析。它将结构化数据文件映射为表&#xff0c;并提供类似 SQL 的查询功能。Hive 的数据存储在 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;中&#xff0c;使用 Hive 查询语…

《解锁高效流程设计:深度剖析责任链模式与实战应用》

《解锁高效流程设计&#xff1a;深度剖析责任链模式与实战应用》 责任链模式 是一种行为设计模式&#xff0c;它允许多个对象来处理请求&#xff0c;而不预先指定具体的处理者。多个处理对象被连接成一条链&#xff0c;沿着这条链传递请求&#xff0c;直到某个处理对象决定处理…

git拉代码时,远程也对文件进行了更改,后面如何操作

解决方法&#xff1a; 1.git stash 把当前未提交的修改暂存起来&#xff0c;让仓库还原到最后一次提交的状态。 2.git pull 拉取远程仓库的代码&#xff0c;让你现在的代码和远程仓库一致 3.git stash pop 放开暂存&#xff0c;恢复当前未提交的修改