微服务项目->在线oj系统(Java-Spring)--增删改(前端)
请求函数
export function addQuestionService(params = {}) {return service({url: "/question/add",method: "post",data: params,});
}
export function getQuestionDetailService(questionId) {return service({url: "/question/detail",method: "get",params: { questionId },});
}export function editQuestionService(params = {}) {return service({url: "/question/edit",method: "put",data: params,});
}export function delQuestionService(questionId) {return service({url: "/question/delete",method: "delete",params: { questionId },});
}
这个我们已经写了好多次了,我们不再赘述
增加弹框
<template><el-drawer><el-form :model="formModel" ref="formRef"><el-form-item label="题⽬标题:"><el-input style="width:387px !important" v-model="formQuestion.title" placeholder="请输⼊标题"></el-input></el-form-item><el-form-item label="题⽬难度:"><selector style="width:387px !important" v-model="formQuestion.difficulty" width="100%" placeholder="请选择题⽬难度"></selector></el-form-item><el-form-item label="时间限制(单位毫秒):"><el-input style="width:300px !important" v-model="formQuestion.timeLimit" placeholder="请输⼊时间限制"></el-input></el-form-item><el-form-item label="空间限制(单位字节):"><el-input style="width:300px !important" v-model="formQuestion.spaceLimit" placeholder="请输⼊空间限制"></el-input></el-form-item><el-form-item label="题⽬内容:"><div class="editor"><quill-editor placeholder="请输⼊题⽬内容" v-model:content="formQuestion.content"></quill-editor></div></el-form-item><el-form-item label="题⽬⽤例:"><el-input style="width:387px !important" v-model="formQuestion.questionCase" placeholder="请输⼊题⽬⽤例"></el-input></el-form-item><el-form-item label="默认代码块:"><code-editor ref="addcodeform" :defaultCode="formQuestion.defaultCode" @update:value="handleEditorContent"></code-editor></el-form-item><el-form-item label="main函数:"><code-editor ref="addcodeform" :defaultCode="formQuestion.mainFuc" @update:value="handleEditorMainFunc"></code-editor></el-form-item><el-form-item><el-button class="question-button" type="primary" plain @click="onSubmit()">发布</el-button></el-form-item></el-form></el-drawer>
</template><script setup>
import { ref, reactive } from 'vue'
import CodeEditor from './CodeEditor.vue';
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'</script><style lang="scss">
.question-button {width: 200px;
}
</style>
细节分析
安装插件
富文本编译器
代码编译器
富文本编译器的使用直接引入就行
代码编译器的引入需要我们引入子组件
<template><div ref="editorform" class="ace-editor"></div>
</template><script setup>
import { ref, onMounted, onBeforeUnmount } from "vue"
import ace from "ace-builds"
import "ace-builds/src-noconflict/mode-java"
import "ace-builds/src-noconflict/theme-eclipse"
import "ace-builds/src-noconflict/ext-language_tools";// 定义选项
const options = {theme: `ace/theme/eclipse`,mode: `ace/mode/java`,maxLines: 20,minLines: 10,fontSize: 15,
};
// 创建响应式引用
let editor = null;
const emit = defineEmits(['update:value']);
const editorform = ref(null);
// 初始化编辑器
onMounted(() => {editor = ace.edit(editorform.value, options);editor.setOptions({enableBasicAutocompletion: true,});editor.getSession().on('change', () => {// 当编辑器内容变化时,触发自定义事件并传递编辑器的内容emit('update:value', editor.getValue());});
});// 销毁编辑器实例
onBeforeUnmount(() => {if (editor) {editor.destroy();editor = null;}
});
</script><style lang="scss" scoped>
.ace-editor {margin: 10px 0 0 0;width: 90%;
}
</style>
这个时候我们去访问前端页面,点击增加题目,发现无反应,因为我们还没有引入抽屉
但是这个时候,我们发现点击之后还是美颜弹出
默认不展示
现在去访问,我们发现有报错,这是因为我们之前写的代码,具有双向绑定,但是它没有找到参数,所以我们创建一个参数(响应式数据)
效果展示
目前当我们一进去之后,就会有弹框出现;
但是目前还有很多问题:
1.弹框的大小有点不符合我们预期,而且上面有很大一片空白
2.弹框是自动弹出的,而不是我们点击添加题目弹出的
3.现在我们点击增加题目,我们发现不会有弹框
解决问题(1)
这个时候,我们突然发现,怎么题目难度框没有选择项呢?
这是因为我们没有引入难度选择组件
解决问题(2)
解决问题(3)
其实也很好想,无非就是增加一个点击事件,当我们点击的时候触发
但是,我们现在是在父组件中操作,但操作参数是子组件的内容,所以我们需要一个ref来引用
在子组件中创建一个函数,然后暴露出来
然后再父组件中实现方法
现在只有我们点击增加题目的时候才会弹出
点击发布的时候会触发一个点击事件
上面这个函数的作用是判断是否有空的数据,如果有,就抛出异常
function validate() {let msg = ''if (!formQuestion.title) {msg = '请添加题目标题'} else if (formQuestion.difficulty === '') {msg = '请选择题目难度'} else if (!formQuestion.timeLimit) {msg = '请输入时间限制'} else if (!formQuestion.spaceLimit) {msg = '请输入空间限制'} else if (!formQuestion.content) {msg = '请输入题目内容信息'} else if (!formQuestion.questionCase) {msg = '请输入题目用例名称'} else if (!formQuestion.defaultCode) {console.log("formQuestion.defaultCode:", formQuestion.defaultCode)msg = '请输入默认代码'} else if (!formQuestion.mainFuc) {msg = '请输入main函数'} else {msg = ''}return msg
}
async function onSubmit() {const errorMessage = validate()if (errorMessage) {ElMessage.error(errorMessage);return false}const fd = new FormData()for (let key in formQuestion) {fd.append(key, formQuestion[key])}await addQuestionService(fd)ElMessage.success('添加成功')visibleDrawer.value = false
}
这里我们可以发现和之前传递参数有些不同
这是因为我们这里是一个post请求,而且参数是在Body里面
先将用不上的去掉,得到下面
这是因为我们是在子组件中修改的参数,但是还没有同步到父组件
我们在这里定义一个事件
当监听器发现事件触发的时候
父组件定义一个事件处理器,当事件触发的时候进行调用,编译器中参数传给事件处理器
function handleEditorContent(content) {formQuestion.defaultCode = content
}function handleEditorMainFunc(content) {formQuestion.mainFuc = content
}
这是因为我们传输的是一个json数据
所以我们增加一个全局的请求头添加配置
这样我们后端如果是接受json类型的时候,我们就可以进行转化了
特殊情况:GET
/DELETE
请求通常不受影响
GET
/DELETE
请求一般通过 URL 参数(params
)传递数据,而非请求体(data
),因此Content-Type
对它们的影响很小(服务器通常会忽略这些请求的Content-Type
)。- 例如获取用户信息的
GET
请求,即使带上application/json
头,只要参数通过params
正确传递,后端仍能正常解析。
所以我们之前的不受影响
这时候我们就可以添加成功了,但是我们需要刷新一下才能显示,这是因为我们没有进行请求题目列表
这里我们子组件增加成功之后告诉父组件(和之前的方式一样)
现在增加成功后就会显示了
但是当我们如果切换到第二页,然后进行添加操作的时候,我们会发现没有显示,因为我们还是在第二页,所以我们继续修改
我们这个时候再次点击添加,我们发现,并没有清空上次的内容
这时候我们添加配置
关闭的时候自动清空
但是我们发现,上面输入框里面的并没有清空,这是因为双向绑定的原因
所以我们在打开页面的时候,将数据进行清空
这样增加前端就解决了
修改题目
增加一个点击事件
当我们点击编辑的时候,调用点击事件
由于我们需要获得参数questionId,所以我们需要使用插槽进行获取
由于是我们在子组件中进行获取详细信息操作,但是又需要父组件中的参数,那么我们可以使用之前的方法
在open中添加questionId,如果参数传了id,那么进行获得详情操作
由于我们进行了双向绑定,所以:我们需要进行赋值,但是由于我们的内容是封装为一个R的返回类型,所以我们需要使用questionDeatil.data
然后在父组件中调用open方法
此时点击编辑的时候,会报后端错误
这个是因为我们后端使用了雪花算法,但是我们后端定义的参数是Long类型的,溢出了,导致qusetionId有了问题
将ID的类型变为String类型
我们可以看到我们的前端题目创建时间不太好,所以进行格式修改
我们现在发现下面的富文本和代码部分没有展示详情
我们可以发现,后端是正确地返回了结果的,所以是前端问题
首先,富文本编译器那里是因为我们没有增加文本类型
现在展示出了题目内容,但是我们发现题目内容不对
查看数据库中的Content
这个原因是因为我们当时存的时候也没有指定类型,所以没有存对
现在我们新增一个
现在我们可以发现,代码块区域还是没有显示代码
我们观察代码
发现和前面的不一样,前面都是直接v-model双向绑定,而我们这里是调用的子组件,所以无法显示,那么我们和之前一样(子组件接收父组件的参数)
前情回顾
正式操作
下面就是修改完之后的发布
如果我们点击发布,我们之前的代码是不知道到底是增加还是删除
但是我们知道增加的时候我们是不知道它的questionId的,但是修改的时候知道,所以根据有无Id进行判断,如果有ID进行编辑
但是还有一些瑕疵:我们修改完之后会和增加一样跳到第一页,导致可能无法看到当前修改的信息
所以,可以在emit中传入参数,然后在父组件中进行判断是否跳到第一页
删除题目
前面俩个难的已经解决,剩下一个简单的
我们这里增加一个确认删除,防止误删