|
@@ -0,0 +1,374 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <el-dialog
|
|
|
+ custom-class="gpt-question-dialog"
|
|
|
+ :visible.sync="modalIsShow"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ append-to-body
|
|
|
+ fullscreen
|
|
|
+ @opened="dialogOpened"
|
|
|
+ >
|
|
|
+ <div slot="title">
|
|
|
+ <div>
|
|
|
+ <h2>智能出题</h2>
|
|
|
+ <span>课程代码:{{ formModel.courseCode }}</span>
|
|
|
+ <span>课程名称:{{ formModel.courseName }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="part-box">
|
|
|
+ <h2 class="part-box-title">生成试题</h2>
|
|
|
+
|
|
|
+ <el-form :model="formModel" label-width="100px">
|
|
|
+ <el-form-item label="题型">
|
|
|
+ <el-button
|
|
|
+ v-for="item in BASE_QUESTION_TYPES"
|
|
|
+ :key="item.code"
|
|
|
+ :type="
|
|
|
+ formModel.questionType === item.code ? 'primary' : 'default'
|
|
|
+ "
|
|
|
+ size="small"
|
|
|
+ @click="switchQuestionType(item.code)"
|
|
|
+ >{{ item.name }}</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="出题数量">
|
|
|
+ <el-input-number
|
|
|
+ v-model="formModel.questionCount"
|
|
|
+ placeholder="出题数量"
|
|
|
+ style="width: 150px"
|
|
|
+ :min="1"
|
|
|
+ :max="100"
|
|
|
+ :step="1"
|
|
|
+ step-strictly
|
|
|
+ :controls="false"
|
|
|
+ ></el-input-number>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="IS_SELECTION_QUESTION" label="选项个数">
|
|
|
+ <el-input-number
|
|
|
+ v-model="formModel.optionCount"
|
|
|
+ placeholder="选项个数"
|
|
|
+ style="width: 150px"
|
|
|
+ :min="1"
|
|
|
+ :max="26"
|
|
|
+ :step="1"
|
|
|
+ step-strictly
|
|
|
+ :controls="false"
|
|
|
+ ></el-input-number>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="IS_BOOLEAN_QUESTION" label="填空个数">
|
|
|
+ <el-input-number
|
|
|
+ v-model="formModel.fillCount"
|
|
|
+ placeholder="填空个数"
|
|
|
+ style="width: 150px"
|
|
|
+ :min="1"
|
|
|
+ :max="100"
|
|
|
+ :step="1"
|
|
|
+ step-strictly
|
|
|
+ :controls="false"
|
|
|
+ ></el-input-number>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="知识点">
|
|
|
+ <property-tree-select
|
|
|
+ v-model="formModel.questionProperty"
|
|
|
+ :course-id="formModel.courseId"
|
|
|
+ @change="propertyChange"
|
|
|
+ ></property-tree-select>
|
|
|
+ <br />
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.supplement"
|
|
|
+ placeholder="请录入知识点补充说明"
|
|
|
+ type="textarea"
|
|
|
+ clearable
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="danger" @click="toProduct">生成试题</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="part-box">
|
|
|
+ <div class="box-justify">
|
|
|
+ <h2 class="part-box-title">检查试题</h2>
|
|
|
+ <div>
|
|
|
+ <el-button
|
|
|
+ type="danger"
|
|
|
+ :disabled="loading"
|
|
|
+ @click="toBatchDeleteQuestion"
|
|
|
+ >批量删除</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :disabled="loading"
|
|
|
+ @click="toSaveQuestion"
|
|
|
+ >加入题库</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ v-loading="loading"
|
|
|
+ element-loading-text="加载中"
|
|
|
+ :data="questionList"
|
|
|
+ @selection-change="tableSelectChange"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ type="selection"
|
|
|
+ width="50"
|
|
|
+ align="center"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column label="试题" min-width="200">
|
|
|
+ <div slot-scope="scope">
|
|
|
+ <rich-text
|
|
|
+ class="row-question-body"
|
|
|
+ title="点击查看试题"
|
|
|
+ :text-json="scope.row.quesBody"
|
|
|
+ ></rich-text>
|
|
|
+ </div>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="课程" width="120">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span>{{ scope.row.course.name }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="题型" prop="sourceDetailName" width="100">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="180" fixed="right">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div class="operate_left">
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="primary"
|
|
|
+ plain
|
|
|
+ @click="toEditQuestion(scope.row)"
|
|
|
+ >查看</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="danger"
|
|
|
+ plain
|
|
|
+ @click="toDeleteQuestion(scope.row)"
|
|
|
+ >删除</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div class="part-page">
|
|
|
+ <el-pagination
|
|
|
+ :current-page="currentPage"
|
|
|
+ :page-size="pageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100, 200, 300]"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ :total="total"
|
|
|
+ @current-change="toPage"
|
|
|
+ @size-change="handleSizeChange"
|
|
|
+ >
|
|
|
+ </el-pagination>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- GptQuestionEditDialog -->
|
|
|
+ <gpt-question-edit-dialog
|
|
|
+ ref="GptQuestionEditDialog"
|
|
|
+ :option-info="{ ...searchFormModel, propertyInfos }"
|
|
|
+ :question="curQuestion"
|
|
|
+ @modified="getList"
|
|
|
+ ></gpt-question-edit-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { BASE_QUESTION_TYPES } from "@/constants/constants";
|
|
|
+import PropertyTreeSelect from "./PropertyTreeSelect.vue";
|
|
|
+import GptQuestionEditDialog from "./GptQuestionEditDialog.vue";
|
|
|
+import {
|
|
|
+ buildGptQuestionApi,
|
|
|
+ gptQuestionListApi,
|
|
|
+ saveGptQuestionApi,
|
|
|
+ deleteGptQuestionApi,
|
|
|
+} from "../api";
|
|
|
+
|
|
|
+const initFormModel = {
|
|
|
+ courseId: null,
|
|
|
+ courseCode: "",
|
|
|
+ courseName: "",
|
|
|
+ questionType: "SINGLE_ANSWER_QUESTION",
|
|
|
+ questionCount: null,
|
|
|
+ optionCount: null,
|
|
|
+ fillCount: null,
|
|
|
+ questionProperty: [],
|
|
|
+ supplement: "",
|
|
|
+};
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "GptQuestionDialog",
|
|
|
+ components: { PropertyTreeSelect, GptQuestionEditDialog },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ taskId: null,
|
|
|
+ formModel: {
|
|
|
+ ...initFormModel,
|
|
|
+ },
|
|
|
+ searchFormModel: {},
|
|
|
+ BASE_QUESTION_TYPES,
|
|
|
+ modalIsShow: false,
|
|
|
+ loading: false,
|
|
|
+ questionList: [],
|
|
|
+ selectedQuestionIds: [],
|
|
|
+ propertyInfos: [],
|
|
|
+ currentPage: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0,
|
|
|
+ curQuestion: {},
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ IS_SELECTION_QUESTION() {
|
|
|
+ return ["SINGLE_ANSWER_QUESTION", "MULTIPLE_ANSWER_QUESTION"].includes(
|
|
|
+ this.formModel.questionType
|
|
|
+ );
|
|
|
+ },
|
|
|
+ IS_BOOLEAN_QUESTION() {
|
|
|
+ return this.formModel.questionType === "BOOL_ANSWER_QUESTION";
|
|
|
+ },
|
|
|
+ IS_FILL_QUESTION() {
|
|
|
+ return this.formModel.questionType === "FILL_BLANK_QUESTION";
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ dialogOpened() {},
|
|
|
+ async toProduct() {
|
|
|
+ this.loading = true;
|
|
|
+
|
|
|
+ const res = await buildGptQuestionApi({ ...this.formModel }).catch(
|
|
|
+ () => {}
|
|
|
+ );
|
|
|
+ this.loading = false;
|
|
|
+ if (!res) return;
|
|
|
+
|
|
|
+ this.searchFormModel = { ...this.formModel };
|
|
|
+ this.taskId = res.data;
|
|
|
+ this.toPage(1);
|
|
|
+ },
|
|
|
+ toPage(page) {
|
|
|
+ this.currentPage = page;
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+ async getList() {
|
|
|
+ // this.selectedQuestionIds = [];
|
|
|
+ // this.questionList = this.questions.slice(
|
|
|
+ // (this.currentPage - 1) * this.pageSize,
|
|
|
+ // this.currentPage * this.pageSize
|
|
|
+ // );
|
|
|
+ let data = {
|
|
|
+ taskId: this.taskId,
|
|
|
+ pageNumber: this.currentPage,
|
|
|
+ pageSize: this.pageSize,
|
|
|
+ };
|
|
|
+ const res = await gptQuestionListApi(data).catch(() => {});
|
|
|
+ this.loading = false;
|
|
|
+ if (!res) return;
|
|
|
+ this.questionList = res.data.content;
|
|
|
+ this.total = res.data.totalElements;
|
|
|
+ },
|
|
|
+ handleSizeChange(val) {
|
|
|
+ this.pageSize = val;
|
|
|
+ this.toPage(1);
|
|
|
+ },
|
|
|
+ tableSelectChange(selections) {
|
|
|
+ this.selectedQuestionIds = selections.map((item) => item.id);
|
|
|
+ },
|
|
|
+ switchQuestionType(questionType) {
|
|
|
+ this.questionModel.questionType = questionType;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.questionTypeChange();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ questionTypeChange() {
|
|
|
+ if (this.IS_FILL_QUESTION) {
|
|
|
+ this.questionModel.optionCount = null;
|
|
|
+ } else if (this.IS_SELECTION_QUESTION) {
|
|
|
+ this.questionModel.fillCount = null;
|
|
|
+ } else {
|
|
|
+ this.questionModel.optionCount = null;
|
|
|
+ this.questionModel.fillCount = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ propertyChange(propertyInfos) {
|
|
|
+ this.propertyInfos = propertyInfos;
|
|
|
+ },
|
|
|
+ toEditQuestion(row) {
|
|
|
+ this.curQuestion = row;
|
|
|
+ this.$refs.GptQuestionEditDialog.open();
|
|
|
+ },
|
|
|
+ async toDeleteQuestion(row) {
|
|
|
+ const confirm = await this.$confirm("确认删除选中试题吗?", "提示", {
|
|
|
+ type: "warning",
|
|
|
+ }).catch(() => {});
|
|
|
+ if (confirm !== "confirm") return;
|
|
|
+
|
|
|
+ this.deleteQuestion([row.id]);
|
|
|
+ },
|
|
|
+ async toBatchDeleteQuestion() {
|
|
|
+ if (!this.selectedQuestionIds.length) {
|
|
|
+ this.$message.error("请选择需要删除的试题!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const confirm = await this.$confirm("确认删除选中试题吗?", "提示", {
|
|
|
+ type: "warning",
|
|
|
+ }).catch(() => {});
|
|
|
+ if (confirm !== "confirm") return;
|
|
|
+
|
|
|
+ this.deleteQuestion(this.selectedQuestionIds);
|
|
|
+ },
|
|
|
+ async deleteQuestion(ids) {
|
|
|
+ // this.questions = this.questions.filter((q) => !ids.includes(q.id));
|
|
|
+ // this.total = this.questions.length;
|
|
|
+ // const maxPage = Math.ceil(this.total / this.pageSize);
|
|
|
+ // this.currentPage = Math.min(maxPage, this.currentPage);
|
|
|
+ // this.toPage(this.currentPage);
|
|
|
+
|
|
|
+ this.loading = true;
|
|
|
+ const res = await deleteGptQuestionApi(ids.join()).catch(() => {});
|
|
|
+ this.loading = false;
|
|
|
+ if (!res) return;
|
|
|
+
|
|
|
+ this.$notify({
|
|
|
+ message: "删除成功",
|
|
|
+ type: "success",
|
|
|
+ });
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+ async toSaveQuestion() {
|
|
|
+ if (this.loading) return;
|
|
|
+
|
|
|
+ if (!this.selectedQuestionIds.length) {
|
|
|
+ this.$message.error("请选择需要删除的试题!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const confirm = await this.$confirm("确认保存所选择的试题吗?", "提示", {
|
|
|
+ type: "warning",
|
|
|
+ }).catch(() => {});
|
|
|
+ if (confirm !== "confirm") {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.loading = true;
|
|
|
+ const datas = {
|
|
|
+ questions: this.selectedQuestionIds,
|
|
|
+ };
|
|
|
+ const res = await saveGptQuestionApi(datas).catch(() => {});
|
|
|
+ this.loading = false;
|
|
|
+ if (!res) return;
|
|
|
+ this.$message.success("保存成功!");
|
|
|
+ this.deleteQuestion(this.selectedQuestionIds);
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|