123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- <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"
- @close="dialogClose"
- >
- <div slot="title">
- <h2>
- AI命题 --<span
- >{{ formModel.courseName }}({{ formModel.courseCode }})</span
- >
- </h2>
- </div>
- <div class="part-box">
- <h2 class="part-box-title">生成试题</h2>
- <el-form class="margin-top-20" :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 class="inline-top" label="出题数量">
- <el-input-number
- v-model="formModel.questionCount"
- placeholder="出题数量"
- style="width: 150px"
- :min="1"
- :max="10"
- :step="1"
- step-strictly
- :controls="false"
- ></el-input-number>
- </el-form-item>
- <el-form-item
- v-if="IS_SELECTION_QUESTION"
- class="inline-top"
- label="选项个数"
- >
- <el-input-number
- v-model="formModel.optionCount"
- placeholder="选项个数"
- style="width: 150px"
- :min="1"
- :max="10"
- :step="1"
- step-strictly
- :controls="false"
- ></el-input-number>
- </el-form-item>
- <el-form-item
- v-if="IS_FILL_QUESTION"
- class="inline-top"
- label="填空个数"
- >
- <el-input-number
- v-model="formModel.blankCount"
- placeholder="填空个数"
- style="width: 150px"
- :min="1"
- :max="5"
- :step="1"
- step-strictly
- :controls="false"
- ></el-input-number>
- </el-form-item>
- <el-form-item label="知识点">
- <property-tree-select
- ref="PropertyTreeSelect"
- class="width-full"
- v-model="formModel.propertyIdList"
- :course-id="formModel.courseId"
- ></property-tree-select>
- <br />
- <el-input
- class="padding-top-6"
- v-model="formModel.knowledgeNotes"
- placeholder="请录入知识点补充说明"
- type="textarea"
- maxlength="30"
- clearable
- ></el-input>
- </el-form-item>
- <el-form-item style="margin: 0">
- <el-button
- type="primary"
- :loading="hasTaskRunning || loading"
- @click="toProduct"
- >生成试题</el-button
- >
- </el-form-item>
- </el-form>
- </div>
- <div class="part-box">
- <!-- <div class="part-box-header">
- <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> -->
- <div class="icon-btn-group">
- <svg-btn name="jiarutiku" :disabled="loading" @click="toSaveQuestion"
- >加入题库</svg-btn
- >
- <svg-btn
- name="shanchu"
- :disabled="loading"
- @click="toBatchDeleteQuestion"
- >删除</svg-btn
- >
- </div>
- <el-table
- v-loading="loading"
- ref="table"
- 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="题型" prop="questionType" width="100">
- <span slot-scope="scope">
- {{ scope.row.questionType | questionTypeFilter }}
- </span>
- </el-table-column>
- <el-table-column label="生成时间" prop="creationTime" width="170">
- </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="handleCurrentChange"
- @size-change="handleSizeChange"
- >
- </el-pagination>
- </div>
- </div>
- </el-dialog>
- <!-- GptQuestionEditDialog -->
- <gpt-question-edit-dialog
- ref="GptQuestionEditDialog"
- :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,
- gptTaskDetailApi,
- } from "../api";
- import timeMixin from "@/mixins/timeMixin";
- import SvgBtn from "@/components/SvgBtn.vue";
- const initFormModel = {
- courseId: null,
- courseCode: "",
- courseName: "",
- questionType: "SINGLE_ANSWER_QUESTION",
- questionCount: 1,
- optionCount: 4,
- blankCount: 1,
- propertyIdList: [],
- knowledgeNotes: "",
- };
- export default {
- name: "GptQuestionDialog",
- components: { PropertyTreeSelect, GptQuestionEditDialog, SvgBtn },
- mixins: [timeMixin],
- props: {
- course: {
- type: Object,
- default() {
- return {};
- },
- },
- },
- data() {
- return {
- curTaskId: null,
- hasTaskRunning: false,
- 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_FILL_QUESTION() {
- return this.formModel.questionType === "FILL_BLANK_QUESTION";
- },
- },
- beforeDestroy() {
- this.clearSetTs();
- },
- methods: {
- dialogOpened() {
- this.formModel = this.$objAssign(initFormModel, this.course);
- this.checkTaskStatus(true);
- },
- dialogClose() {
- this.resetData();
- this.clearSetTs();
- },
- resetData() {
- this.questionList = [];
- this.selectedQuestionIds = [];
- this.propertyInfos = [];
- this.curQuestion = {};
- this.searchFormModel = {};
- this.formModel = { ...initFormModel };
- },
- cancel() {
- this.modalIsShow = false;
- },
- open() {
- this.modalIsShow = true;
- },
- async checkTaskStatus(isReview) {
- this.clearSetTs();
- const res = await gptTaskDetailApi({
- courseId: this.course.courseId,
- taskId: this.curTaskId,
- }).catch(() => {});
- if (!res || !res.data) return;
- this.curTaskId = res.data.id;
- if (res.data.status === "FAILED") {
- this.hasTaskRunning = false;
- if (!isReview) this.$message.error("出题失败,请重新尝试!");
- this.handleCurrentChange(1);
- return;
- }
- if (res.data.status === "FINISH") {
- this.hasTaskRunning = false;
- if (!isReview) this.$message.success("出题成功!");
- this.handleCurrentChange(1);
- return;
- }
- this.hasTaskRunning = ["RUNNING", "INIT"].includes(res.data.status);
- this.addSetTime(() => {
- this.checkTaskStatus();
- }, 3 * 1000);
- },
- async toProduct() {
- this.loading = true;
- const res = await buildGptQuestionApi({ ...this.formModel }).catch(
- () => {}
- );
- this.loading = false;
- if (!res) return;
- this.curTaskId = res.data;
- this.searchFormModel = { ...this.formModel };
- this.hasTaskRunning = true;
- this.addSetTime(() => {
- this.checkTaskStatus();
- }, 3 * 1000);
- },
- handleCurrentChange(page) {
- this.currentPage = page;
- this.getList();
- },
- async getList() {
- this.selectedQuestionIds = [];
- let data = {
- courseId: this.course.courseId,
- curPage: 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.handleCurrentChange(1);
- },
- tableSelectChange(selections) {
- this.selectedQuestionIds = selections.map((item) => item.id);
- },
- switchQuestionType(questionType) {
- this.formModel.questionType = questionType;
- this.$nextTick(() => {
- this.questionTypeChange();
- });
- },
- questionTypeChange() {
- if (this.IS_FILL_QUESTION) {
- this.formModel.optionCount = null;
- } else if (this.IS_SELECTION_QUESTION) {
- this.formModel.blankCount = null;
- } else {
- this.formModel.optionCount = null;
- this.formModel.blankCount = null;
- }
- },
- toEditQuestion(row) {
- const propertyInfos =
- !row.propertyIds || !row.propertyIds.length
- ? []
- : this.$refs.PropertyTreeSelect.getCheckedPropertyInfos(
- row.propertyIds
- );
- this.curQuestion = { ...row, ...this.course, propertyInfos };
- 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.loading = true;
- const res = await deleteGptQuestionApi(ids.join()).catch(() => {});
- this.loading = false;
- if (!res) return;
- this.$notify({
- message: "删除成功",
- type: "success",
- });
- this.deletePageLastItem(ids.length);
- },
- 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;
- }
- if (this.loading) return;
- this.loading = true;
- const res = await saveGptQuestionApi(
- this.selectedQuestionIds.join()
- ).catch(() => {});
- this.loading = false;
- if (!res) return;
- this.$message.success("保存成功!");
- this.deletePageLastItem(this.selectedQuestionIds.length);
- this.$emit("modified");
- },
- },
- };
- </script>
|