请求函数
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 },
});
}
这个我们已经写了好多次了,我们不再赘述
增加弹框
发布
<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>
细节分析
安装插件
![]()

富文本编译器

代码编译器

富文本编译器的使用直接引入就行

代码编译器的引入需要我们引入子组件
<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>
![]()
这个时候我们去访问前端页面,点击增加题目,发现无反应,因为我们还没有引入抽屉

但是这个时候,我们发现点击之后还是美颜弹出
默认不展示


现在去访问,我们发现有报错,这是因为我们之前写的代码,具有双向绑定,但是它没有找到参数,所以我们创建一个参数(响应式数据)

效果展示
目前当我们一进去之后,就会有弹框出现;
但是目前还有很多问题:
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中传入参数,然后在父组件中进行判断是否跳到第一页

删除题目
前面俩个难的已经解决,剩下一个简单的

我们这里增加一个确认删除,防止误删


浙公网安备 33010602011771号