Jelajahi Sumber

pdf生成管理

zhangjie 1 tahun lalu
induk
melakukan
862fcbbfe4

+ 10 - 0
src/assets/styles/base.scss

@@ -414,6 +414,16 @@ body {
     }
   }
 }
+.btn-icon {
+  &.el-button--text {
+    font-size: 20px !important;
+    padding: 5px 0;
+
+    > i {
+      display: inline;
+    }
+  }
+}
 
 .btn-white {
   background-color: #fff !important;

+ 0 - 1
src/components/SecpSelect.vue

@@ -25,7 +25,6 @@
         clearable
         :semester-id="filter.semesterId"
         :exam-id="filter.examId"
-        @change="printPlanChange"
       ></print-plan-select>
     </el-form-item>
     <el-form-item

+ 73 - 0
src/constants/menus-data.js

@@ -5611,4 +5611,77 @@ export default [
       },
     ],
   },
+  {
+    id: "78201",
+    name: "PDF生成管理",
+    url: "PdfBuildManage",
+    type: "MENU",
+    parentId: "112",
+    sequence: 6,
+    enable: true,
+    urls: [
+      {
+        id: "783",
+        name: "查询",
+        url: "/api/admin/basic/operation_log/query",
+        type: "URL",
+        parentId: "782",
+        sequence: 1,
+        enable: true,
+      },
+    ],
+    buttons: [
+      {
+        id: "785",
+        name: "查询",
+        url: "Select",
+        type: "BUTTON",
+        parentId: "782",
+        sequence: 2,
+        enable: true,
+      },
+    ],
+    lists: [
+      {
+        id: "803",
+        name: "列表",
+        url: "List",
+        type: "LIST",
+        parentId: "782",
+        sequence: 3,
+        enable: true,
+      },
+    ],
+    conditions: [
+      {
+        id: "784",
+        name: "查询条件",
+        url: "Condition",
+        type: "CONDITION",
+        parentId: "782",
+        sequence: 1,
+        enable: true,
+      },
+    ],
+    links: [
+      {
+        id: "338",
+        name: "导出日志",
+        url: "Export",
+        type: "LINK",
+        parentId: "113",
+        sequence: 1,
+        enable: true,
+      },
+      {
+        id: "413",
+        name: "重新生成pdf",
+        url: "CreatePdf",
+        type: "LINK",
+        parentId: "113",
+        sequence: 3,
+        enable: true,
+      },
+    ],
+  },
 ];

+ 9 - 0
src/modules/exam/api.js

@@ -170,6 +170,10 @@ export const uploadOrFindExamTaskStudent = (datas) => {
     datas
   );
 };
+// 从题库选择试卷 创建命题任务
+export const tikuPaperListQuery = (datas) => {
+  return $postParam("/api/admin/tiku/task/switch_card", datas);
+};
 
 // task-review-manage
 export const taskReviewUnauditedListPage = (datas) => {
@@ -294,3 +298,8 @@ export const savePreviewLog = (datas) => {
   // examTaskId,paperType,type
   return $postParam("/api/admin/basic/operation_log/save_preview_log", datas);
 };
+
+// pdf-build-manage
+export const pdfBuildListPage = (datas) => {
+  return $postParam("/api/admin/data/task/page_pdf_create", datas);
+};

+ 112 - 27
src/modules/exam/components/createExamAndPrintTask/InfoExamTask.vue

@@ -84,20 +84,22 @@
 
     <div class="apply-content task-detail">
       <div class="task-body">
-        <div class="mb-2 text-right">
+        <div class="mb-4 tab-btns">
           <el-button
-            type="info"
-            icon="el-icon-circle-plus-outline"
-            @click="addAtachment"
-            >增加卷型</el-button
-          >
+            v-for="tab in tabs"
+            :key="tab.val"
+            size="medium"
+            :type="curTab == tab.val ? 'primary' : 'default'"
+            @click="selectMenu(tab.val)"
+            >{{ tab.name }}
+          </el-button>
         </div>
         <table class="table mb-2">
           <colgroup>
             <col width="100" />
             <col width="280" />
             <col />
-            <col width="60" />
+            <col width="90" />
           </colgroup>
           <tr>
             <th>试卷类型</th>
@@ -107,7 +109,25 @@
           </tr>
           <tr v-for="(attachment, index) in paperAttachments" :key="index">
             <td>{{ attachment.name }}卷</td>
-            <td>
+
+            <td v-if="IS_TIKU_TAB">
+              <el-button
+                type="text"
+                class="btn-primary"
+                @click="toSelect(attachment)"
+              >
+                <i
+                  :class="[
+                    'icon',
+                    attachment.attachmentId ? 'icon-files-act' : 'icon-files',
+                  ]"
+                ></i
+                >{{
+                  attachment.attachmentId ? attachment.filename : "选择试卷"
+                }}
+              </el-button>
+            </td>
+            <td v-else>
               <el-button
                 type="text"
                 class="btn-primary"
@@ -126,7 +146,21 @@
                 }}
               </el-button>
             </td>
-            <td>
+            <td v-if="IS_TIKU_TAB">
+              <el-select
+                v-model="attachment.cardId"
+                placeholder="请选择"
+                style="width: 260px"
+              >
+                <el-option
+                  v-if="attachment.cardId"
+                  :value="attachment.cardId"
+                  :label="attachment.cardTitle"
+                >
+                </el-option>
+              </el-select>
+            </td>
+            <td v-else>
               <el-select
                 class="mr-2"
                 v-model="attachment.cardId"
@@ -160,19 +194,21 @@
                   {{ item.title }}
                 </el-option>
               </el-select>
-              <span
-                v-if="attachment.cardId"
-                :class="[
-                  attachment.cardType === 'GENERIC'
-                    ? 'color-success'
-                    : 'color-primary',
-                  'mr-1',
-                  {
-                    'color-danger': attachment.used,
-                  },
-                ]"
-                >[{{ attachment.cardType === "GENERIC" ? "通" : "专" }}]</span
-              >
+              <template v-if="!IS_TIKU_TAB">
+                <span
+                  v-if="attachment.cardId"
+                  :class="[
+                    attachment.cardType === 'GENERIC'
+                      ? 'color-success'
+                      : 'color-primary',
+                    'mr-1',
+                    {
+                      'color-danger': attachment.used,
+                    },
+                  ]"
+                  >[{{ attachment.cardType === "GENERIC" ? "通" : "专" }}]</span
+                >
+              </template>
               <el-button
                 class="btn-primary"
                 type="text"
@@ -181,6 +217,7 @@
                 >预览</el-button
               >
               <el-button
+                v-if="!IS_TIKU_TAB"
                 class="btn-primary"
                 type="text"
                 :disabled="
@@ -195,6 +232,7 @@
                 class="btn-primary"
                 type="text"
                 :disabled="
+                  IS_TIKU_TAB ||
                   !attachment.cardId ||
                   attachment.cardType === 'GENERIC' ||
                   !(!attachment.used && attachment.createId === user.id)
@@ -203,6 +241,7 @@
                 >编辑</el-button
               >
               <el-button
+                v-if="!IS_TIKU_TAB"
                 class="btn-primary"
                 type="text"
                 :disabled="!canCreateCard"
@@ -210,13 +249,20 @@
                 >新建</el-button
               >
             </td>
-            <td>
+            <td class="text-right">
+              <el-button
+                v-if="index === paperAttachments.length - 1"
+                class="btn-primary btn-icon"
+                type="text"
+                icon="el-icon-circle-plus"
+                @click="addAtachment"
+              ></el-button>
               <el-button
-                class="btn-danger"
+                class="btn-danger btn-icon"
                 type="text"
+                icon="el-icon-remove"
                 @click="deleteAttachment(index)"
-                >删除</el-button
-              >
+              ></el-button>
             </td>
           </tr>
           <tr v-if="!paperAttachments.length">
@@ -300,6 +346,12 @@
     ></simple-image-preview>
     <!-- ModifyCard -->
     <modify-card ref="ModifyCard" @modified="cardModified"></modify-card>
+    <!-- SelectTikuPaperDialog -->
+    <select-tiku-paper-dialog
+      ref="SelectTikuPaperDialog"
+      :row="curAttachment"
+      @confirm="tikuPaperSelected"
+    ></select-tiku-paper-dialog>
   </div>
 </template>
 
@@ -307,6 +359,7 @@
 import UploadPaperDialog from "../UploadPaperDialog";
 import SimpleImagePreview from "@/components/SimpleImagePreview";
 import ModifyCard from "../../../card/components/ModifyCard";
+import SelectTikuPaperDialog from "./SelectTikuPaperDialog.vue";
 import { COMMON_CARD_RULE_ID } from "../../../../constants/enumerate";
 import { cardForSelectList } from "../../api";
 import { courseQuery, examConfigByExamIdOrgId } from "../../../base/api";
@@ -317,9 +370,25 @@ import { copyCard } from "../../../card/api";
 // type=CUSTOM时,可复制,不可编辑,如果是当前自己任务的题卡,才可编辑。
 export default {
   name: "info-exam-task",
-  components: { UploadPaperDialog, SimpleImagePreview, ModifyCard },
+  components: {
+    UploadPaperDialog,
+    SimpleImagePreview,
+    ModifyCard,
+    SelectTikuPaperDialog,
+  },
   data() {
     return {
+      tabs: [
+        {
+          name: "上传本地试卷",
+          val: "upload",
+        },
+        {
+          name: "从题库选择试卷",
+          val: "tiku",
+        },
+      ],
+      curTab: "upload",
       user: {},
       task: {},
       rules: {
@@ -404,6 +473,9 @@ export default {
         this.examTask.cardRuleId !== COMMON_CARD_RULE_ID
       );
     },
+    IS_TIKU_TAB() {
+      return this.curTab === "tiku";
+    },
   },
   watch: {
     "examTask.examId": function (val, oldval) {
@@ -444,6 +516,9 @@ export default {
         this.$refs.examTaskComp.clearValidate();
       });
     },
+    selectMenu(tab) {
+      this.curTab = tab;
+    },
     async getCardList() {
       if (!this.examTask.courseCode || !this.examTask.examId) return;
       const data = await cardForSelectList({
@@ -688,6 +763,16 @@ export default {
     emitRelateInfo(type) {
       this.$emit("relate-info-change", this.getData(), type);
     },
+    toSelect(attachment) {
+      this.curAttachment = attachment;
+      this.$refs.SelectTikuPaperDialog.open();
+    },
+    tikuPaperSelected(data) {
+      // TODO:
+      Object.assign(this.curAttachment, {
+        paperId: data.id,
+      });
+    },
     // exam-task-detail edit
     addAtachment() {
       if (this.paperAttachments.length >= this.attachmentLimitCount) return;

+ 106 - 0
src/modules/exam/components/createExamAndPrintTask/SelectTikuPaperDialog.vue

@@ -0,0 +1,106 @@
+<template>
+  <el-dialog
+    class="select-tiku-paper-dialog page-dialog"
+    :visible.sync="modalIsShow"
+    title="试卷选择"
+    top="10vh"
+    width="900px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    destroy-on-close
+  >
+    <div class="part-box part-box-pad">
+      <el-form ref="FilterForm" label-position="left" label-width="85px" inline>
+        <el-form-item label="试卷名称:">
+          <el-input
+            v-model="filter.paperName"
+            placeholder="请输入试卷名称"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label-width="0px">
+          <el-checkbox v-model="filter.youSelf">仅显示本人试卷</el-checkbox>
+        </el-form-item>
+        <el-form-item label-width="0px">
+          <el-button type="primary" @click="getList">查询</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <div class="part-box part-box-pad">
+      <el-table ref="TableList" :data="dataList">
+        <el-table-column type="index" label="序号"></el-table-column>
+        <el-table-column prop="paperName" label="试卷名称"></el-table-column>
+        <el-table-column prop="examPrintPlanName" label="命题人">
+        </el-table-column>
+        <el-table-column prop="createTime" label="创建时间" width="170">
+          <span slot-scope="scope">{{
+            scope.row.createTime | timestampFilter
+          }}</span>
+        </el-table-column>
+        <el-table-column class-name="action-column" label="操作" width="100">
+          <template slot-scope="scope">
+            <el-button
+              :class="
+                scope.row.id === row.paperId ? 'btn-act-primary' : 'btn-primary'
+              "
+              type="text"
+              @click="toSelect(scope.row)"
+              >选择</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div slot="footer">
+      <el-button @click="cancel">关闭</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { tikuPaperListQuery } from "../../api";
+
+export default {
+  name: "select-tiku-paper-dialog",
+  props: {
+    row: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      filter: {
+        paperName: "",
+        youSelf: true,
+      },
+      dataList: [],
+      loading: false,
+    };
+  },
+  methods: {
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async getList() {
+      const res = await tikuPaperListQuery({
+        courseCode: this.row.courseCode,
+        ...this.filter,
+      });
+      this.dataList = res || [];
+    },
+    toSelect(row) {
+      this.$emit("confirm", row);
+      this.cancel();
+    },
+  },
+};
+</script>

+ 6 - 0
src/modules/exam/router.js

@@ -9,6 +9,7 @@ import DataTaskManage from "./views/DataTaskManage.vue";
 import StatisticsManage from "./views/StatisticsManage.vue";
 import DownloadManage from "./views/DownloadManage.vue";
 import ActionLogManage from "./views/ActionLogManage.vue";
+import PdfBuildManage from "./views/PdfBuildManage.vue";
 
 export default [
   {
@@ -61,4 +62,9 @@ export default [
     name: "ActionLogManage",
     component: ActionLogManage,
   },
+  {
+    path: "/exam/pdf-build-manage",
+    name: "PdfBuildManage",
+    component: PdfBuildManage,
+  },
 ];

+ 260 - 0
src/modules/exam/views/PdfBuildManage.vue

@@ -0,0 +1,260 @@
+<template>
+  <div class="data-task-manage">
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form ref="FilterForm" label-position="left" label-width="55px" inline>
+        <template v-if="checkPrivilege('condition', 'condition')">
+          <secp-select
+            v-model="filter"
+            defaultSelectExam
+            @exam-default="toPage(1)"
+          ></secp-select>
+          <el-form-item label="状态:">
+            <el-select
+              v-model="filter.status"
+              placeholder="状态"
+              clearable
+              style="width: 120px"
+            >
+              <el-option
+                v-for="(val, key) in DATA_TASK_STATUS"
+                :key="key"
+                :value="key"
+                :label="val"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="数据结果:" label-width="85px">
+            <el-select
+              v-model="filter.result"
+              placeholder="数据结果"
+              clearable
+              style="width: 120px"
+            >
+              <el-option
+                v-for="(val, key) in DATA_TASK_RESULT"
+                :key="key"
+                :value="key"
+                :label="val"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="考点:">
+            <el-input
+              v-model.trim="filter.examPlace"
+              placeholder="考点"
+              clearable
+            >
+            </el-input>
+          </el-form-item>
+          <el-form-item label="考场:">
+            <el-input
+              v-model.trim="filter.examPlace"
+              placeholder="考场"
+              clearable
+            >
+            </el-input>
+          </el-form-item>
+          <el-form-item label="考试时间:">
+            <el-date-picker
+              v-model="createTime"
+              type="datetimerange"
+              :picker-options="pickerOptions"
+              range-separator="至"
+              start-placeholder="考试开始时间"
+              end-placeholder="考试结束时间"
+              value-format="timestamp"
+              align="right"
+              unlink-panels
+            >
+            </el-date-picker>
+          </el-form-item>
+        </template>
+        <el-form-item>
+          <el-button
+            v-if="checkPrivilege('button', 'select')"
+            type="primary"
+            @click="toPage(1)"
+            >查询</el-button
+          >
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="part-box part-box-pad">
+      <el-table ref="TableList" :data="dataList">
+        <el-table-column
+          type="index"
+          label="序号"
+          width="50"
+          :index="indexMethod"
+        ></el-table-column>
+        <el-table-column
+          prop="paperNumber"
+          label="试卷编号"
+          min-width="100"
+        ></el-table-column>
+        <el-table-column
+          prop="courseNameCode"
+          label="课程(代码)"
+          min-width="200"
+        >
+        </el-table-column>
+        <el-table-column
+          prop="printPlanName"
+          label="项目"
+          min-width="120"
+        ></el-table-column>
+        <el-table-column prop="createTypeDisplay" label="类别" width="160">
+        </el-table-column>
+        <el-table-column prop="examPlace" label="考点" width="160">
+        </el-table-column>
+        <el-table-column prop="examRoom" label="考场" width="160">
+        </el-table-column>
+        <el-table-column prop="statusDisplay" label="状态" width="100">
+        </el-table-column>
+        <el-table-column prop="resultDisplay" label="结果" width="100">
+        </el-table-column>
+        <el-table-column prop="examStartTime" label="考试开始时间" width="170">
+          <span slot-scope="scope">{{
+            scope.row.examStartTime | timestampFilter
+          }}</span>
+        </el-table-column>
+        <el-table-column prop="examEndTime" label="考试结束时间" width="170">
+          <span slot-scope="scope">{{
+            scope.row.examEndTime | timestampFilter
+          }}</span>
+        </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="160px"
+          fixed="right"
+        >
+          <template slot-scope="scope">
+            <el-button
+              v-if="checkPrivilege('link', 'export')"
+              class="btn-primary"
+              type="text"
+              @click="toViewLog(scope.row)"
+              >查看日志</el-button
+            >
+            <el-button
+              v-if="checkPrivilege('link', 'createPdf')"
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toResetCreatePdf(scope.row)"
+              >重新生成PDF</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total, sizes, prev, pager, next, jumper"
+          :pager-count="5"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+          @size-change="pageSizeChange"
+        >
+        </el-pagination>
+      </div>
+    </div>
+
+    <el-dialog
+      class="log-dialog"
+      :visible.sync="modalIsShow"
+      title="日志"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      top="10vh"
+      width="800px"
+    >
+      <div style="min-height: 300px; overflow: auto">
+        <p v-for="(cont, cidx) in logList" :key="cidx">{{ cont }}</p>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { DATA_TASK_STATUS, DATA_TASK_RESULT } from "@/constants/enumerate";
+import { pdfBuildListPage, taskResetPdf } from "../api";
+import pickerOptions from "@/constants/datePickerOptions";
+
+export default {
+  name: "pdf-build-manage",
+  data() {
+    return {
+      filter: {
+        semesterId: "",
+        examId: "",
+        printPlanId: "",
+        courseCode: "",
+        paperNumber: "",
+        status: "",
+        result: "",
+        examPlace: "",
+        examRoom: "",
+        examStartTime: "",
+        examEndTime: "",
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      dataList: [],
+      curRow: {},
+      loading: false,
+      DATA_TASK_STATUS,
+      DATA_TASK_RESULT,
+      // date-picker
+      createTime: [],
+      pickerOptions,
+      // log dialog
+      modalIsShow: false,
+      logList: [],
+    };
+  },
+  mounted() {},
+  methods: {
+    async getList() {
+      if (!this.checkPrivilege("list", "list")) return;
+
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size,
+      };
+      if (this.createTime) {
+        datas.examStartTime = this.createTime[0];
+        datas.examEndTime = this.createTime[1];
+      }
+      const data = await pdfBuildListPage(datas);
+      this.tasks = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    async toResetCreatePdf(row) {
+      if (this.loading) return;
+
+      this.loading = true;
+      const res = await taskResetPdf(row.id).catch(() => {});
+      this.loading = false;
+      if (!res) return;
+
+      this.$message.success("操作成功!");
+      this.getList();
+    },
+    toViewLog(row) {
+      this.logList = (row.summary || "").split("\n");
+      this.modalIsShow = true;
+    },
+  },
+};
+</script>