Browse Source

card edit -f

zhangjie 3 years ago
parent
commit
30314328ba

+ 1 - 0
card/components/CardDesign.vue

@@ -465,6 +465,7 @@ export default {
           const data = JSON.stringify(
             {
               version: CARD_VERSION,
+              cardType: "STANDARD",
               cardConfig: this.cardConfig,
               paperParams: this.paperParams,
               pages: this.pages

+ 2 - 1
card/components/PagePropEdit.vue

@@ -95,7 +95,8 @@ export default {
   data() {
     return {
       columnOptions: [],
-      pageSizeOptions: ["A3", "A4"],
+      pageSizeOptions: ["A3"],
+      // pageSizeOptions: ["A3", "A4"],
       form: {
         pageSize: "A3",
         columnNumber: 2,

+ 1 - 0
card/modules/free/components/CardFreeDesign.vue

@@ -334,6 +334,7 @@ export default {
           const data = JSON.stringify(
             {
               version: CARD_VERSION,
+              cardType: "FREE",
               cardConfig: this.cardConfig,
               paperParams: this.paperParams,
               pages: this.pages

+ 2 - 1
card/modules/free/components/PagePropEdit.vue

@@ -65,7 +65,8 @@ export default {
   data() {
     return {
       columnOptions: [],
-      pageSizeOptions: ["A3", "A4"],
+      pageSizeOptions: ["A3"],
+      // pageSizeOptions: ["A3", "A4"],
       form: {
         pageSize: "A3",
         columnNumber: 2,

+ 5 - 1
src/constants/enumerate.js

@@ -64,11 +64,15 @@ export const SMS_TYPE = {
 // 通用题卡规则id
 export const COMMON_CARD_RULE_ID = "-1";
 
-export const CARD_CREATE_TYPE = {
+export const CARD_CREATE_METHOD_TYPE = {
   UPLOAD: "上传文件",
   STANDARD: "标准模式",
   FREE: "自由模式"
 };
+export const CARD_TYPE = {
+  GENERIC: "通卡",
+  CUSTOM: "自定义专卡"
+};
 
 // 模板类型
 export const TEMPLATE_TYPE = {

+ 5 - 2
src/modules/base/api.js

@@ -125,10 +125,13 @@ export const templateContentView = attachmentId => {
 };
 // card-manage
 export const cardListPage = datas => {
-  return $postParam("/api/admin/basic/card/list", datas);
+  return $postParam("/api/admin/exam/card/page", datas);
+};
+export const updateCard = datas => {
+  return $post("/api/admin/exam/card/save_generic", datas);
 };
 export const deleteCard = id => {
-  return $post("/api/admin/basic/card/remove", { id });
+  return $postParam("/api/admin/exam/card/delete_generic", { id });
 };
 // course-manage
 export const courseListPage = datas => {

+ 32 - 26
src/modules/base/components/ModifyCardInfo.vue

@@ -16,9 +16,9 @@
       :rules="rules"
       :model="modalForm"
     >
-      <el-form-item prop="name" label="题卡名称:">
+      <el-form-item prop="title" label="题卡名称:">
         <el-input
-          v-model.trim="modalForm.name"
+          v-model.trim="modalForm.title"
           placeholder="建议不超过30个字,题卡名称不允许重复"
           clearable
         ></el-input>
@@ -35,10 +35,10 @@
           placeholder="建议不超过50个字"
         ></el-input>
       </el-form-item>
-      <el-form-item prop="createType" label="题卡创建方式:">
-        <el-radio-group v-model="modalForm.createType" :disabled="isEdit">
+      <el-form-item prop="createMethod" label="题卡创建方式:">
+        <el-radio-group v-model="modalForm.createMethod" :disabled="isEdit">
           <el-radio-button
-            v-for="(val, key) in CARD_CREATE_TYPE"
+            v-for="(val, key) in CARD_CREATE_METHOD_TYPE"
             :key="key"
             :label="key"
             >{{ val }}</el-radio-button
@@ -62,6 +62,7 @@
           placeholder="请选择题卡规则"
           clearable
           class="width-full"
+          :disabled="isEdit"
           :show-common-card="false"
         ></card-rule-select>
       </el-form-item>
@@ -80,19 +81,21 @@
 </template>
 
 <script>
-import { updateTemplate } from "../api";
+import { updateCard } from "../api";
 import { attachmentDetail } from "../../login/api";
-import { CARD_CREATE_TYPE } from "../../../constants/enumerate";
+import { CARD_CREATE_METHOD_TYPE } from "../../../constants/enumerate";
 import UploadFileView from "@/components/UploadFileView";
 import SelectOrgs from "./SelectOrgs";
 
 const initModalForm = {
   id: null,
-  name: "",
-  createType: "UPLOAD",
+  title: "",
+  type: "GENERIC",
+  createMethod: "UPLOAD",
   remark: "",
   cardRuleId: "",
   attachmentId: "",
+  status: "STAGE",
   orgIds: []
 };
 
@@ -114,14 +117,17 @@ export default {
     title() {
       return (this.isEdit ? "编辑" : "新增") + "题卡";
     },
+    IS_GENGRIC() {
+      return this.modalForm.type === "GENERIC";
+    },
     IS_UPLOAD() {
-      return this.modalForm.createType === "UPLOAD";
+      return this.modalForm.createMethod === "UPLOAD";
     },
     IS_STANDARD() {
-      return this.modalForm.createType === "STANDARD";
+      return this.modalForm.createMethod === "STANDARD";
     },
     IS_FREE() {
-      return this.modalForm.createType === "FREE";
+      return this.modalForm.createMethod === "FREE";
     }
   },
   data() {
@@ -131,9 +137,9 @@ export default {
       modalForm: {},
       attachment: {},
       format: ["html"],
-      CARD_CREATE_TYPE,
+      CARD_CREATE_METHOD_TYPE,
       rules: {
-        name: [
+        title: [
           {
             required: true,
             message: "题卡名称不能超过30个字",
@@ -141,7 +147,7 @@ export default {
             trigger: "change"
           }
         ],
-        createType: [
+        createMethod: [
           {
             required: true,
             message: "请选择题卡创建方式",
@@ -188,11 +194,11 @@ export default {
       this.modalForm = this.$objAssign(initModalForm, val);
       if (val.id) {
         this.modalForm.orgIds = val.orgs.map(item => item.id);
-        if (this.modalForm.createType !== "UPLOAD") return;
+        if (this.modalForm.createMethod !== "UPLOAD") return;
         this.getAttachment();
       } else {
         this.modalForm.orgIds = [];
-        if (this.modalForm.createType !== "UPLOAD") return;
+        if (this.modalForm.createMethod !== "UPLOAD") return;
         this.$nextTick(() => {
           this.$refs.UploadFileView.setAttachmentName("");
         });
@@ -223,26 +229,26 @@ export default {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;
 
+      if (!this.IS_UPLOAD && !this.isEdit) {
+        this.$ls.set("prepareTcPCard", this.modalForm);
+        this.$router.push({
+          name: "CardEdit"
+        });
+        return;
+      }
+
       if (this.isSubmit) return;
       this.isSubmit = true;
       let datas = {
         ...this.modalForm
       };
-      if (datas.type === "GENERIC") datas.classify = "CARD";
-      const data = await updateTemplate(datas).catch(() => {});
+      const data = await updateCard(datas).catch(() => {});
       this.isSubmit = false;
       if (!data) return;
-      console.log(datas);
 
       this.$message.success("保存成功!");
       this.$emit("modified");
       this.cancel();
-
-      if (!this.IS_UPLOAD && !this.isEdit) {
-        this.$router.push({
-          name: this.IS_STANDARD ? "CardEdit" : "CardFreeEdit"
-        });
-      }
     },
     uplaodError(errorData) {
       this.$notify.error({ title: "错误提示", message: errorData.message });

+ 65 - 30
src/modules/base/views/CardManage.vue

@@ -5,26 +5,40 @@
         <template v-if="checkPrivilege('condition', 'condition')">
           <el-form-item label="题卡名称:">
             <el-input
-              v-model.trim="filter.name"
+              v-model.trim="filter.title"
               placeholder="名称"
               clearable
             ></el-input>
           </el-form-item>
           <el-form-item label="创建方式:" label-width="90px">
             <el-select
-              v-model="filter.createType"
+              v-model="filter.createMethod"
               style="width: 120px;"
               placeholder="创建方式"
               clearable
             >
               <el-option
-                v-for="(val, key) in CARD_CREATE_TYPE"
+                v-for="(val, key) in CARD_CREATE_METHOD_TYPE"
                 :key="key"
                 :value="key"
                 :label="val"
               ></el-option>
             </el-select>
           </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
@@ -53,14 +67,20 @@
           width="70"
           :index="indexMethod"
         ></el-table-column>
-        <el-table-column prop="name" label="题卡名称"></el-table-column>
-        <el-table-column prop="type" label="类型"></el-table-column>
-        <el-table-column prop="orgs" label="适用学院">
+        <el-table-column prop="title" label="题卡名称"></el-table-column>
+        <el-table-column prop="type" label="类型">
+          <span slot-scope="scope">{{ scope.row.type | cardTypeFilter }}</span>
+        </el-table-column>
+        <el-table-column prop="orgNames" label="适用学院">
           <template slot-scope="scope">
             <more-text :data="scope.row.orgNames"></more-text>
           </template>
         </el-table-column>
-        <el-table-column prop="createType" label="创建方式"></el-table-column>
+        <el-table-column prop="createMethod" label="创建方式">
+          <span slot-scope="scope">{{
+            scope.row.createMethod | cardCreateMethodTypeFilter
+          }}</span>
+        </el-table-column>
         <el-table-column prop="remark" label="备注">
           <span slot-scope="scope">{{
             scope.row.remark | defaultFieldFilter
@@ -74,7 +94,7 @@
         <el-table-column class-name="action-column" label="操作" width="140">
           <template slot-scope="scope">
             <el-button
-              v-if="checkPrivilege('link', 'preview')"
+              v-if="!checkPrivilege('link', 'preview')"
               class="btn-primary"
               type="text"
               @click="toPreview(scope.row)"
@@ -83,7 +103,7 @@
             <el-button
               v-if="
                 checkPrivilege('link', 'edit') &&
-                  scope.row.createType !== 'UPLOAD'
+                  scope.row.createMethod !== 'UPLOAD'
               "
               class="btn-primary"
               type="text"
@@ -130,9 +150,10 @@
 </template>
 
 <script>
-import { CARD_CREATE_TYPE } from "../../../constants/enumerate";
+import { CARD_CREATE_METHOD_TYPE } from "../../../constants/enumerate";
 import { cardListPage, deleteCard } from "../api";
 import ModifyCardInfo from "../components/ModifyCardInfo";
+import pickerOptions from "@/constants/datePickerOptions";
 
 export default {
   name: "card-manage",
@@ -140,28 +161,25 @@ export default {
   data() {
     return {
       filter: {
-        name: "",
-        createType: ""
+        title: "",
+        createMethod: "",
+        createStartTime: "",
+        createEndTime: ""
       },
       current: 1,
       size: this.GLOBAL.pageSize,
       total: 0,
-      CARD_CREATE_TYPE,
-      cardList: [
-        {
-          id: "11",
-          name: "标准题卡001",
-          type: "",
-          orgs: [],
-          orgNames: ["一中"],
-          createType: "STANDARD",
-          remark: "",
-          createTime: "152145785632145"
-        }
-      ],
-      curCard: {}
+      CARD_CREATE_METHOD_TYPE,
+      cardList: [],
+      curCard: {},
+      // date-picker
+      createTime: [],
+      pickerOptions
     };
   },
+  mounted() {
+    this.getList();
+  },
   methods: {
     async getList() {
       if (!this.checkPrivilege("list", "list")) return;
@@ -171,8 +189,15 @@ export default {
         pageNumber: this.current,
         pageSize: this.size
       };
+      if (this.createTime) {
+        datas.createStartTime = this.createTime[0];
+        datas.createEndTime = this.createTime[1];
+      }
       const data = await cardListPage(datas);
-      this.cardList = data.records;
+      this.cardList = data.records.map(item => {
+        item.orgNames = item.orgs.map(org => org.name);
+        return item;
+      });
       this.total = data.total;
     },
     toPage(page) {
@@ -186,7 +211,7 @@ export default {
     toPreview(row) {
       this.curCard = row;
       this.$router.push({
-        name: row.createType === "STANDARD" ? "CardPreview" : "CardFreePreview",
+        name: "CardPreview",
         params: {
           cardId: row.id,
           viewType: "view"
@@ -195,8 +220,18 @@ export default {
     },
     toEditCard(row) {
       this.curCard = row;
+      this.$ls.set("prepareTcPCard", {
+        id: row.id,
+        title: row.title,
+        type: row.type,
+        createMethod: row.createMethod,
+        remark: row.remark,
+        cardRuleId: row.cardRuleId,
+        attachmentId: row.attachmentId,
+        orgIds: row.orgs.map(item => item.id)
+      });
       this.$router.push({
-        name: row.createType === "STANDARD" ? "CardEdit" : "CardFreeEdit",
+        name: "CardEdit",
         params: {
           cardId: row.id
         }
@@ -207,7 +242,7 @@ export default {
       this.$refs.ModifyCardInfo.open();
     },
     toDelete(row) {
-      this.$confirm(`确定要删除题卡【${row.name}】吗?`, "提示", {
+      this.$confirm(`确定要删除题卡【${row.title}】吗?`, "提示", {
         type: "warning"
       })
         .then(async () => {

+ 1 - 1
src/modules/base/views/ExamManage.vue

@@ -161,7 +161,7 @@ export default {
   },
   methods: {
     async getList() {
-      if (this.checkPrivilege("list", "list")) return;
+      if (!this.checkPrivilege("list", "list")) return;
 
       const datas = {
         ...this.filter,

+ 5 - 1
src/modules/card/api.js

@@ -8,5 +8,9 @@ export const cardDetail = cardId => {
 };
 
 export const saveCard = (datas, config = {}) => {
-  return $post("/api/admin/exam/card/save", datas, config);
+  if (datas.type === "GENERIC") {
+    return $post("/api/admin/exam/card/save_generic", datas, config);
+  } else {
+    return $post("/api/admin/exam/card/save", datas, config);
+  }
 };

+ 86 - 45
src/modules/card/views/CardEdit.vue

@@ -1,14 +1,15 @@
 <template>
   <div class="card-edit">
-    <card-design
+    <component
       v-if="dataReady"
+      :is="editComp"
       ref="CardDesign"
       :content="cardContent"
       @on-preview="toPreview"
       @on-save="toSave"
       @on-submit="toSubmit"
       @on-exit="toExit"
-    ></card-design>
+    ></component>
 
     <!-- card-view-frame -->
     <div class="design-preview-frame" v-if="cardPreviewUrl">
@@ -20,22 +21,22 @@
 <script>
 import { cardConfigInfos, cardDetail, saveCard } from "../api";
 import CardDesign from "../../../../card/components/CardDesign";
+import CardFreeDesign from "../../../../card/modules/free/components/CardFreeDesign";
+import { examRuleDetail } from "../../base/api";
+import { getEnums } from "../../login/api";
 
 export default {
   name: "card-edit",
   components: {
-    CardDesign
+    CardDesign,
+    CardFreeDesign
   },
   data() {
     return {
       cardId: this.$route.params.cardId || this.$ls.get("cardId"),
-      prepareTcPCard: this.$ls.get("prepareTcPCard", {
-        examTaskId: "",
-        courseCode: "",
-        courseName: "",
-        makeMethod: "SELF",
-        cardRuleId: ""
-      }),
+      prepareTcPCard: this.$ls.get("prepareTcPCard", {}),
+      cardType: "CUSTOM",
+      cardCreateMethod: "STANDARD",
       cardContent: {},
       cardPreviewUrl: "",
       canSave: false,
@@ -45,10 +46,24 @@ export default {
   computed: {
     isEdit() {
       return !!this.cardId;
+    },
+    editComp() {
+      return this.cardCreateMethod === "STANDARD"
+        ? "card-design"
+        : "card-free-design";
+    },
+    IS_GENERIC() {
+      return this.cardType === "GENERIC";
     }
   },
   mounted() {
-    if (!this.prepareTcPCard.examTaskId && !this.isEdit) {
+    this.cardCreateMethod = this.prepareTcPCard.createMethod || "STANDARD";
+    this.cardType = this.prepareTcPCard.type || "CUSTOM";
+    if (
+      !this.prepareTcPCard.examTaskId &&
+      !this.isEdit &&
+      this.cardType === "CUSTOM"
+    ) {
       this.$message.error("找不到命题任务,请退出题卡制作!");
       return;
     }
@@ -61,7 +76,10 @@ export default {
       if (this.isEdit) {
         await this.getCardTempDetail();
       } else {
-        const cardConfig = await this.getCardConfig();
+        let cardConfig = await this.getCardConfig();
+        if (this.IS_GENERIC) {
+          cardConfig.cardTitle = this.prepareTcPCard.title;
+        }
         this.cardContent = {
           pages: [],
           cardConfig,
@@ -72,9 +90,9 @@ export default {
     },
     getCardTitle(titleRule) {
       const fieldMap = {
-        courseCode: this.prepareTcPCard.courseCode,
-        courseName: this.prepareTcPCard.courseName,
-        schoolName: this.prepareTcPCard.schoolName
+        courseCode: this.prepareTcPCard.courseCode || "",
+        courseName: this.prepareTcPCard.courseName || "",
+        schoolName: this.prepareTcPCard.schoolName || ""
       };
       Object.entries(fieldMap).forEach(([key, val]) => {
         titleRule = titleRule.replace("${" + key + "}", val);
@@ -89,7 +107,7 @@ export default {
       } else {
         let cardConfig = await this.getCardConfig();
         // 没有题卡内容时,直接创建新的内容
-        if (detData.makeMethod === "CUST") {
+        if (detData.makeMethod === "CUST" || detData.type === "GENERIC") {
           cardConfig.cardTitle = detData.title;
         }
         this.cardContent = {
@@ -100,27 +118,50 @@ export default {
       }
     },
     async getCardConfig() {
-      const data = await cardConfigInfos(this.prepareTcPCard.cardRuleId);
-      if (!data) {
-        this.$message.error("找不到题卡规则!");
-        return;
-      }
-      let config = {
-        ...data,
-        ...{
+      if (this.cardCreateMethod === "STANDARD") {
+        const data = await cardConfigInfos(this.prepareTcPCard.cardRuleId);
+        if (!data) {
+          this.$message.error("找不到题卡规则!");
+          return Promise.reject();
+        }
+        let config = {
+          ...data,
+          ...{
+            pageSize: "A3",
+            columnNumber: 2,
+            columnGap: 20,
+            showForbidArea: true,
+            cardDesc: "",
+            makeMethod: this.prepareTcPCard.makeMethod
+          }
+        };
+        config.aOrB = true; // 默认开启A/B卷型
+        config.requiredFields = JSON.parse(config.requiredFields);
+        config.extendFields = JSON.parse(config.extendFields);
+        config.cardTitle = this.getCardTitle(config.titleRule);
+        return config;
+      } else {
+        let requiredFields = await getEnums("REQUIRED_FIELDS");
+        requiredFields = requiredFields.map(item => {
+          return {
+            code: item.code,
+            name: item.desc,
+            enable: true
+          };
+        });
+        const examRule = await examRuleDetail();
+        const extendFields = examRule.extendFields | "[]";
+        let config = {
           pageSize: "A3",
           columnNumber: 2,
           columnGap: 20,
           showForbidArea: true,
           cardDesc: "",
-          makeMethod: this.prepareTcPCard.makeMethod
-        }
-      };
-      config.aOrB = true; // 默认开启A/B卷型
-      config.requiredFields = JSON.parse(config.requiredFields);
-      config.extendFields = JSON.parse(config.extendFields);
-      config.cardTitle = this.getCardTitle(config.titleRule);
-      return config;
+          requiredFields,
+          extendFields: JSON.parse(extendFields)
+        };
+        return config;
+      }
     },
     // 操作
     getRequestConfig() {
@@ -132,18 +173,16 @@ export default {
           }
         : {};
     },
-    getCardData(htmlContent = "", model = "") {
-      let data = this.$refs.CardDesign.getCardData(htmlContent, model);
-      data = {
+    getCardInfo(data) {
+      let cardInfo = {
         ...data,
-        type: "CUSTOM",
         ...this.prepareTcPCard
       };
-      if (this.cardId) data.id = this.cardId;
-      return data;
+      if (this.cardId) cardInfo.id = this.cardId;
+      return cardInfo;
     },
-    async toPreview(datas) {
-      await this.toSave(datas);
+    async toPreview(cardModel) {
+      await this.toSave(cardModel);
 
       const { href } = this.$router.resolve({
         name: "CardPreview",
@@ -156,9 +195,10 @@ export default {
     },
     // save
     async toSave(datas) {
-      datas.status = "STAGE";
+      let cardInfo = this.getCardInfo(datas);
+      cardInfo.status = "STAGE";
       const result = await saveCard(
-        datas,
+        cardInfo,
         this.getRequestConfig()
       ).catch(() => {});
 
@@ -187,10 +227,11 @@ export default {
     },
     registWindowSubmit() {
       window.submitCardTemp = async (htmlContent, model) => {
-        const datas = this.getCardData(htmlContent, model);
-        datas.status = "SUBMIT";
+        const datas = this.$refs.CardDesign.getCardData(htmlContent, model);
+        const cardInfo = this.getCardInfo(datas);
+        cardInfo.status = "SUBMIT";
         const result = await saveCard(
-          datas,
+          cardInfo,
           this.getRequestConfig()
         ).catch(() => {});
         this.cardPreviewUrl = "";

+ 76 - 35
src/modules/card/views/CardPreview.vue

@@ -1,33 +1,38 @@
 <template>
   <div :class="classes">
-    <div v-if="IS_COMMON_CARD" class="preview-frame" id="preview-frame"></div>
-    <card-view
-      v-if="!IS_COMMON_CARD && pages.length"
+    <div v-if="IS_HTML_TEMPLATE" class="preview-frame" id="preview-frame"></div>
+
+    <component
+      v-if="!IS_HTML_TEMPLATE && pages.length"
+      :is="editComp"
       ref="CardView"
       class="preview-body"
       :pages="pages"
       :card-config="cardConfig"
-    ></card-view>
+    ></component>
   </div>
 </template>
 
 <script>
 import CardView from "../../../../card/components/CardView";
+import CardFreeView from "../../../../card/modules/free/components/CardFreeView";
 import { cardDetail } from "../api";
 import { deepCopy } from "@/plugins/utils";
 const JsBarcode = require("jsbarcode");
 
 export default {
   name: "card-preview",
-  components: { CardView },
+  components: { CardView, CardFreeView },
   data() {
     return {
       isPrint: this.$route.params.viewType !== "view",
       isFrame: this.$route.params.viewType === "frame",
       cardId: this.$route.params.cardId,
+      cardCreateMethod: "STANDARD",
+      cardType: "CUSTOM",
       cardConfig: {},
       pages: [],
-      IS_COMMON_CARD: false
+      IS_HTML_TEMPLATE: false
     };
   },
   computed: {
@@ -38,6 +43,12 @@ export default {
           "card-print": this.isPrint
         }
       ];
+    },
+    editComp() {
+      return this.cardCreateMethod === "FREE" ? "card-free-view" : "card-view";
+    },
+    IS_HTML_TEMPLATE1() {
+      return this.cardType === "GENERIC" && this.cardCreateMethod === "UPLOAD";
     }
   },
   mounted() {
@@ -52,21 +63,26 @@ export default {
       const cardData = window.parent.cardData;
       if (!cardData) return;
 
-      const { cardConfig, pages } = deepCopy(cardData);
+      const { cardConfig, pages, createMethod, type } = deepCopy(cardData);
+      this.cardCreateMethod = createMethod;
+      this.cardType = type;
       let fieldInfos = {};
       [...cardConfig.requiredFields, ...cardConfig.extendFields]
         .filter(item => item.enable)
         .map(item => {
           fieldInfos[item.code] = "${" + item.code + "}";
         });
-      if (cardConfig.examNumberStyle === "PRINT") {
-        fieldInfos.examNumber = "data:image/png;base64,${examNumber}";
-        fieldInfos.examNumberStr = "${examNumberStr}";
-      }
 
-      if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
-        fieldInfos.paperType = "data:image/png;base64,${paperType}";
-        fieldInfos.paperTypeName = "${paperTypeName}";
+      if (this.cardCreateMethod === "STANDARD") {
+        if (cardConfig.examNumberStyle === "PRINT") {
+          fieldInfos.examNumber = "data:image/png;base64,${examNumber}";
+          fieldInfos.examNumberStr = "${examNumberStr}";
+        }
+
+        if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
+          fieldInfos.paperType = "data:image/png;base64,${paperType}";
+          fieldInfos.paperTypeName = "${paperTypeName}";
+        }
       }
 
       this.cardConfig = cardConfig;
@@ -84,11 +100,13 @@ export default {
     },
     async init() {
       const detData = await cardDetail(this.cardId);
+      this.cardCreateMethod = detData.createMethod;
+      this.cardType = detData.type;
 
-      this.IS_COMMON_CARD = detData.type === "GENERIC";
+      this.IS_HTML_TEMPLATE =
+        detData.type === "GENERIC" && detData.createMethod === "UPLOAD";
       // 通卡展示
-      if (this.IS_COMMON_CARD) {
-        // TODO:通卡展示逻辑要调整
+      if (this.IS_HTML_TEMPLATE) {
         this.$nextTick(() => {
           this.initHtmlTemp(detData.htmlContent);
         });
@@ -120,22 +138,26 @@ export default {
       let fieldInfos = {};
       const defContent = "相关信息";
       const defNumber = "123456789";
+      console.log(cardConfig);
+      // TODO:extendFields => 0 bug
       [...cardConfig.requiredFields, ...cardConfig.extendFields]
         .filter(item => item.enable)
         .map(item => {
           fieldInfos[item.code] = stdInfo[item.code] || defContent;
         });
-      if (cardConfig.examNumberStyle === "PRINT") {
-        fieldInfos.examNumber = this.getBase64Barcode(
-          stdInfo["examNumber"] || defNumber
-        );
-        fieldInfos.examNumberStr = stdInfo["examNumber"] || defNumber;
-      }
-      if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
-        fieldInfos.paperType = this.getBase64Barcode(
-          stdInfo["paperType"] || defNumber
-        );
-        fieldInfos.paperTypeName = stdInfo["paperTypeName"] || "A";
+      if (this.cardCreateMethod === "STANDARD") {
+        if (cardConfig.examNumberStyle === "PRINT") {
+          fieldInfos.examNumber = this.getBase64Barcode(
+            stdInfo["examNumber"] || defNumber
+          );
+          fieldInfos.examNumberStr = stdInfo["examNumber"] || defNumber;
+        }
+        if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
+          fieldInfos.paperType = this.getBase64Barcode(
+            stdInfo["paperType"] || defNumber
+          );
+          fieldInfos.paperTypeName = stdInfo["paperTypeName"] || "A";
+        }
       }
 
       return fieldInfos;
@@ -155,14 +177,33 @@ export default {
       return canvas.toDataURL();
     },
     appendFieldInfo(pages, fieldInfos) {
-      pages.forEach((page, pageNo) => {
-        if (pageNo % 2) return;
-        const cardHeadElement = page.columns[0].elements[0];
+      if (this.cardCreateMethod === "STANDARD") {
+        pages.forEach((page, pageNo) => {
+          if (pageNo % 2) return;
+          const cardHeadElement = page.columns[0].elements[0];
 
-        if (cardHeadElement.type === "CARD_HEAD") {
-          cardHeadElement.fieldInfos = fieldInfos;
-        }
-      });
+          if (cardHeadElement.type === "CARD_HEAD") {
+            cardHeadElement.fieldInfos = fieldInfos;
+          }
+        });
+      } else {
+        const VALID_ELEMENTS_FOR_EXTERNAL = ["BARCODE", "FILL_FIELD"];
+        pages.forEach(page => {
+          page.columns.forEach(column => {
+            column.elements.forEach(element => {
+              if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
+
+              if (element.type === "BARCODE") {
+                const field = element.fields[0] && element.fields[0].code;
+                element.content = `data:image/png;base64,${fieldInfos[field]}`;
+                return;
+              }
+
+              element.fieldInfos = fieldInfos;
+            });
+          });
+        });
+      }
       return pages;
     }
   }

+ 229 - 0
src/modules/card/views/CardStandardEdit.vue

@@ -0,0 +1,229 @@
+<template>
+  <div class="card-edit">
+    <card-design
+      v-if="dataReady"
+      ref="CardDesign"
+      :content="cardContent"
+      @on-preview="toPreview"
+      @on-save="toSave"
+      @on-submit="toSubmit"
+      @on-exit="toExit"
+    ></card-design>
+
+    <!-- card-view-frame -->
+    <div class="design-preview-frame" v-if="cardPreviewUrl">
+      <iframe :src="cardPreviewUrl" frameborder="0"></iframe>
+    </div>
+  </div>
+</template>
+
+<script>
+import { cardConfigInfos, cardDetail, saveCard } from "../api";
+import CardDesign from "../../../../card/components/CardDesign";
+
+export default {
+  name: "card-standard-edit",
+  components: {
+    CardDesign
+  },
+  data() {
+    return {
+      cardId: this.$route.params.cardId || this.$ls.get("cardId"),
+      prepareTcPCard: this.$ls.get("prepareTcPCard", {
+        examTaskId: "",
+        courseCode: "",
+        courseName: "",
+        makeMethod: "SELF",
+        cardRuleId: ""
+      }),
+      cardContent: {},
+      cardPreviewUrl: "",
+      canSave: false,
+      dataReady: false
+    };
+  },
+  computed: {
+    isEdit() {
+      return !!this.cardId;
+    }
+  },
+  mounted() {
+    if (!this.prepareTcPCard.examTaskId && !this.isEdit) {
+      this.$message.error("找不到命题任务,请退出题卡制作!");
+      return;
+    }
+    this.initCard();
+    this.registWindowSubmit();
+  },
+  methods: {
+    async initCard() {
+      this.dataReady = false;
+      if (this.isEdit) {
+        await this.getCardTempDetail();
+      } else {
+        const cardConfig = await this.getCardConfig();
+        this.cardContent = {
+          pages: [],
+          cardConfig,
+          paperParams: {}
+        };
+      }
+      this.dataReady = true;
+    },
+    getCardTitle(titleRule) {
+      const fieldMap = {
+        courseCode: this.prepareTcPCard.courseCode,
+        courseName: this.prepareTcPCard.courseName,
+        schoolName: this.prepareTcPCard.schoolName
+      };
+      Object.entries(fieldMap).forEach(([key, val]) => {
+        titleRule = titleRule.replace("${" + key + "}", val);
+      });
+      return titleRule;
+    },
+    async getCardTempDetail() {
+      const detData = await cardDetail(this.cardId);
+      // 可能存在题卡内容没有记录的情况
+      if (detData.content) {
+        this.cardContent = JSON.parse(detData.content);
+      } else {
+        let cardConfig = await this.getCardConfig();
+        // 没有题卡内容时,直接创建新的内容
+        if (detData.makeMethod === "CUST") {
+          cardConfig.cardTitle = detData.title;
+        }
+        this.cardContent = {
+          pages: [],
+          cardConfig,
+          paperParams: {}
+        };
+      }
+    },
+    async getCardConfig() {
+      const data = await cardConfigInfos(this.prepareTcPCard.cardRuleId);
+      if (!data) {
+        this.$message.error("找不到题卡规则!");
+        return;
+      }
+      let config = {
+        ...data,
+        ...{
+          pageSize: "A3",
+          columnNumber: 2,
+          columnGap: 20,
+          showForbidArea: true,
+          cardDesc: "",
+          makeMethod: this.prepareTcPCard.makeMethod
+        }
+      };
+      config.aOrB = true; // 默认开启A/B卷型
+      config.requiredFields = JSON.parse(config.requiredFields);
+      config.extendFields = JSON.parse(config.extendFields);
+      config.cardTitle = this.getCardTitle(config.titleRule);
+      return config;
+    },
+    // 操作
+    getRequestConfig() {
+      return this.prepareTcPCard.makeMethod === "CUST"
+        ? {
+            headers: {
+              schoolId: this.prepareTcPCard.schoolId
+            }
+          }
+        : {};
+    },
+    getCardData(htmlContent = "", model = "") {
+      let data = this.$refs.CardDesign.getCardData(htmlContent, model);
+      data = {
+        ...data,
+        type: "CUSTOM",
+        ...this.prepareTcPCard
+      };
+      if (this.cardId) data.id = this.cardId;
+      return data;
+    },
+    async toPreview(datas) {
+      await this.toSave(datas);
+
+      const { href } = this.$router.resolve({
+        name: "CardPreview",
+        params: {
+          cardId: this.cardId,
+          viewType: "view"
+        }
+      });
+      window.open(href);
+    },
+    // save
+    async toSave(datas) {
+      datas.status = "STAGE";
+      const result = await saveCard(
+        datas,
+        this.getRequestConfig()
+      ).catch(() => {});
+
+      this.$refs.CardDesign.unloading();
+      if (!result) return;
+
+      this.cardId = result;
+      this.$ls.set("cardId", this.cardId);
+      this.$message.success("保存成功!");
+    },
+    async toSubmit(cardData) {
+      const res = await this.$confirm("确定要提交当前题卡吗?", "提示", {
+        type: "warning"
+      }).catch(() => {});
+      if (res !== "confirm") return;
+
+      window.cardData = cardData;
+      const { href } = this.$router.resolve({
+        name: "CardPreview",
+        params: {
+          cardId: 1,
+          viewType: "frame"
+        }
+      });
+      this.cardPreviewUrl = href;
+    },
+    registWindowSubmit() {
+      window.submitCardTemp = async (htmlContent, model) => {
+        const datas = this.getCardData(htmlContent, model);
+        datas.status = "SUBMIT";
+        const result = await saveCard(
+          datas,
+          this.getRequestConfig()
+        ).catch(() => {});
+        this.cardPreviewUrl = "";
+        window.cardData = null;
+        if (result) {
+          this.cardId = result;
+          this.$ls.set("cardId", this.cardId);
+          this.canSave = false;
+          this.$message.success("提交成功!");
+          this.goback();
+        } else {
+          this.$message.error("提交失败,请重新尝试!");
+        }
+      };
+    },
+    toExit() {
+      this.$confirm(
+        "请确保当前题卡已经正常保存,确定要退出当前题卡编辑吗?",
+        "提示",
+        {
+          type: "warning"
+        }
+      )
+        .then(() => {
+          this.goback();
+        })
+        .catch(() => {});
+    }
+  },
+  beforeDestroy() {
+    this.$ls.remove("cardId");
+    this.$ls.remove("prepareTcPCard");
+    delete window.submitCardTemp;
+  }
+};
+</script>

+ 2 - 0
src/modules/customer/views/CustomerCard.vue

@@ -306,6 +306,8 @@ export default {
         courseName: row.courseName,
         schoolName: row.schoolName,
         makeMethod: "CUST",
+        type: "CUSTOM",
+        createMethod: "STANDARD",
         cardRuleId: row.cardRuleId,
         schoolId: row.schoolId
       });

+ 3 - 1
src/modules/exam/components/ApplyContent.vue

@@ -776,7 +776,9 @@ export default {
         courseCode: this.task.courseCode,
         courseName: this.task.courseName,
         makeMethod: this.task.makeMethod,
-        cardRuleId: this.task.cardRuleId
+        cardRuleId: this.task.cardRuleId,
+        type: "CUSTOM",
+        createMethod: "STANDARD"
       });
     },
     async toCreateOrViewCard() {

+ 3 - 1
src/modules/exam/components/CardOptionDialog.vue

@@ -277,7 +277,9 @@ export default {
           schoolName: this.$ls.get("schoolName"),
           makeMethod: this.modalForm.makeMethod,
           cardRuleId: this.modalForm.cardRuleId,
-          paperType: this.modalForm.paperType
+          paperType: this.modalForm.paperType,
+          type: "CUSTOM",
+          createMethod: "STANDARD"
         });
         // 打开题卡编辑页,创建题卡,并预设需要绑定的任务
         this.$router.push({

+ 3 - 1
src/modules/exam/components/CreateTaskApply.vue

@@ -593,7 +593,9 @@ export default {
         courseCode: this.examTask.courseCode,
         courseName: this.examTask.courseName,
         makeMethod: this.examTaskDetail.makeMethod,
-        cardRuleId: this.examTask.cardRuleId
+        cardRuleId: this.examTask.cardRuleId,
+        type: "CUSTOM",
+        createMethod: "STANDARD"
       });
     },
     async toCreateOrViewCard() {

+ 3 - 1
src/modules/exam/components/ModifyTaskPaper.vue

@@ -393,7 +393,9 @@ export default {
         courseName: this.curTaskApply.courseName,
         makeMethod: this.curTaskApply.makeMethod,
         cardRuleId: this.curTaskApply.cardRuleId,
-        paperType: this.paperAttachments.map(item => item.name).join(",")
+        paperType: this.paperAttachments.map(item => item.name).join(","),
+        type: "CUSTOM",
+        createMethod: "STANDARD"
       });
     },
     async toCreateOrViewCard() {

+ 9 - 1
src/plugins/filters.js

@@ -15,7 +15,9 @@ import {
   STMMS_SYNC_TYPE,
   SYNC_PRINT_STATUS,
   PRINT_PDF_TYPE,
-  EXAM_TYPE
+  EXAM_TYPE,
+  CARD_TYPE,
+  CARD_CREATE_METHOD_TYPE
 } from "../constants/enumerate";
 import { formatDate } from "../plugins/utils";
 
@@ -92,3 +94,9 @@ Vue.filter("printPdfTypeFilter", function(val) {
 Vue.filter("examTypeFilter", function(val) {
   return EXAM_TYPE[val] || DEFAULT_FIELD;
 });
+Vue.filter("cardTypeFilter", function(val) {
+  return CARD_TYPE[val] || DEFAULT_FIELD;
+});
+Vue.filter("cardCreateMethodTypeFilter", function(val) {
+  return CARD_CREATE_METHOD_TYPE[val] || DEFAULT_FIELD;
+});