微服務的編程測評系統8-題庫管理-競賽管理

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔

文章目錄

  • 前言
  • 1. 添加題目
    • 1.1 service方法
    • 1.2 畫頁面-引入富文本和代碼編輯框
    • 1.3 子組件中發送請求
  • 2. 獲取題目詳情
  • 3. 編輯題目
  • 4. 刪除題目
  • 5. Vue生命周期函數
    • 5.1 創建階段
    • 5.2 掛載階段
    • 5.3 更新階段
    • 5.4 卸載階段
  • 6. 競賽管理
    • 6.1 表結構設計
  • 7. 競賽列表功能
    • 7.1 后端開發
    • 7.2 前端開發
  • 總結


前言

1. 添加題目

1.1 service方法

先在question.js里面添加方法


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 },});
}

1.2 畫頁面-引入富文本和代碼編輯框

npm install @vueup/vue-quill@1.2.0

這個是富文本的

npm install ace-builds@1.4.13

這個是代碼編輯框
添加題目的前端我們可以提取為一個組件QuestionDrawer.vue

<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" vmodel="formQuestion.difficulty" width="100%"placeholder="請選擇題?難度"></selector></el-form-item><el-form-item label="時間限制(單位毫秒):"><el-input style="width:300px !important" vmodel="formQuestion.timeLimit"placeholder="請輸?時間限制"></el-input></el-form-item><el-form-item label="空間限制(單位字節):"><el-input style="width:300px !important" vmodel="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" vmodel="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>
</script>
<style lang="scss">
.question-button {width: 200px;
}
</style>

el-drawer是抽屜
在這里插入圖片描述

                <div class="editor"><quill-editor placeholder="請輸?題?內容" v-model:content="formQuestion.content"></quill-editor></div>

這個是富文本編輯器組件

                <code-editor ref="addcodeform" :defaultCode="formQuestion.defaultCode"@update:value="handleEditorContent"></code-editor>

這個是代碼編輯器

import { QuillEditor } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css'

富文本編輯器引入就可以直接用了
代碼編輯器還有配置才可以使用
再次給代碼編輯器創建一個子組件CodeEditor.vue

<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>
import CodeEditor from './CodeEditor.vue'; 

然后再question.vue中引入抽屜

import QuestionDrawer from "@/components/QuestionDrawer.vue";

在這里插入圖片描述

    <el-drawer v-model="visibleDrawer">
const visibleDrawer = ref(true); 
const formQuestion = reactive({title: '',difficulty: '',timeLimit: '',spaceLimit: '',content: '',questionCase: '',defaultCode: '',mainFuc: '',
});

因為都是let屬性的,所以可以這樣寫,都寫成字符串類型,前端的類型是可以自動變化的
在這里插入圖片描述
最上邊的空白是抽屜的titel
在這里插入圖片描述

    <el-drawer v-model="visibleDrawer" :with-header="false">

在這里插入圖片描述
然后是題目難度的引入

                <QuestionSelector  style="width:387px !important" v-model="formQuestion.difficulty" width="100%"placeholder="請選擇題?難度"></QuestionSelector>
import QuestionSelector from './QuestionSelector.vue';

或者

                <QuestionSelector  style="width:387px !important" v-model="formQuestion.difficulty" width="100%"placeholder="請選擇題?難度"></QuestionSelector>

都是可以的
在這里插入圖片描述
然后我們把寬度弄大一點
在這里插入圖片描述

    <el-drawer v-model="visibleDrawer" :with-header="false" size="50%">

在這里插入圖片描述
現在設置點擊添加題目才彈出來
默認為收回狀態

      <el-button plain type="primary" :icon="Plus" @click="onAddQuetion">添加題?</el-button>

怎么在父組件里面修改子組件的屬性呢
先獲取子組件的實例

    <question-drawer ref="questionDrawerRef"></question-drawer>

然后定義一個響應式數據來存儲子組件實例

const questionDrawerRef = ref();

然后再子組件中定義修改屬性的方法

function open() {visibleDrawer.value = true;
}

所以在父組件中調用這個方法就可以了
但是這個方法要暴露才可以


defineExpose({open,
});

這樣就可以暴露
然后可以在父組件中調用了

function onAddQuetion(){questionDrawerRef.value.open(); 
}

這樣就OK了

點擊旁邊的空白處就可以收回抽屜

1.3 子組件中發送請求

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) {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])}console.log(formQuestion)await addQuestionService(fd)ElMessage.success('添加成功')visibleDrawer.value = false
}

validate是用來判斷某個字段是不是沒有填寫

            <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>

這個又是子組件,怎么把子組件中的數據同步到父組件呢

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;}
});

定義了一個事件update:value

    editor.getSession().on('change', () => {// 當編輯器內容變化時,觸發?定義事件并傳遞編輯器的內容emit('update:value', editor.getValue());});

這個就是監聽到內容發送變化的時候觸發這個事件update:value
會把編輯器的內容作為參數傳遞給事件處理器update:value

            <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>

事件處理器的函數定義在父組件中,用于觸發相應的邏輯
意思就是內容發送變化的時候會調用函數handleEditorContent
然后會把編輯器的你內容作為參數給這個函數
這樣就可以獲得編輯器的內容了

function handleEditorContent(content){formQuestion.defaultCode = content
}
function handleEditorMainFunc (content){formQuestion.mainFuc = content
}
            <el-form-item label="默認代碼塊:"><code-editor ref="addcodeform" @update:value="handleEditorContent"></code-editor></el-form-item><el-form-item label="main函數:"><code-editor ref="addcodeform" @update:value="handleEditorMainFunc"></code-editor></el-form-item>

在這里插入圖片描述
但是后端需要的是json,前端是表單數據,只需要設置一下請求頭為json就可以了

service.defaults.headers["Content-Type"] = "application/json;charset=utf-8";  

在這里插入圖片描述
zairequest.js里面這樣設置就可以了

但是我們還要設置一下,就是添加成功以后,刷新一下列表
但是添加題目的請求是在抽屜里面的,怎么弄到父組件呢,怎么告訴父組件呢
我們只需要學習一下編輯器,自己定義一個事件就可以了

const emit = defineEmits(['success']);
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])}console.log(formQuestion)await addQuestionService(fd)ElMessage.success('添加成功')emit('success')visibleDrawer.value = false
}

定義一個事件。添加成功以后就會觸發事件sucess
然后在queston組件里面定義這個事件來使用

    <question-drawer ref="questionDrawerRef" @success="onSuccess"></question-drawer>function onSuccess(){getQuestionList();  
}

這樣的話添加就會馬上顯示到列表了
但是頁碼應該也切換到第一頁

function onSuccess(){paranms.pageNum = 1;  getQuestionList();  
}

這樣就行了
然后還有一個問題就是點擊添加題目的時候,上一次添加的內容還有
在這里插入圖片描述
配置這個屬性就可以了

    <el-drawer v-model="visibleDrawer" :with-header="false" size="50%" :destroy-on-close="true">

但是這個只能消除代碼編輯器的內容,因為這個屬性只是銷毀子組件,而不能銷毀v-model里面的數據

function open() {visibleDrawer.value = true;for(const key in formQuestion){formQuestion[key] = ''  }
}

這樣就可以了

2. 獲取題目詳情

先寫Question.vue

      <template #default="{ row }"><el-button type="text" @click="onEdit(row.questionId)">編輯</el-button><el-button type="text" class="red">刪除</el-button></template>

這樣就可以了
主要就是把questionId傳給子組件了
調用那個open方法就可以了

async function onEdit(questionId){ questionDrawerRef.value.open(questionId); 
} 
async function open(questionId) {visibleDrawer.value = true;for(const key in formQuestion){formQuestion[key] = ''  }if(questionId){const res = await getQuestionDetailService(questionId)Object.assign(formQuestion, res.data)   }
}

這樣就可以把res.data里面的數據賦值給formQuestion

在這里插入圖片描述
但是報了這個錯怎么回事呢
我們在數據庫中查看一下,不存在這個id
在這里插入圖片描述
但我們用apifox查出來的id是這個,和前端展示的不一樣,為什么呢
因為返回的是long,前端存儲不了,就會截斷,所以顯示不對
所以我們可以把long變為string類型,再返回給前端
這樣的話,就不會截斷了

@Data
public class QuestionVO {@JsonSerialize(using = ToStringSerializer.class)private Long questionId;private String title;private Integer difficulty;private String createName;private LocalDateTime createTime;
}

這樣就可以了
因為前端類型是任意變化的,所以我們不用改,它會隨著后端的變化而變化
然后請求的時候,前端的questionId是string,但是后端要求為long,所以前端就會轉為long,后端返回數據long,前端就用int來接受,后端返回string,前端就用string,所以前端是動態變化的類型
在這里插入圖片描述

這樣就OK了
然后還有創建時間那里也有問題,多了一個T

@Data
public class QuestionVO {@JsonSerialize(using = ToStringSerializer.class)private Long questionId;private String title;private Integer difficulty;private String createName;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;
}

在這里插入圖片描述

這樣就可以了

在這里插入圖片描述
但是編輯器的內容沒有呢
因為編輯器沒有v-model
后端返回了數據,但是前端沒有展示
題目內容沒有顯示的原始主要是因為我們沒有指定這個富文本的內容格式

                    <quill-editor placeholder="請輸?題?內容" v-model:content="formQuestion.content" contentType="html"></quill-editor>

至于代碼框呢,主要是因為沒有類似于v-model的指定
我們可以把數據傳給子組件編輯器,怎么傳呢,類似于open方法的使用就可以了
在CodeEditor里面

function setAceCode(content){editor.setValue(content);
}defineExpose({setAceCode
});

然后再quertionDrawer里面

            <el-form-item label="默認代碼塊:"><code-editor  @update:value="handleEditorContent" ref="defaultCodeRef"></code-editor></el-form-item><el-form-item label="main函數:"><code-editor @update:value="handleEditorMainFunc" ref="mainFuncRef"></code-editor></el-form-item>
const defaultCodeRef = ref();
const mainFuncRef = ref();async function open(questionId) {visibleDrawer.value = true;for(const key in formQuestion){formQuestion[key] = ''  }if(questionId){const res = await getQuestionDetailService(questionId)Object.assign(formQuestion, res.data)   defaultCodeRef.value.setAceCode(res.data.defaultCode)mainFuncRef.value.setAceCode(res.data.mainFuc)}
}

這樣就可以了

3. 編輯題目


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])}console.log(formQuestion)if(formQuestion.questionId){await editQuestionService(formQuestion.questionId)ElMessage.success('修改成功')emit('success','edit')}else{await addQuestionService(fd)ElMessage.success('添加成功')emit('success','add')}visibleDrawer.value = false
}
const formQuestion = reactive({questionId: '',title: '',difficulty: '',timeLimit: '',spaceLimit: '',content: '',questionCase: '',defaultCode: '',mainFuc: '',
});

然后在question.vue中

function onSuccess(params){if(params==='add'){paranms.pageNum = 1;  getQuestionList();  }else if(params==='edit'){getQuestionList(); }
}

修改數據不用把頁面置為1,添加的話要把數據弄為1

@Data
public class QuestionDetailVO {@JsonSerialize(using = ToStringSerializer.class)private Long questionId;private String title;private Integer difficulty;private Long timeLimit;private Long spaceLimit;private String content;private String questionCase;private String defaultCode;private String mainFuc;
}

記得獲取詳細信息這里也要對questionId進行字符串的序列化

這樣測試的時候就成功了

4. 刪除題目

        <el-button type="text" class="red" @click="onDelete(row.questionId)">刪除</el-button>
async function onDelete(questionId){ await delQuestionService(questionId)paranms.pageNum = 1;ElMessage.success('刪除成功');getQuestionList();
}

刪除之后要變為第一頁才可以

這樣就成功了,很簡單

5. Vue生命周期函數

就是特定時刻完成特定的工作
官網

在CodeEditor.vue中

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;}
});

5.1 創建階段

setup()

5.2 掛載階段

onBeforeMount
onMounted

5.3 更新階段

onBeforeUpdate
onUpdated

5.4 卸載階段

onBeforeUnmount
onUnmounted

6. 競賽管理

6.1 表結構設計

create table tb_exam (
exam_id  bigint unsigned not null comment '競賽id(主鍵)',
title varchar(50) not null comment '競賽標題',
start_time datetime not null comment '競賽開始時間',
end_time datetime not null comment '競賽結束時間',
status tinyint not null default '0' comment '是否發布 0:未發布  1:已發布',
create_by    bigint unsigned not null  comment '創建人',
create_time  datetime not null comment '創建時間',
update_by    bigint unsigned  comment '更新人',
update_time  datetime comment '更新時間',
primary key(exam_id)
)

是否開賽,我們可以在前端用目前時間和開始時間和結束時間進行判斷
是否發布,我們用一個status進行判斷了,默認是未發布
題目和競賽是多對多的關系,所以我們可以新建一個表,來存儲它們的關系

create table tb_exam_question (
exam_question_id  bigint unsigned not null comment '競賽題目關系id(主鍵)',
question_id  bigint unsigned not null comment '題目id(主鍵)',
exam_id  bigint unsigned not null comment '競賽id(主鍵)',
question_order int not null comment '題目順序',
create_by    bigint unsigned not null  comment '創建人',
create_time  datetime not null comment '創建時間',
update_by    bigint unsigned  comment '更新人',
update_time  datetime comment '更新時間',
primary key(exam_question_id)
)

question_order int not null comment ‘題目順序’,設置這個的原因主要是因為我們要把先選擇的放在前面
發布還是不發布,就會影響用戶能不能看到這個競賽
結不結束這個競賽的話,可以根據當前時間和結束和開始時間來判斷

已經開始的競賽不能報名了
未開始的比賽,才可以報名
競賽有幾個狀態,發布,未發布
還有,未開始,開始,結束
還有,報名,未報名 —》用戶和競賽的關系
競賽倒計時就是當前時間和結束時間之差
只有結束的比賽才可以去競賽練習的,而且競賽練習沒有倒計時

7. 競賽列表功能

7.1 后端開發

基礎類

@Getter
@Setter
@TableName("tb_exam")
public class Exam extends BaseEntity {@TableId(value = "EXAM_ID", type = IdType.ASSIGN_ID)private Long examId;private String title;private LocalDateTime startTime;private LocalDateTime endTime;private Integer status;
}
@Getter
@Setter
@TableName("tb_exam_question")
public class ExamQuestion extends BaseEntity {@TableId(value = "EXAM_QUESTION_ID", type = IdType.ASSIGN_ID)private Long examQuestionId;private Long examId;private Long questionId;private Integer questionOrder;
}
@Data
public class ExamQueryDTO extends PageQueryDTO {private String title;private LocalDateTime startTime;private LocalDateTime endTime;
}
@Data
public class ExamVO {private Long examId;private String title;private LocalDateTime startTime;private LocalDateTime endTime;private Integer status;private LocalDateTime createTime;private String createName;}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ck.system.mapper.exam.ExamMapper"><select id="selectExamList" resultType="com.ck.system.domain.exam.vo.ExamVO">SELECTte.exam_id,te.title,te.start_time,te.end_time,te.create_time,ts.nick_name as create_name,te.statusFROMtb_exam teleft jointb_sys_user tsonte.create_by = ts.user_id<where><if test="title !=null and title !='' ">AND te.title LIKE CONCAT('%',#{title},'%')</if><if test="startTime != null and startTime != '' ">AND te.start_time >= #{startTime}</if><if test="endTime != null and endTime != ''">AND te.end_time &lt;= #{endTime}</if></where>ORDER BYte.create_time DESC</select>
</mapper>

時間的比較,時間戳大的反而比較小

    @Overridepublic List<ExamVO> list(ExamQueryDTO examQueryDTO) {PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());return examMapper.selectExamList(examQueryDTO);}

就這樣就可以了
但是前端傳過來的是字符串,前端沒有時間類型
在這里插入圖片描述
前端說無法把String轉化為LocalDateTime
因為前端沒有對應的LocalDateTime類型,只是apifox沒有,瀏覽器的前端還是有的

@Data
public class ExamQueryDTO extends PageQueryDTO {private String title;private String startTime;private String endTime;
}
<if test="startTime != null and startTime != '' ">

而且xml也是用 把時間看為字符串來比較的

因為后端的mybatis是可以把string類型轉化為時間類型進行比較的
在這里插入圖片描述

7.2 前端開發

<template><el-form inline="true"><el-form-item label="創建日期"><el-date-picker v-model="datetimeRange" style="width: 240px" type="datetimerange" range-separator="至"start-placeholder="開始日期" end-placeholder="結束日期"></el-date-picker></el-form-item><el-form-item label="競賽名稱"><el-input v-model="params.title" placeholder="請您輸入要搜索的競賽名稱" /></el-form-item><el-form-item><el-button @click="onSearch" plain>搜索</el-button><el-button @click="onReset" plain type="info">重置</el-button><el-button type="primary" :icon="Plus" plain @click="onAddExam">添加競賽</el-button></el-form-item></el-form><!-- 表格 --><el-table height="526px" :data="examList"><el-table-column prop="title" label="競賽標題" /><el-table-column prop="startTime" width="180px" label="競賽開始時間" /><el-table-column prop="endTime" width="180px" label="競賽結束時間" /><el-table-column label="是否開賽" width="100px"><template #default="{ row }"><div v-if="!isNotStartExam(row)"><el-tag type="warning">已開賽</el-tag></div><div v-else><el-tag type="info">未開賽</el-tag></div></template></el-table-column><el-table-column prop="status" width="100px" label="是否發布"><template #default="{ row }"><div v-if="row.status == 0"><el-tag type="danger">未發布</el-tag></div><div v-if="row.status == 1"><el-tag type="success">已發布</el-tag></div></template></el-table-column><el-table-column prop="createName" width="140px" label="創建用戶" /><el-table-column prop="createTime" width="180px" label="創建時間" /><el-table-column label="操作" width="180px"><template #default="{ row }"><el-button v-if="isNotStartExam(row) && row.status == 0" type="text" @click="onEdit(row.examId)">編輯</el-button><el-button v-if="isNotStartExam(row) && row.status == 0" type="text" @click="onDelete(row.examId)"class="red">刪除</el-button><el-button v-if="row.status == 1 && isNotStartExam(row)" type="text"@click="cancelPublishExam(row.examId)">撤銷發布</el-button><el-button v-if="row.status == 0 && isNotStartExam(row)" type="text"@click="publishExam(row.examId)">發布</el-button><el-button type="text" v-if="!isNotStartExam(row)">已開賽,不允許操作</el-button></template></el-table-column></el-table><!-- 分頁區域 --><el-pagination background size="small" layout="total, sizes, prev, pager, next, jumper" :total="total"v-model:current-page="params.pageNum" v-model:page-size="params.pageSize" :page-sizes="[5, 10, 15, 20]"@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</template><script setup>
import { Plus } from '@element-plus/icons-vue'
import { getExamListService, delExamService, publishExamService, cancelPublishExamService } from '@/apis/exam'
import { reactive, ref } from 'vue'
import router from '@/router'function isNotStartExam(exam) {const now = new Date(); //當前時間return new Date(exam.startTime) > now
}const params = reactive({pageNum: 1,pageSize: 10,startTime: '',endTime: '',title: ''
})const examList = ref([])
const total = ref(0)
const datetimeRange = ref([])</script>
            <el-date-picker v-model="datetimeRange" style="width: 240px" type="datetimerange" range-separator="至"start-placeholder="開始日期" end-placeholder="結束日期"></el-date-picker>
const datetimeRange = ref([])

這個是時間選擇框,其中v-model綁定的是一個數組,數組里面存儲的是開始和結束時間數據

然后就是開發js代碼了

import service from "@/utils/request";export function getExamListService(params) {return service({url: "/exam/list",method: "get",params,});
}
async function getExamList() {const res = await getExamListService(params);console.log("獲取題目管理表單數據:", res);examList.value = res.rows;total.value = res.total;
}getExamList();

在這里插入圖片描述

@Data
public class ExamVO {private Long examId;private String title;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime startTime;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime endTime;private Integer status;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;private String createName;}

然后是修改分頁請求

function handleSizeChange(newSize) {params.pageNum = 1;getExamList();
}
function handleCurrentChange(newPage) {getExamList();
}

然后是搜索和重置
然后就是datetimeRange 里面的元素數據類型是時間類型Date的,那要怎么辦呢,我們可以轉化為Json類型,為什么VO里面不用時間類型呢,因為apifox沒有時間類型來測試

function onSearch(){params.pageNum = 1;getExamList();
}function onReset(){params.startTime = ''params.endTime = ''params.title = ''params.pageNum = 1params.pageSize = 10datetimeRange.value.length = 0getExamList();
}
async function getExamList() {if(datetimeRange.value[0] instanceof Date){params.startTime =  datetimeRange.value[0].toISOString()}if(datetimeRange.value[1] instanceof Date){params.endTime =  datetimeRange.value[1].toISOString()}console.log("Exam,params:",params)const res = await getExamListService(params);console.log("獲取題目管理表單數據:", res);examList.value = res.rows;total.value = res.total;
}

這樣就可以了
instanceof 是判斷類型,如果不為空,而且為Date類型的話,那么就轉為json

總結

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91880.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91880.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91880.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于springboot的學習輔導系統設計與實現

學生&#xff1a;注冊登錄&#xff0c;學習視頻&#xff0c;學習資料&#xff0c;在線交流&#xff0c;系統公告&#xff0c;個人中心&#xff0c;后臺管理教師&#xff1a;登錄&#xff0c;個人中心&#xff0c;學習視頻管理&#xff0c;學習資料管理&#xff0c;簽到記錄管理…

Kubernetes (K8s) 部署Doris

官網提供yaml地址下載部署 https://doris.apache.org/zh-CN/docs/2.0/install/cluster-deployment/k8s-deploy/install-env/禁用和關閉 swap 在部署 Doris 時&#xff0c;建議關閉 swap 分區。 通過以下命令可以永久關閉 swap 分區。 echo "vm.swappiness 0">>…

AI生成圖片工具分享!

CZL在線工具箱近日推出了一款基于Cloudflare Workers AI的免費在線AI圖片生成服務。該服務采用**Stable Diffusion XL&#xff08;SDXL&#xff09;**模型&#xff0c;為用戶提供高質量、逼真的圖像生成體驗。 核心特性 全球GPU網絡&#xff1a;基于Cloudflare全球分布式GPU網…

Spring Batch的2種STEP定義方式

Spring Batch的2種STEP定義方式 1. 第一種&#xff1a;基于Chunk-Oriented Processing&#xff08;read&#xff0c;process&#xff0c;write&#xff09;形式 適用場景&#xff1a; 大數據量批處理&#xff1a;適合需要分批次讀取、處理并寫入大量數據的場景&#xff08;如數…

前端JS-調用單刪接口來刪除多個選中文件

當開發中遇到&#xff1a;服務端沒有刪除多個文件功能接口&#xff0c;只有單個刪除文件功能接口時&#xff0c;會遇到如何多選刪除文件效果最佳。await Promise.all(selectedDocPaths.map(async (path) > {try {await fileDelete(path)} catch (err) {throw new Error(刪除…

機器學習——過采樣(OverSampling),解決類別不平衡問題,案例:邏輯回歸 信用卡欺詐檢測

下采樣&#xff1a;機器學習——下采樣&#xff08;UnderSampling&#xff09;&#xff0c;解決類別不平衡問題&#xff0c;案例&#xff1a;邏輯回歸 信用卡欺詐檢測-CSDN博客 &#xff08;完整代碼在底部&#xff09; 解決樣本不平衡問題&#xff1a;SMOTE 過采樣實戰講解 …

Ettus USRP X440 進行“超短波個人衛星信號的偵查與干擾”任務

結合 Ettus USRP X440 進行“超短波個人衛星信號的偵查與干擾”任務&#xff0c;可以構建一個高性能、靈活可編程的電子對抗系統原型平臺。以下是面向科研/工程/軍用驗證場景的構思和技術文案&#xff1a; &#x1f6f0;? 項目名稱建議&#xff08;可選&#xff09;&#xff1…

如何在出售Windows11/10/8/7前徹底清除電腦數據

為了保護您的個人數據&#xff0c;在出售電腦前徹底清除數據是一個明智之舉。然而&#xff0c;僅僅刪除文件是不夠的&#xff0c;因為恢復工具通常可以恢復它們。因此&#xff0c;本指南分享了如何在出售電腦前清除數據&#xff0c;包括 Windows 11/10/8/7&#xff0c;確保您的…

Go語言實戰案例:多協程并發下載網頁內容

本文是《Go語言100個實戰案例 網絡與并發篇》第6篇&#xff0c;實戰演示如何使用 Goroutine 和 Channel&#xff0c;實現多協程并發抓取網頁內容&#xff0c;提升網絡請求效率&#xff0c;為構建爬蟲、內容聚合器、API 批量采集器打下基礎。一、實戰背景在互聯網項目中&#x…

分享鏈接實現狀態共享

有這么一個場景&#xff1a;就是有一些列表頁面&#xff0c;然后上面是有一些篩選項的&#xff0c;我去對這個列表做了一些篩選出來一個結果&#xff0c;然后我想把這個鏈接&#xff0c;或者說把這個篩選結構給分享出去&#xff0c;讓別人在打開這個頁面的時候&#xff0c;也是…

Fay數字人如何使用GPT-SOVITS進行TTS轉換以及遇到的一些問題

一、GPT-SoVITS 簡介 GPT-SoVITS 是一款開源的語音合成&#xff08;TTS&#xff09;工具&#xff0c;結合了 GPT 模型的文本理解能力與 SoVITS&#xff08;Sound of Voice In Text-to-Speech&#xff09;的聲紋模擬技術&#xff0c;能夠實現高自然度、個性化的語音合成。它支持…

HTML 顏色值

HTML 顏色值 引言 在網頁設計和開發中,顏色是一個重要的元素,它能夠幫助用戶更好地理解內容,提升視覺效果。HTML 顏色值是用于指定網頁中元素顏色的一種標準表示方法。本文將詳細介紹 HTML 顏色值的種類、表示方法以及在實際應用中的使用技巧。 HTML 顏色值種類 HTML 顏…

關于記錄一下“bug”,在做圖片上傳的時候出現的小問題

項目場景&#xff1a;之前的話寫過csdn&#xff0c;最近出現了一些小事情&#xff0c;所以耽誤了好久沒有更新&#xff0c;最近把以前的項目拿出來然后改了下環境就出現了一些問題&#xff0c;該項目使用SpringBoot3.5 SpringMVC Mybatis-Plus3.5.0&#xff0c;然后權限控制采…

數據結構:基礎知識和鏈表①

一、概念程序數據結構算法1.描述數據存儲和操作的結構 2.操作數據對象的方法二、衡量代碼的質量和效率 無論代碼操作數據量多大&#xff0c;希望程序代碼的運行時間保持恒定 隨著數據的增長&#xff0c;程序運行時間緩慢增長隨著數據的增長&#xff0c;程序運…

進階向:自動化天氣查詢工具(API調用)

自動化天氣查詢工具&#xff08;API調用&#xff09;完全指南天氣數據是日常生活中經常需要查詢的信息之一。本教程將介紹如何使用Python編寫一個自動化天氣查詢工具&#xff0c;通過調用開放的天氣API獲取實時天氣數據。這個工具適合完全不懂編程的新手學習&#xff0c;將從最…

【ROS2】常用命令

1、目錄結構在 ROS 2 包中&#xff0c;launch、urdf、rviz&#xff08;通常指 RViz 配置文件&#xff09;、config 等文件夾應直接放在包的根目錄下&#xff08;與 robot_arm/ Python 模塊目錄同級&#xff09;。這是 ROS 2 社區的通用約定&#xff0c;便于工具&#xff08;如 …

基礎組件(三):mysql連接池

文章目錄一、MySQL連接池設計1. 連接池解決了什么問題&#xff1f;連接池的作用 &#xff08;好處&#xff09;為什么不創建多條連接而用連接池2. 同步和異步連接池的區別同步連接池&#xff08;場景局限&#xff0c;應用服務器啟動時初始化資源&#xff09;異步連接池&#xf…

FI文件包含漏洞

本地文件包含&#xff08;LFI&#xff09;文件包含開發人員將可重復使用的內容寫到單個文件中&#xff0c;使用時直接調用此文件&#xff0c;無需再次編寫&#xff0c;這種調用文件的過程一般被稱為文件包含。這樣編寫代碼能減少代碼冗余&#xff0c;降低代碼后期維護難度&…

rapidocr_web v1.0.0發布了

建立RapidOCRWeb獨立倉庫 終于將web這塊代碼移了出來&#xff0c;成立了獨立倉庫RapidOCRWeb (https://github.com/RapidAI/RapidOCRWeb )。這樣以來&#xff0c;RapidOCR倉庫下的各個衍生項目均有自己的獨立倉庫&#xff0c;可以單獨控制發版和維護。這也算是為RapidOCR減負了…

Arduino IDE離線安裝ESP8266板管理工具

文章目錄概要官網地址開發板管理地址安裝ESP8266開發板支持離線安裝額外記錄NODE啟動服務概要 Arduino IDE離線安裝ESP8266板管理工具&#xff0c;在線安裝因為網絡或者https的問題不能安裝 官網地址 Adruino&#xff1a;https://www.arduino.cc/ ESP8266項目&#xff1a;<…