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

目录

前端创建页面的开发一

创建一个路由

用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.mzph.cn/bicheng/55139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

程序员软硬实力双修的成长之路

一、引言  随着AI辅助编程工具的迅速发展和广泛应用&#xff0c;AIGC大语言模型如chatgpt、midjourney、claude等接二连三地涌现&#xff0c;程序员的工作方式正在经历深刻的变革。AI技术的兴起是否会取代部分编程工作&#xff1f;这成为了行业内外广泛关注和讨论的焦点话题。…

Python基础知识 (七)--匿名函数

匿名函数表示没有名字的函数&#xff0c;这种函数得名于省略了用def关键字声明函数的标准步骤。 定义匿名函数语法&#xff1a; lambda 参数列表 : 表达式 调用匿名函数语法&#xff1a; 函数名 lambda 参数列表 : 表达式 函数名([参数列表]) 例如&#xff0c;一起来完成…

Scrapy入门

Scrapy是一个用Python实现的快速、高层次的屏幕抓取和web抓取框架&#xff0c;主要用于抓取web站点并从页面中提取结构化的数据。 安装 pip install scrapy 创建Scrapy项目 使用scrapy startproject命令创建一个新的Scrapy项目。例如&#xff0c;创建一个名为myproject的项…

Jenkins入门:从搭建到部署第一个Springboot项目(踩坑记录)

本文讲述在虚拟机环境下(模拟服务器)&#xff0c;使用docker方式搭建jenkins&#xff0c;并部署一个简单的Springboot项目。仅记录关键步骤和遇到的坑 目录 一、环境准备和基础工具安装 1. 环境 2. yum安装 3. docker安装 4. 内网穿透工具安装natapp 二、jenkins安装和配置…

毕业设计选题:基于ssm+vue+uniapp的校园二手交易平台小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

【python】函数介绍

学习目标 快速体验函数的使用了解函数的作用 函数 函数&#xff1a;是组织好的&#xff0c;可重复使用的&#xff0c;用来实现特定功能的代码段。 name "xiaoming" length len(name) print(length)输出结果是&#xff1a; 8 为什么随时都可以使用 len() 统计长…

操作系统与进程

1.操作系统 操作系统是计算机中的一个重要软件&#xff0c;它是一个专门进行管理的软件。操作系统可以通过驱动程序来间接管理外部硬件&#xff0c;也可以为计算机中的程序提供一个稳定的运行环境&#xff0c;从而来方便管理各种程序的运行&#xff0c;让程序之间的运行互不影…

上交所服务器崩溃:金融交易背后的技术隐患暴露杭州BGP高防服务器43.228.71.X

一、上交所宕机事件始末 2024 年 9 月 27 日&#xff0c;上交所交易系统突发崩溃&#xff0c;这一事件犹如一颗巨石投入平静的湖面&#xff0c;引起了轩然大波。当天上午&#xff0c;众多投资者反馈券商交易出现延迟问题&#xff0c;随后上交所发布了《关于股票竞价交易出现异常…

AI驱动的Java开发框架:Spring AI Alibaba实战部署教程

前言 随着生成式 AI 的快速发展&#xff0c;基于 AI 开发框架构建 AI 应用的诉求迅速增长&#xff0c;涌现出了包括 LangChain、LlamaIndex 等开发框架&#xff0c;但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言&a…

敏感字段加密 - 华为OD统一考试(E卷)

2024华为OD机试(E卷+D卷+C卷)最新题库【超值优惠】Java/Python/C++合集 题目描述 【敏感字段加密】给定一个由多个命令字组成的命令字符串: 1、字符串长度小于等于127字节,只包含大小写字母,数字,下划线和偶数个双引号; 2、命令字之间以一个或多个下划线 进行分割; 3、可…

WPF文本框无法输入小数点

问题描述 在WPF项目中&#xff0c;文本框BInding双向绑定了数据Text“{UpdateSourceTriggerPropertyChanged}”&#xff0c;但手套数据是double类型&#xff0c;手动输入数据时&#xff0c;小数点输入不进去 解决办法&#xff1a; 在App.xaml.cs文件中添加语句&#xff1a; …

【JavaSE系列】IO流

目录 前言 一、IO流概述 二、IO流体系结构 三、File相关的流 1. FileInputStream 2. FileOutputStream 3. FileReader 4. FileWriter 四、缓冲流 五、转换流 1. InputStreamReader 2. OutputStreamWriter 六、数据流 七、对象流 八、打印流 九、标准输入输出流…

探讨MySQL中的GROUP BY语句大小写敏感性

在数据库操作中&#xff0c;GROUP BY语句是SQL查询中用于根据一个或多个列的值对结果集进行分组的重要工具。然而&#xff0c;对于字符串类型的列&#xff0c;GROUP BY的行为可能会因为大小写敏感性而有所不同。本文将深入探讨MySQL中GROUP BY语句的大小写敏感性&#xff0c;并…

如何通过 GitHub Actions 使用 SSH 自动化部署到阿里云 ECS 实例

在现代应用开发中,自动化部署是提升开发效率的重要工具之一。GitHub Actions 是 GitHub 提供的一种自动化工具,允许开发者在代码推送时自动执行一些任务,比如测试、构建和部署。本文将介绍如何通过 GitHub Actions 使用 SSH 登录到阿里云 ECS 实例,实现自动化部署。 场景设…

Apache APISIX学习(2):安装Grafana、prometheus

一、Grafana安装 1、介绍 Grafana 是一个监控仪表系统&#xff0c;它是由 Grafana Labs 公司开源的的一个系统监测 (System Monitoring) 工具。它可以大大帮助你简化监控的复杂度&#xff0c;你只需要提供你需要监控的数据&#xff0c;它就可以帮你生成各种可视化仪表。同时它…

Deep Learning for Video Anomaly Detection: A Review 深度学习视频异常检测综述阅读

Deep Learning for Video Anomaly Detection: A Review 深度学习视频异常检测综述阅读 AbstractI. INTRODUCTIONII. BACKGROUNDA. Notation and TaxonomyB. Datasets and Metrics III. SEMI-SUPERVISED VIDEO ANOMALY DETECTIONA. Model InputB. MethodologyC. Network Archite…

基于Python实现的国庆节庆祝小程序

祖国母亲即将迎来75周年华诞&#xff0c;在这个特殊的日子里&#xff0c;我们可以用编程的方式来表达对祖国的祝福。本文将使用Python编写一个简单的国庆节庆祝小程序&#xff0c;通过一些编程技巧和设计为国庆节增添一些程序员的特色。 ⭕️庆祝国庆 ⭐️ 程序设计思路&#x…

828华为云征文|部署个人知识管理系统 SiyuanNote

828华为云征文&#xff5c;部署个人知识管理系统 SiyuanNote 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 SiyuanNote3.1 SiyuanNote 介绍3.2 SiyuanNote 部署3.3 Siyua…

Linux下C开发使用小技巧

Linux下C开发使用小技巧 基础类 整形,字符串互转 C语言提供了几个标准库函数&#xff0c;可以将任意类型(整型、长整型、浮点型等)的数字转换为字符串&#xff0c;下面列举了各函数的方法及其说明。 ● itoa()&#xff1a;将整型值转换为字符串。 ● ltoa()&#xff1a;将长…

大数据毕业设计选题推荐-重庆旅游景点数据分析系统-Python-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…