|
@@ -0,0 +1,478 @@
|
|
|
+<template>
|
|
|
+ <section class="content add-paper-select">
|
|
|
+ <div>
|
|
|
+ <LinkTitlesCustom
|
|
|
+ :current-paths="['题库管理 ', '卷库管理', '抽题模板管理']"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="box-body">
|
|
|
+ <div class="top">
|
|
|
+ <div class="flex items-center">
|
|
|
+ <p>课程名称:{{ $route.query.courseName }}</p>
|
|
|
+ <p style="margin-left: 100px">
|
|
|
+ 课程代码:{{ $route.query.courseNo }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" size="small" @click="save">保存</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="form">
|
|
|
+ <el-form
|
|
|
+ ref="form"
|
|
|
+ :rules="rules"
|
|
|
+ :model="form"
|
|
|
+ label-position="left"
|
|
|
+ label-width="120px"
|
|
|
+ >
|
|
|
+ <el-form-item label="组卷模板名称:" prop="name">
|
|
|
+ <el-input v-model="form.name" style="width: 300px"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="选择组卷模式:" required>
|
|
|
+ <el-radio-group
|
|
|
+ v-model="form.paperStructType"
|
|
|
+ @change="paperStructTypeChange"
|
|
|
+ >
|
|
|
+ <el-radio label="EXACT">精确结构</el-radio>
|
|
|
+ <el-radio label="BLUEPRINT">蓝图结构</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="选择组卷结构:" prop="paperStructId">
|
|
|
+ <el-select v-model="form.paperStructId">
|
|
|
+ <el-option
|
|
|
+ v-for="item in options1"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item.id"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
+ <p style="display: inline-block; margin-left: 40px">
|
|
|
+ 难度:<span style="color: #409eff; font-weight: bold">{{
|
|
|
+ curStruct?.difficulty
|
|
|
+ }}</span>
|
|
|
+ </p>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ v-loading="tableLoading1"
|
|
|
+ :data="tableData1"
|
|
|
+ border
|
|
|
+ style="margin-top: 10px; margin-bottom: 20px; width: 700px"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ v-for="(item, index) in tableColumns1"
|
|
|
+ :key="index"
|
|
|
+ :label="item.label"
|
|
|
+ :prop="item.prop"
|
|
|
+ :min-width="item.minWidth"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span
|
|
|
+ v-if="
|
|
|
+ !['hardInfo', 'mediumInfo', 'easyInfo'].includes(item.prop)
|
|
|
+ "
|
|
|
+ >{{ scope.row[item.prop] }}</span
|
|
|
+ >
|
|
|
+ <span v-else>{{ scope.row[item.prop]?.count }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div class="flex" style="margin-top: 30px">
|
|
|
+ <div style="width: 40%">
|
|
|
+ <el-form-item label="选择题源范围:" style="margin-bottom: 0">
|
|
|
+ <el-select
|
|
|
+ v-model="form.paperType"
|
|
|
+ placeholder="题源选择"
|
|
|
+ style="width: 120px"
|
|
|
+ @change="changePaperType"
|
|
|
+ >
|
|
|
+ <el-option label="题库来源" value="IMPORT"></el-option>
|
|
|
+ <el-option label="卷库来源" value="GENERATE"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <span
|
|
|
+ v-if="checked && !multipleSelection.length"
|
|
|
+ class="red"
|
|
|
+ style="font-size: 12px; font-weight: bold; margin-left: 10px"
|
|
|
+ >请选择数据</span
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ <el-table
|
|
|
+ ref="table2"
|
|
|
+ :data="tableData2"
|
|
|
+ border
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ type="selection"
|
|
|
+ width="55"
|
|
|
+ :selectable="canSelect"
|
|
|
+ >
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ v-for="(item, index) in tableColumns2"
|
|
|
+ :key="index"
|
|
|
+ :label="item.label"
|
|
|
+ :prop="item.prop"
|
|
|
+ :width="item.width"
|
|
|
+ >
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div style="width: 60%; padding-left: 20px">
|
|
|
+ <div style="color: #606266; font-size: 14px; line-height: 32px">
|
|
|
+ <span>选中范围预览:</span>
|
|
|
+ <span
|
|
|
+ v-if="hasError()"
|
|
|
+ class="red"
|
|
|
+ style="font-size: 12px; font-weight: bold"
|
|
|
+ >不满足最低要求</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <el-table
|
|
|
+ v-loading="tableLoading3"
|
|
|
+ :data="tableData3"
|
|
|
+ border
|
|
|
+ style="margin-top: 8px"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ v-for="(item, index) in tableColumns3"
|
|
|
+ :key="index"
|
|
|
+ :label="item.label"
|
|
|
+ :prop="item.prop"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span
|
|
|
+ v-if="
|
|
|
+ !['hardInfo', 'mediumInfo', 'easyInfo'].includes(
|
|
|
+ item.prop
|
|
|
+ )
|
|
|
+ "
|
|
|
+ :class="{ red: hasNumError(scope.row, item.prop) }"
|
|
|
+ >{{ scope.row[item.prop] }}</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ v-else
|
|
|
+ :class="{ red: hasNumError(scope.row, item.prop) }"
|
|
|
+ >{{ scope.row[item.prop]?.count }}</span
|
|
|
+ >
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import qs from "qs";
|
|
|
+import { mapState } from "vuex";
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ form: {
|
|
|
+ paperStructType: "BLUEPRINT",
|
|
|
+ name: "",
|
|
|
+ paperStructId: "",
|
|
|
+ paperType: "IMPORT",
|
|
|
+ paperIds: "",
|
|
|
+ },
|
|
|
+ paperIdsArr: [],
|
|
|
+ options1: [],
|
|
|
+ tableData1: [],
|
|
|
+ tableColumns1: [
|
|
|
+ { label: "题型", prop: "detailName", minWidth: "100" },
|
|
|
+ { label: "总分", prop: "totalScore", minWidth: "80" },
|
|
|
+ { label: "数量", prop: "totalCount", minWidth: "80" },
|
|
|
+ { label: "难", prop: "hardInfo", minWidth: "80" },
|
|
|
+ { label: "中", prop: "mediumInfo", minWidth: "80" },
|
|
|
+ { label: "易", prop: "easyInfo", minWidth: "80" },
|
|
|
+ ],
|
|
|
+ tableData2: [],
|
|
|
+ tableColumns2: [
|
|
|
+ { label: "名称", prop: "name" },
|
|
|
+ { label: "小题数量", prop: "unitCount", width: "100px" },
|
|
|
+ ],
|
|
|
+ multipleSelection: [],
|
|
|
+ tableData3: [],
|
|
|
+ tableColumns3: [
|
|
|
+ { label: "题型", prop: "detailName", minWidth: "100" },
|
|
|
+ { label: "数量", prop: "totalCount", minWidth: "80" },
|
|
|
+ { label: "难", prop: "hardInfo", minWidth: "80" },
|
|
|
+ { label: "中", prop: "mediumInfo", minWidth: "80" },
|
|
|
+ { label: "易", prop: "easyInfo", minWidth: "80" },
|
|
|
+ ],
|
|
|
+ lastRequestKey: "",
|
|
|
+ tableLoading3: false,
|
|
|
+ tableLoading1: false,
|
|
|
+ checked: false,
|
|
|
+ initSelectedRows: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState({ user: (state) => state.user }),
|
|
|
+ curStruct() {
|
|
|
+ if (this.form.paperStructId) {
|
|
|
+ return this.options1.find(
|
|
|
+ (item) => item.id === this.form.paperStructId
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ },
|
|
|
+ rules() {
|
|
|
+ return {
|
|
|
+ name: { required: true, message: "请输入模板名称", trigger: "change" },
|
|
|
+ paperStructId: {
|
|
|
+ required: true,
|
|
|
+ message: "请选择组卷结构",
|
|
|
+ trigger: "change",
|
|
|
+ },
|
|
|
+ };
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ "form.paperStructId"() {
|
|
|
+ this.structChange();
|
|
|
+ },
|
|
|
+ // "form.paperStructType"() {
|
|
|
+ // this.form.paperStructId = "";
|
|
|
+ // this.getStruct();
|
|
|
+ // this.tableData1 = [];
|
|
|
+ // this.$refs.table2.clearSelection();
|
|
|
+ // },
|
|
|
+ multipleSelection(val) {
|
|
|
+ this.form.paperIds = val.map((item) => item.id).join(",");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ async created() {
|
|
|
+ let res = await this.getTplData();
|
|
|
+ if (res) {
|
|
|
+ this.getStruct();
|
|
|
+ this.getTable2(true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ paperStructTypeChange() {
|
|
|
+ alert("paperStructTypeChange");
|
|
|
+ this.form.paperStructId = "";
|
|
|
+ this.getStruct();
|
|
|
+ this.tableData1 = [];
|
|
|
+ this.$refs.table2.clearSelection();
|
|
|
+ },
|
|
|
+ async getTplData() {
|
|
|
+ const { id } = this.$route.params;
|
|
|
+ if (id) {
|
|
|
+ try {
|
|
|
+ const data = await this.$http.post(
|
|
|
+ "/api/ecs_ques/randompaper/info",
|
|
|
+ null,
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ id,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const tplData = data.data;
|
|
|
+ this.paperIdsArr = tplData.paperIds || [];
|
|
|
+ Object.assign(this.form, tplData || {}, {
|
|
|
+ paperIds: (tplData.paperIds || []).join(","),
|
|
|
+ });
|
|
|
+ return true;
|
|
|
+ } catch (e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ save() {
|
|
|
+ this.checked = true;
|
|
|
+ this.$refs.form.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ if (this.multipleSelection.length && !this.hasError()) {
|
|
|
+ let params = {
|
|
|
+ courseId: this.$route.query.courseId,
|
|
|
+ ...this.form,
|
|
|
+ rootOrgId: this.user.rootOrgId,
|
|
|
+ };
|
|
|
+ if (this.$route.params.id) {
|
|
|
+ params.id = this.$route.params.id;
|
|
|
+ }
|
|
|
+ this.$http
|
|
|
+ .post("/api/ecs_ques/randompaper/save", qs.stringify(params))
|
|
|
+ .then(() => {
|
|
|
+ this.$message.success("保存成功");
|
|
|
+ this.$router.back();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log("error submit!!");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ canSelect() {
|
|
|
+ return !!this.form.paperStructId;
|
|
|
+ },
|
|
|
+ structChange() {
|
|
|
+ this.tableLoading1 = true;
|
|
|
+ this.$http
|
|
|
+ .post("/api/ecs_ques/randompaper/struct/question/info", null, {
|
|
|
+ params: { structId: this.form.paperStructId },
|
|
|
+ headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ this.tableData1 = res.data.structQuestionInfo || [];
|
|
|
+ this.tableLoading1 = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getStruct() {
|
|
|
+ let apiUrl = "/api/ecs_ques/paperStruct/1/10000";
|
|
|
+ let params =
|
|
|
+ this.form.paperStructType == "EXACT"
|
|
|
+ ? { courseNo: "ALL", type: "EXACT" }
|
|
|
+ : { type: "BLUEPRINT" };
|
|
|
+ this.$http.get(apiUrl, { params }).then((res) => {
|
|
|
+ this.options1 = res.data.content;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getTable2(bool) {
|
|
|
+ let apiUrl =
|
|
|
+ this.form.paperType === "IMPORT"
|
|
|
+ ? "/api/ecs_ques/importPaper/huoge/1/10000"
|
|
|
+ : "/api/ecs_ques/genPaper/huoge/1/10000";
|
|
|
+ this.$http
|
|
|
+ .get(apiUrl, {
|
|
|
+ params: { courseNo: this.$route.query.courseNo, ids: "" },
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ this.tableData2 = res.data.content || [];
|
|
|
+ if (bool) {
|
|
|
+ this.tableData2.forEach((item) => {
|
|
|
+ if (this.paperIdsArr.includes(item.id)) {
|
|
|
+ this.initSelectedRows.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ setTimeout(() => {
|
|
|
+ this.initSelectedRows.forEach((item) => {
|
|
|
+ this.$refs.table2.toggleRowSelection(item, true);
|
|
|
+ });
|
|
|
+ }, 0);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ changePaperType() {
|
|
|
+ this.tableData2 = [];
|
|
|
+ this.multipleSelection = [];
|
|
|
+ this.getTable2();
|
|
|
+ },
|
|
|
+ getTable3() {
|
|
|
+ let paperIds = this.multipleSelection.map((item) => item.id);
|
|
|
+ if (!paperIds.length) {
|
|
|
+ this.tableData3 = [];
|
|
|
+ this.tableLoading3 = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ this.tableLoading3 = true;
|
|
|
+ let str = new Date().getTime() + "";
|
|
|
+ this.lastRequestKey = str;
|
|
|
+ this.$http
|
|
|
+ .post(
|
|
|
+ "/api/ecs_ques/randompaper/struct/question/view/info",
|
|
|
+ qs.stringify({
|
|
|
+ paperIds: paperIds.join(","),
|
|
|
+ structId: this.form.paperStructId,
|
|
|
+ }),
|
|
|
+ {
|
|
|
+ headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
|
+ }
|
|
|
+ )
|
|
|
+ .then((res) => {
|
|
|
+ if (this.lastRequestKey === str) {
|
|
|
+ this.tableData3 = res.data.structQuestionInfo || [];
|
|
|
+ this.tableLoading3 = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleSelectionChange(val) {
|
|
|
+ this.multipleSelection = val;
|
|
|
+ this.getTable3();
|
|
|
+ },
|
|
|
+ hasNumError(row, prop) {
|
|
|
+ if (prop === "detailName") {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ let targetName = row.detailName;
|
|
|
+ let find = this.tableData1.find(
|
|
|
+ (item) => item.detailName === targetName
|
|
|
+ );
|
|
|
+ if (!find) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if (prop === "totalCount") {
|
|
|
+ return row[prop] < find[prop];
|
|
|
+ } else {
|
|
|
+ return row[prop].count < find[prop].count;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ hasError() {
|
|
|
+ return (
|
|
|
+ this.tableData1.length &&
|
|
|
+ this.tableData3.length &&
|
|
|
+ this.tableData3.every((item) => {
|
|
|
+ return (
|
|
|
+ this.hasNumError(item, "totalCount") ||
|
|
|
+ this.hasNumError(item, "hardInfo") ||
|
|
|
+ this.hasNumError(item, "mediumInfo") ||
|
|
|
+ this.hasNumError(item, "easyInfo")
|
|
|
+ );
|
|
|
+ })
|
|
|
+ );
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.add-paper-select {
|
|
|
+ * {
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form .el-form-item {
|
|
|
+ margin-bottom: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .red {
|
|
|
+ color: #f56c6c;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .top {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding-bottom: 15px;
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .box-body {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 15px 10px;
|
|
|
+
|
|
|
+ .form {
|
|
|
+ margin-top: 15px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|