zhangjie 3 anni fa
parent
commit
e38990fe50
24 ha cambiato i file con 3167 aggiunte e 1 eliminazioni
  1. 105 0
      src/modules/analysis/api.js
  2. 119 0
      src/modules/analysis/components/ModifyAnalysisBatch.vue
  3. 193 0
      src/modules/analysis/components/ModifyAnalysisBatchPaper.vue
  4. 109 0
      src/modules/analysis/components/ModifyBaseConfig.vue
  5. 257 0
      src/modules/analysis/components/SelectAnalysisPaper.vue
  6. 96 0
      src/modules/analysis/components/baseConfig/BlueprintConfig.vue
  7. 134 0
      src/modules/analysis/components/baseConfig/CommentAbility.vue
  8. 59 0
      src/modules/analysis/components/baseConfig/CommentConfig.vue
  9. 134 0
      src/modules/analysis/components/baseConfig/CommentKnowledge.vue
  10. 174 0
      src/modules/analysis/components/baseConfig/DiagnoseConfig.vue
  11. 157 0
      src/modules/analysis/components/baseConfig/DimensionAbilityList.vue
  12. 59 0
      src/modules/analysis/components/baseConfig/DimensionConfig.vue
  13. 184 0
      src/modules/analysis/components/baseConfig/DimensionKnowledgeList.vue
  14. 140 0
      src/modules/analysis/components/baseConfig/ModifyAbilityComment.vue
  15. 213 0
      src/modules/analysis/components/baseConfig/ModifyAbilityDim.vue
  16. 143 0
      src/modules/analysis/components/baseConfig/ModifyKnowledgeComment.vue
  17. 302 0
      src/modules/analysis/components/baseConfig/ModifyKnowledgeDim.vue
  18. 109 0
      src/modules/analysis/components/baseConfig/ProficiencyEdit.vue
  19. 95 0
      src/modules/analysis/components/baseConfig/defaultComment.js
  20. 26 0
      src/modules/analysis/components/baseConfig/dimenData.js
  21. 16 0
      src/modules/analysis/router.js
  22. 198 0
      src/modules/analysis/views/AnalysisBatchManage.vue
  23. 143 0
      src/modules/analysis/views/DataInitManage.vue
  24. 2 1
      src/router.js

+ 105 - 0
src/modules/analysis/api.js

@@ -0,0 +1,105 @@
+import { $postParam, $post } from "@/plugins/axios";
+
+export const questionTeatherUserQuery = ({ courseCode, param }) => {
+  return $postParam("/api/admin/sys/user/user_list", { courseCode, param });
+};
+// user-manage
+export const userListPage = datas => {
+  return $postParam("/api/admin/sys/user/list", datas);
+};
+export const updateUser = datas => {
+  return $post("/api/admin/sys/user/save", datas);
+};
+export const ableUser = ({ id, enable }) => {
+  return $post("/api/admin/sys/user/enable", { id, enable });
+};
+export const resetPwd = id => {
+  return $post("/api/admin/sys/user/reset_password", { id });
+};
+export const updatePwd = datas => {
+  return $post("/api/admin/sys/user/update_password", datas);
+};
+export const userBindRoles = ({ id, roleIds }) => {
+  return $post("/api/admin/sys/user/bind_roles", { id, roleIds });
+};
+export const userRoleListPage = () => {
+  return $postParam("/api/admin/sys/role/list_to_user", {});
+};
+
+// role-manage
+export const roleListPage = datas => {
+  return $postParam("/api/admin/sys/role/list", datas);
+};
+export const ableRole = ({ id, enable }) => {
+  return $post("/api/admin/sys/role/enable", { id, enable });
+};
+export const updateRole = datas => {
+  return $post("/api/admin/sys/role/save", datas);
+};
+export const deleteRole = id => {
+  return $post("/api/admin/sys/role/remove", { id });
+};
+export const userBoundRoles = userId => {
+  return $postParam("/api/admin/sys/role/get_user_roles", { userId });
+};
+// menu-manage
+export const menuAuthList = datas => {
+  return $postParam("/api/admin/sys/privilege/list_auth", datas);
+};
+export const roleBoundPrivileges = roleId => {
+  return $postParam("/api/admin/sys/privilege/get_role_privileges", { roleId });
+};
+// organization-manage
+export const organizationList = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+export const updateOrganization = datas => {
+  return $post("/api/admin/sys/org/save", datas);
+};
+export const ableOrganization = ({ id, enable }) => {
+  return $post("/api/admin/sys/org/enable", { id, enable });
+};
+export const deleteOrganization = id => {
+  return $post("/api/admin/sys/org/remove", { id });
+};
+
+// data-init-manage
+export const dataInitList = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+export const updateKnowledgeDimension = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+
+// analysis-course-manage
+export const analysisBatchList = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+export const analysisBatchQuery = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+export const updateAnalysisBatch = datas => {
+  return $post("/api/admin/sys/org/save", datas);
+};
+export const deleteAnalysisBatch = ids => {
+  return $post("/api/admin/sys/org/list", { ids });
+};
+export const analysisBatchPaperList = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+export const addAnalysisBatchPaper = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+export const deleteAnalysisBatchPaper = ids => {
+  return $postParam("/api/admin/sys/org/list", { ids });
+};
+export const analysisPaperList = datas => {
+  return $postParam("/api/admin/sys/org/list", datas);
+};
+
+// common
+export const uploadFile = datas => {
+  return $post("/api/admin/common/file/upload", datas);
+};
+
+// system

+ 119 - 0
src/modules/analysis/components/ModifyAnalysisBatch.vue

@@ -0,0 +1,119 @@
+<template>
+  <el-dialog
+    class="modify-analysis-batch"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10vh"
+    width="540px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <div class="part-box part-box-pad part-box-border">
+      <el-form
+        ref="modalFormComp"
+        :model="modalForm"
+        :rules="rules"
+        label-width="100px"
+      >
+        <el-form-item prop="name" label="批次名称:">
+          <el-input
+            style="width:100%;"
+            v-model.trim="modalForm.name"
+            placeholder="请输入批次名称"
+            clearable
+          ></el-input>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button type="danger" @click="cancel" plain>取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { updateAnalysisBatch } from "../api";
+
+const initModalForm = {
+  id: null,
+  name: ""
+};
+
+export default {
+  name: "modify-analysis-batch",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "分析批次";
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: {},
+      rules: {
+        name: [
+          {
+            required: true,
+            message: "请输入批次名称",
+            trigger: "change"
+          },
+          {
+            max: 100,
+            message: "批次名称不能超过100",
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    async visibleChange() {
+      if (this.instance.id) {
+        this.modalForm = this.$objAssign(initModalForm, this.instance);
+      } else {
+        this.modalForm = { ...initModalForm };
+      }
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const datas = { ...this.modalForm };
+      const data = await updateAnalysisBatch(datas).catch(() => {});
+      this.isSubmit = false;
+      if (!data) return;
+
+      this.$emit("modified");
+      this.cancel();
+    }
+  }
+};
+</script>

+ 193 - 0
src/modules/analysis/components/ModifyAnalysisBatchPaper.vue

@@ -0,0 +1,193 @@
+<template>
+  <div class="modify-analysis-batch">
+    <el-dialog
+      :visible.sync="modalIsShow"
+      :title="title"
+      top="0px"
+      width="80%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      @opened="visibleChange"
+    >
+      <div class="part-box part-box-filter part-box-flex">
+        <el-form
+          ref="FilterForm"
+          label-position="left"
+          label-width="55px"
+          inline
+        >
+          <el-form-item label="学期:">
+            <semester-select v-model="filter.semester"></semester-select>
+          </el-form-item>
+          <el-form-item label="考试:">
+            <exam-select
+              v-model="filter.examId"
+              :semester="filter.semester"
+            ></exam-select>
+          </el-form-item>
+          <el-form-item label="课程:">
+            <course-select
+              v-model="filter.courseCode"
+              :exam-id="filter.examId"
+              inspect
+            ></course-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="toPage(1)">查询</el-button>
+          </el-form-item>
+        </el-form>
+        <div class="part-box-action">
+          <el-button type="danger" :loading="loading" @click="toBatchDelete"
+            >批量删除</el-button
+          >
+          <el-button type="primary" @click="toAdd">添加分析试卷</el-button>
+        </div>
+      </div>
+      <div class="part-box part-box-pad">
+        <el-table
+          ref="TableList"
+          :data="dataList"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column prop="semester" label="学期"></el-table-column>
+          <el-table-column prop="examName" label="考试"> </el-table-column>
+          <el-table-column prop="courseCode" label="课程(代码)" min-width="120">
+            <span slot-scope="scope">
+              {{ scope.row.courseName }}({{ scope.row.courseCode }})
+            </span>
+          </el-table-column>
+          <el-table-column prop="paperNumber" label="试卷编号">
+          </el-table-column>
+          <el-table-column prop="paperType" label="试卷类型"> </el-table-column>
+          <el-table-column prop="teachName" label="命题老师"> </el-table-column>
+          <el-table-column
+            class-name="action-column"
+            label="操作"
+            width="160px"
+            align="center"
+          >
+            <template slot-scope="scope">
+              <el-button
+                class="btn-danger"
+                type="text"
+                :disabled="loading"
+                @click="toDelete(scope.row)"
+                >删除</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="part-page">
+          <el-pagination
+            background
+            layout="total,prev, pager, next"
+            :current-page="current"
+            :total="total"
+            :page-size="size"
+            @current-change="toPage"
+          >
+          </el-pagination>
+        </div>
+      </div>
+      <div slot="footer"></div>
+    </el-dialog>
+
+    <!-- SelectAnalysisPaper -->
+    <select-analysis-paper
+      ref="SelectAnalysisPaper"
+      :batch-id="instance.id"
+      @modified="getList"
+    ></select-analysis-paper>
+  </div>
+</template>
+
+<script>
+import { analysisBatchPaperList, deleteAnalysisBatchPaper } from "../api";
+import SelectAnalysisPaper from "./SelectAnalysisPaper.vue";
+
+export default {
+  name: "modify-analysis-batch-paper",
+  components: { SelectAnalysisPaper },
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      filter: {
+        semester: "",
+        examId: "",
+        courseCode: ""
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      dataList: [],
+      curRow: {},
+      multipleSelection: [],
+      loading: false
+    };
+  },
+  computed: {
+    title() {
+      return `分析课程管理-${this.instance.name}`;
+    }
+  },
+  methods: {
+    async getList() {
+      const datas = {
+        ...this.filter,
+        batchId: this.instance.id,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      const data = await analysisBatchPaperList(datas);
+      this.dataList = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    toAdd() {},
+    handleSelectionChange(val) {
+      this.multipleSelection = val.map(item => item.id);
+    },
+    async toBatchDelete() {
+      if (!this.multipleSelection.length) {
+        this.$message.error("请选择要删除的批次!");
+        return;
+      }
+
+      const confirm = await this.$confirm(`确定要删除选中的试卷吗?`, "提示", {
+        type: "warning"
+      }).catch(() => {});
+      if (confirm !== "confirm") return;
+
+      await deleteAnalysisBatchPaper(this.multipleSelection);
+      this.$message.success("删除成功!");
+      this.deletePageLastItem();
+    },
+    async toDelete(row) {
+      const confirm = await this.$confirm(
+        `确定要删除试卷【${row.paperNumber}】吗?`,
+        "提示",
+        {
+          type: "warning"
+        }
+      ).catch(() => {});
+      if (confirm !== "confirm") return;
+
+      await deleteAnalysisBatchPaper([row.id]);
+      this.$message.success("删除成功!");
+      this.deletePageLastItem();
+    }
+  }
+};
+</script>

+ 109 - 0
src/modules/analysis/components/ModifyBaseConfig.vue

@@ -0,0 +1,109 @@
+<template>
+  <el-dialog
+    custom-class="modify-base-config"
+    :visible.sync="modalIsShow"
+    title="基础配置"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    fullscreen
+    @opened="visibleChange"
+  >
+    <div slot="title">
+      基础配置<span class="color-gray-2 ml-2">{{ insCont }}</span>
+    </div>
+    <div class="part-box part-box-pad">
+      <el-steps :active="curStep" align-center>
+        <el-step v-for="(item, ind) in steps" :key="item.val">
+          <el-button
+            slot="title"
+            type="text"
+            :disabled="item.disabled"
+            @click="changeStep(ind)"
+            >{{ item.name }}</el-button
+          >
+        </el-step>
+      </el-steps>
+    </div>
+
+    <div class="part-box part-box-pad">
+      <component :is="compName" :course="instance"></component>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import DimensionConfig from "./baseConfig/DimensionConfig.vue";
+import BlueprintConfig from "./baseConfig/BlueprintConfig.vue";
+import DiagnoseConfig from "./baseConfig/DiagnoseConfig.vue";
+import CommentConfig from "./baseConfig/CommentConfig.vue";
+
+export default {
+  name: "modify-base-config",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  components: {
+    DimensionConfig,
+    BlueprintConfig,
+    DiagnoseConfig,
+    CommentConfig
+  },
+  data() {
+    return {
+      modalIsShow: true,
+      isSubmit: false,
+      curStep: 0,
+      steps: [
+        {
+          name: "知识/能力维度设置",
+          val: "dimension",
+          disabled: false
+        },
+        {
+          name: "命题蓝图设置",
+          val: "blueprint",
+          disabled: false
+        },
+        {
+          name: "诊断规则定义",
+          val: "diagnose",
+          disabled: false
+        },
+        {
+          name: "评价模型设置",
+          val: "comment",
+          disabled: false
+        }
+      ]
+    };
+  },
+  computed: {
+    compName() {
+      const stepVal = this.steps[this.curStep].val;
+      return `${stepVal}-config`;
+    },
+    insCont() {
+      return `${this.instance.semester}-${this.instance.examName}-${this.instance.courseName}(${this.instance.courseCode})`;
+    }
+  },
+  methods: {
+    visibleChange() {},
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    changeStep(ind) {
+      if (ind === this.curStep) return;
+      this.curStep = ind;
+    }
+  }
+};
+</script>

+ 257 - 0
src/modules/analysis/components/SelectAnalysisPaper.vue

@@ -0,0 +1,257 @@
+<template>
+  <el-dialog
+    class="select-analysis-paper"
+    :visible.sync="modalIsShow"
+    title="选择分析试卷"
+    top="0px"
+    width="80%"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form ref="FilterForm" label-position="left" label-width="55px" inline>
+        <el-form-item label="学期:">
+          <semester-select v-model="filter.semester"></semester-select>
+        </el-form-item>
+        <el-form-item label="考试:">
+          <exam-select
+            v-model="filter.examId"
+            :semester="filter.semester"
+          ></exam-select>
+        </el-form-item>
+        <el-form-item label="课程:">
+          <course-select
+            v-model="filter.courseCode"
+            :exam-id="filter.examId"
+            inspect
+          ></course-select>
+        </el-form-item>
+        <el-form-item>
+          <el-input
+            v-model="filter.name"
+            placeholder="请输入命题老师姓名"
+          ></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="toPage(1)">查询</el-button>
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action">
+        <el-button type="danger" :loading="loading" @click="toBatchDelete"
+          >批量删除</el-button
+        >
+        <el-button type="primary" @click="toAdd">添加分析试卷</el-button>
+      </div>
+    </div>
+
+    <div class="mb-4 tab-btns">
+      <el-button
+        v-for="tab in tabs"
+        :key="tab.val"
+        size="medium"
+        :type="curTab == tab.val ? 'primary' : 'default'"
+        @click="selectMenu(tab.val)"
+        >{{ tab.name }}
+        <span v-if="curTab === 'selected'">({{ selectedPapers.length }})</span>
+      </el-button>
+    </div>
+
+    <div v-if="curTab === 'query'" class="part-box part-box-pad">
+      <el-table
+        ref="TableList"
+        :data="dataList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column prop="semester" label="学期"></el-table-column>
+        <el-table-column prop="examName" label="考试"> </el-table-column>
+        <el-table-column prop="courseCode" label="课程(代码)" min-width="120">
+          <span slot-scope="scope">
+            {{ scope.row.courseName }}({{ scope.row.courseCode }})
+          </span>
+        </el-table-column>
+        <el-table-column prop="collegeName" label="开课学院"> </el-table-column>
+        <el-table-column prop="teachName" label="命题老师"> </el-table-column>
+        <el-table-column prop="paperNumber" label="试卷编号"> </el-table-column>
+        <el-table-column prop="paperType" label="试卷类型"> </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total,prev, pager, next"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+        >
+        </el-pagination>
+      </div>
+    </div>
+    <div v-else class="part-box part-box-pad">
+      <el-table ref="SelectedTableList" :data="selectedPapers">
+        <el-table-column prop="semester" label="学期"></el-table-column>
+        <el-table-column prop="examName" label="考试"> </el-table-column>
+        <el-table-column prop="courseCode" label="课程(代码)" min-width="120">
+          <span slot-scope="scope">
+            {{ scope.row.courseName }}({{ scope.row.courseCode }})
+          </span>
+        </el-table-column>
+        <el-table-column prop="collegeName" label="开课学院"> </el-table-column>
+        <el-table-column prop="teachName" label="命题老师"> </el-table-column>
+        <el-table-column prop="paperNumber" label="试卷编号"> </el-table-column>
+        <el-table-column prop="paperType" label="试卷类型"> </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="80px"
+          align="center"
+        >
+          <template slot-scope="scope">
+            <el-button
+              class="btn-danger"
+              type="text"
+              @click="toDelete(scope.row)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <div slot="footer">
+      <el-button type="primary" :loading="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button type="danger" @click="cancel" plain>取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { analysisPaperList, addAnalysisBatchPaper } from "../api";
+
+export default {
+  name: "select-analysis-paper",
+  props: {
+    batchId: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      filter: {
+        semester: "",
+        examId: "",
+        courseCode: "",
+        name: ""
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      curTab: "query",
+      tabs: [
+        {
+          name: "列表",
+          val: "query"
+        },
+        {
+          name: "已选",
+          val: "selected"
+        }
+      ],
+      dataList: [],
+      selectedPapers: [],
+      selectedPaperIds: [],
+      isSubmit: false
+    };
+  },
+  methods: {
+    visibleChange() {
+      this.curTab = "query";
+      this.selectedPapers = [];
+      this.selectedPaperIds = [];
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      const data = await analysisPaperList(datas);
+      this.dataList = data.records;
+      this.total = data.total;
+
+      this.$nextTick(() => this.changeCurListSelect());
+    },
+    changeCurListSelect() {
+      const curPageSelectedList = this.dataList.filter(item =>
+        this.selectedPaperIds.includes(item.id)
+      );
+      this.$refs.TableList.clearSelection();
+      this.$refs.TableList.toggleRowSelection(curPageSelectedList, true);
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    selectMenu(tab) {
+      this.curTab = tab;
+      if (tab === "query") {
+        this.$nextTick(() => this.changeCurListSelect());
+      }
+    },
+    toDelete(row) {
+      this.selectedPapers = this.selectedPapers.filter(
+        item => item.id !== row.id
+      );
+      this.updateSelectedIds();
+    },
+    updateSelectedIds() {
+      this.selectedPaperIds = this.selectedPapers.map(item => item.id);
+    },
+    handleSelectionChange(val) {
+      const seletedIds = val.map(item => item.id);
+      this.dataList.forEach(item => {
+        const isSelected = seletedIds.includes(item.id);
+        if (isSelected) {
+          if (this.selectedPaperIds.includes(item.id)) return;
+          this.selectedPapers.push({ ...item });
+        } else {
+          if (!this.selectedPaperIds.includes(item.id)) return;
+          const pos = this.selectedPapers.findIndex(p => p.id === item.id);
+          this.selectedPapers.splice(pos, 1);
+        }
+      });
+      this.updateSelectedIds();
+    },
+    async submit() {
+      if (!this.selectedPapers.length) {
+        this.$message.error("请选择试卷");
+        return;
+      }
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+
+      const res = await addAnalysisBatchPaper({
+        batchId: this.batchId,
+        paperIds: this.selectedPaperIds
+      }).catch(() => {});
+      this.isSubmit = false;
+      if (!res) return;
+
+      this.$message.success("添加成功!");
+      this.cancel();
+      this.$emit("modified");
+    }
+  }
+};
+</script>

+ 96 - 0
src/modules/analysis/components/baseConfig/BlueprintConfig.vue

@@ -0,0 +1,96 @@
+<template>
+  <div class="blueprint-config">
+    <div class="mb-4 box-justify">
+      <el-button type="success" @click="toImport">导入</el-button>
+    </div>
+
+    <div class="part-box part-box-border-bold">
+      <el-table ref="TableList" :data="dataList">
+        <el-table-column prop="courseCode" label="课程代码"></el-table-column>
+        <el-table-column prop="courseName" label="课程名称"> </el-table-column>
+        <el-table-column prop="courseName" label="试卷编号"> </el-table-column>
+        <el-table-column prop="courseName" label="大题号"> </el-table-column>
+        <el-table-column prop="courseName" label="小题号"> </el-table-column>
+        <el-table-column prop="courseName" label="题目类型"> </el-table-column>
+        <el-table-column prop="courseName" label="题目满分"> </el-table-column>
+        <el-table-column prop="courseName" label="计分规则"> </el-table-column>
+        <el-table-column prop="knowledgeDim" label="知识模块">
+          <template slot-scope="scope">
+            <el-select
+              v-model="scope.row.knowledgeDim"
+              placeholder="请选择"
+              filterable
+              clearable
+              multiple
+            >
+              <el-option
+                v-for="item in knowledgeList"
+                :key="item.code"
+                :value="item.code"
+                :label="item.name"
+              >
+              </el-option>
+            </el-select>
+          </template>
+        </el-table-column>
+        <el-table-column prop="abilityDim" label="能力模块">
+          <template slot-scope="scope">
+            <el-select
+              v-model="scope.row.abilityDim"
+              placeholder="请选择"
+              filterable
+              clearable
+              multiple
+            >
+              <el-option
+                v-for="item in abilityList"
+                :key="item.code"
+                :value="item.code"
+                :label="item.name"
+              >
+              </el-option>
+            </el-select>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <import-file
+      ref="ImportFile"
+      title="上传文件"
+      :upload-url="uploadUrl"
+      :download-url="downloadUrl"
+      :download-filename="downloadFilename"
+      :format="['xls', 'xlsx']"
+      @upload-success="fileUploaded"
+    >
+    </import-file>
+  </div>
+</template>
+
+<script>
+import ImportFile from "@/components/ImportFile";
+
+export default {
+  name: "blueprint-config",
+  components: { ImportFile },
+  data() {
+    return {
+      dataList: [],
+      knowledgeList: [],
+      abilityList: [],
+      // upload
+      uploadUrl: "yourUploadPath",
+      downloadUrl: "",
+      downloadFilename: ""
+    };
+  },
+  methods: {
+    getList() {},
+    toImport() {
+      this.$refs.ImportFile.open();
+    },
+    fileUploaded() {}
+  }
+};
+</script>

+ 134 - 0
src/modules/analysis/components/baseConfig/CommentAbility.vue

@@ -0,0 +1,134 @@
+<template>
+  <div class="comment-ability">
+    <el-table ref="TableList" :data="dataList">
+      <el-table-column prop="level" label="等级" width="60"></el-table-column>
+      <el-table-column prop="level" label="划分规划" width="300">
+        <div
+          slot-scope="scope"
+          :class="[
+            'rate-input',
+            { 'rate-input-offset-left': scope.$index === 0 }
+          ]"
+        >
+          <el-input-number
+            v-if="scope.$index !== 0"
+            v-model="scope.row.startRate"
+            placeholder="请输入"
+            :min="0"
+            :max="100"
+            :step="1"
+            step-strictly
+            size="small"
+            :controls="false"
+            @change="rateChange"
+          ></el-input-number>
+          <span v-if="scope.$index !== 0">≤</span>
+          <span>百分位等级TOP</span>
+          <span>≤</span>
+          <el-input-number
+            v-model="scope.row.endRate"
+            placeholder="请输入"
+            :min="0"
+            :max="100"
+            :step="1"
+            step-strictly
+            size="small"
+            :controls="false"
+            @change="rateChange"
+          ></el-input-number>
+        </div>
+      </el-table-column>
+      <el-table-column
+        prop="levelDesc"
+        label="水平层次"
+        width="140"
+      ></el-table-column>
+      <el-table-column prop="result" label="诊断结果"></el-table-column>
+      <el-table-column prop="suggest" label="学习建议"></el-table-column>
+      <el-table-column
+        class-name="action-column"
+        label="操作"
+        width="80px"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-button class="btn-primary" type="text" @click="toEdit(scope.row)"
+            >编辑</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <p v-if="errorMsg" class="tips-info tips-error">{{ errorMsg }}</p>
+
+    <!-- ModifyAbilityComment -->
+    <modify-ability-comment
+      ref="ModifyAbilityComment"
+      :instance="curRow"
+      :modified="modified"
+    ></modify-ability-comment>
+  </div>
+</template>
+
+<script>
+import { initAbilityList } from "./defaultComment";
+import ModifyAbilityComment from "./ModifyAbilityComment.vue";
+
+export default {
+  name: "comment-ability",
+  components: { ModifyAbilityComment },
+  props: {
+    rates: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  data() {
+    return {
+      dataList: [],
+      curRow: {},
+      errorMsg: ""
+    };
+  },
+  mounted() {
+    const data = this.rates.length ? this.rates : initAbilityList;
+    this.dataList = data.map(item => {
+      return { ...item };
+    });
+  },
+  methods: {
+    toEdit(row) {
+      this.curRow = row;
+      this.$refs.ModifyAbilityComment.open();
+    },
+    modified(data) {
+      const ind = this.dataList.findIndex(item => item.level === data.level);
+      this.dataList[ind] = this.$objAssign(this.dataList[ind], data);
+    },
+    rateChange() {
+      const isEmpty = num => !num && num !== 0;
+
+      if (
+        this.dataList.some(
+          item => isEmpty(item.startRate) || isEmpty(item.endRate)
+        )
+      ) {
+        this.errorMsg = "请完成划分规则";
+        return;
+      }
+
+      for (let i = 0; i < this.dataList.length; i++) {
+        const item = this.dataList[i];
+        if (i) {
+          const prevItem = this.dataList[i - 1];
+          if (prevItem.endRate + 1 !== item.startRate) {
+            this.errorMsg = "请保证区间连续";
+            return;
+          }
+        }
+      }
+    }
+  }
+};
+</script>

+ 59 - 0
src/modules/analysis/components/baseConfig/CommentConfig.vue

@@ -0,0 +1,59 @@
+<template>
+  <div class="comment-config">
+    <div class="mb-4 tab-btns">
+      <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>
+
+    <component :is="compName" :course="course"></component>
+  </div>
+</template>
+
+<script>
+import CommentKnowledge from "./CommentKnowledge.vue";
+import CommentAbility from "./CommentAbility.vue";
+
+export default {
+  name: "comment-config",
+  components: { CommentKnowledge, CommentAbility },
+  props: {
+    course: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      curTab: "knowledge",
+      tabs: [
+        {
+          name: "知识维度",
+          val: "knowledge"
+        },
+        {
+          name: "能力维度",
+          val: "ability"
+        }
+      ]
+    };
+  },
+  computed: {
+    compName() {
+      return `comment-${this.curTab}`;
+    }
+  },
+  methods: {
+    selectMenu(tab) {
+      this.curTab = tab;
+    }
+  }
+};
+</script>

+ 134 - 0
src/modules/analysis/components/baseConfig/CommentKnowledge.vue

@@ -0,0 +1,134 @@
+<template>
+  <div class="comment-knowledge">
+    <el-table ref="TableList" :data="dataList">
+      <el-table-column prop="level" label="等级" width="60"></el-table-column>
+      <el-table-column prop="level" label="划分规划" width="280">
+        <div
+          slot-scope="scope"
+          :class="[
+            'rate-input',
+            { 'rate-input-offset-left': scope.$index === dataList.length - 1 }
+          ]"
+        >
+          <el-input-number
+            v-if="scope.$index !== dataList.length - 1"
+            v-model="scope.row.startRate"
+            placeholder="请输入"
+            :min="0"
+            :max="100"
+            :step="1"
+            step-strictly
+            size="small"
+            :controls="false"
+            @change="rateChange"
+          ></el-input-number>
+          <span v-if="scope.$index !== dataList.length - 1">≤</span>
+          <span>个人得分率</span>
+          <span v-if="scope.$index !== 0">≤</span>
+          <el-input-number
+            v-if="scope.$index !== 0"
+            v-model="scope.row.endRate"
+            placeholder="请输入"
+            :min="0"
+            :max="100"
+            :step="1"
+            step-strictly
+            size="small"
+            :controls="false"
+            @change="rateChange"
+          ></el-input-number>
+        </div>
+      </el-table-column>
+      <el-table-column
+        prop="levelDesc"
+        label="水平层次"
+        width="140"
+      ></el-table-column>
+      <el-table-column prop="result" label="诊断结果"></el-table-column>
+      <el-table-column prop="suggest" label="学习建议"></el-table-column>
+      <el-table-column
+        class-name="action-column"
+        label="操作"
+        width="80px"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-button class="btn-primary" type="text" @click="toEdit(scope.row)"
+            >编辑</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <p v-if="errorMsg" class="tips-info tips-error">{{ errorMsg }}</p>
+    <!-- ModifyKnowledgeComment -->
+    <modify-knowledge-comment
+      ref="ModifyKnowledgeComment"
+      :instance="curRow"
+      :modified="modified"
+    ></modify-knowledge-comment>
+  </div>
+</template>
+
+<script>
+import { initKnowledgeList } from "./defaultComment";
+import ModifyKnowledgeComment from "./ModifyKnowledgeComment.vue";
+
+export default {
+  name: "comment-knowledge",
+  components: { ModifyKnowledgeComment },
+  props: {
+    rates: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  data() {
+    return {
+      dataList: [],
+      curRow: {},
+      errorMsg: ""
+    };
+  },
+  mounted() {
+    const data = this.rates.length ? this.rates : initKnowledgeList;
+    this.dataList = data.map(item => {
+      return { ...item };
+    });
+  },
+  methods: {
+    toEdit(row) {
+      this.curRow = row;
+      this.$refs.ModifyKnowledgeComment.open();
+    },
+    modified(data) {
+      const ind = this.dataList.findIndex(item => item.level === data.level);
+      this.dataList[ind] = this.$objAssign(this.dataList[ind], data);
+    },
+    rateChange() {
+      const isEmpty = num => !num && num !== 0;
+
+      if (
+        this.dataList.some(
+          item => isEmpty(item.startRate) || isEmpty(item.endRate)
+        )
+      ) {
+        this.errorMsg = "请完成划分规则";
+        return;
+      }
+
+      for (let i = 0; i < this.dataList.length; i++) {
+        const item = this.dataList[i];
+        if (i) {
+          const prevItem = this.dataList[i - 1];
+          if (prevItem.startRate - 1 !== item.endRate) {
+            this.errorMsg = "请保证区间连续";
+            return;
+          }
+        }
+      }
+    }
+  }
+};
+</script>

+ 174 - 0
src/modules/analysis/components/baseConfig/DiagnoseConfig.vue

@@ -0,0 +1,174 @@
+<template>
+  <div class="diagnose-config">
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      label-width="180px"
+    >
+      <el-form-item prop="knowledgeTitle" label="知识:">
+        <el-input
+          v-model.trim="modalForm.knowledgeTitle"
+          placeholder="知识"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="rateSet" label="二级维度的精熟度定义:">
+        <div class="part-box part-box-pad part-box-border-bold">
+          <proficiency-edit
+            :rates="modalForm.rateSet"
+            @data-change="rateSetChange"
+          ></proficiency-edit>
+        </div>
+      </el-form-item>
+      <el-form-item prop="abilityTitle" label="能力:">
+        <el-input
+          v-model.trim="modalForm.abilityTitle"
+          placeholder="能力"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="isfuf" label="是否呈现赋分:">
+        <el-radio-group v-model="modalForm.isfuf">
+          <el-radio
+            v-for="(val, key) in BOOLEAN_TYPE"
+            :key="key"
+            :label="key * 1"
+            >{{ val }}</el-radio
+          >
+        </el-radio-group>
+        <p class="tips-info">
+          说明:若选择“是”,则考后需提供学生的赋分成绩(学号、总分),报告中的分值显示赋分后的成绩分数;若选择“否”,则报告中的分值显示卷面原始分。
+        </p>
+      </el-form-item>
+      <el-form-item prop="fullScore" label="满分:">
+        <el-input-number
+          v-model="modalForm.fullScore"
+          placeholder="请输入满分,如100"
+          :min="1"
+          :max="9999"
+          :step="1"
+          step-strictly
+          :controls="false"
+        ></el-input-number>
+        <p class="tips-info">
+          说明:若显示赋分,则填写赋分满分分值,否则填写卷面原始分满分分值。
+        </p>
+      </el-form-item>
+      <el-form-item prop="passScore" label="及格分:">
+        <el-input-number
+          v-model="modalForm.passScore"
+          placeholder="请输入及格分,如60"
+          :min="1"
+          :max="9999"
+          :step="1"
+          step-strictly
+          :controls="false"
+        ></el-input-number>
+        <p class="tips-info">
+          说明:成绩分数≥及格分数线,报告中的结果显示“通过”,否则为“不通过”。
+        </p>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { BOOLEAN_TYPE } from "@/constants/enumerate";
+import ProficiencyEdit from "./ProficiencyEdit.vue";
+
+const initModalForm = {
+  id: "",
+  knowledgeTitle: "课程标准规定的学科内容",
+  abilityTitle: "经学习与训练内化而成的心理结构",
+  isfuf: 0,
+  fullScore: 100,
+  passScore: 100,
+  rateSet: []
+};
+
+export default {
+  name: "diagnose-config",
+  components: { ProficiencyEdit },
+  data() {
+    const isEmpty = num => !num && num !== 0;
+
+    const rateSetValidator = (rule, value, callback) => {
+      if (
+        value.some(item => isEmpty(item.startRate) || isEmpty(item.endRate))
+      ) {
+        return callback(new Error("请完成精熟度定义"));
+      }
+
+      for (let i = 0; i < value.length; i++) {
+        const item = value[i];
+        if (i) {
+          const prevItem = value[i - 1];
+          if (prevItem.startRate - 1 !== item.endRate)
+            return callback(new Error("请保证区间连续"));
+        }
+      }
+
+      callback();
+    };
+    return {
+      modalForm: { ...initModalForm },
+      BOOLEAN_TYPE,
+      rules: {
+        knowledgeTitle: [
+          {
+            required: true,
+            message: "请输入知识",
+            trigger: "change"
+          },
+          {
+            max: 100,
+            message: "知识字数不能超过100",
+            trigger: "change"
+          }
+        ],
+        abilityTitle: [
+          {
+            required: true,
+            message: "请输入能力",
+            trigger: "change"
+          },
+          {
+            max: 100,
+            message: "能力字数不能超过100",
+            trigger: "change"
+          }
+        ],
+        fullScore: [
+          {
+            required: true,
+            message: "请输入满分",
+            trigger: "change"
+          }
+        ],
+        passScore: [
+          {
+            required: true,
+            message: "请输入及格分",
+            trigger: "change"
+          }
+        ],
+        rateSet: [
+          {
+            validator: rateSetValidator,
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    getList() {},
+    rateSetChange(data) {
+      this.modalForm.rateSet = data;
+      this.$refs.modalFormComp.validateField("rateSet");
+    },
+    async submit() {}
+  }
+};
+</script>

+ 157 - 0
src/modules/analysis/components/baseConfig/DimensionAbilityList.vue

@@ -0,0 +1,157 @@
+<template>
+  <div class="dimension-ability-list">
+    <div class="mb-4 box-justify">
+      <el-button type="success" @click="toImport">导入</el-button>
+      <el-button type="primary" @click="toAdd">新增</el-button>
+    </div>
+
+    <div class="part-box part-box-border-bold dimension-table">
+      <el-table ref="TableList" :data="dataList">
+        <el-table-column prop="courseCode" label="课程代码"></el-table-column>
+        <el-table-column prop="courseName" label="课程名称"> </el-table-column>
+        <el-table-column prop="courseName" label="一级能力维度">
+        </el-table-column>
+        <el-table-column prop="courseName" label="一级维度编号">
+        </el-table-column>
+        <el-table-column prop="courseName" label="一级维度术语解释">
+        </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="160px"
+          align="center"
+        >
+          <template slot-scope="scope">
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toEdit(scope.row)"
+              >编辑</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toDelete(scope)"
+              >删除</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading || scope.row.isFirstSec"
+              @click="toUp(scope)"
+              >上移</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading || scope.row.isLastSec"
+              @click="toDown(scope)"
+              >下移</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <import-file
+      ref="ImportFile"
+      title="上传文件"
+      :upload-url="uploadUrl"
+      :upload-data="uploadData"
+      :download-url="downloadUrl"
+      :download-filename="downloadFilename"
+      :format="['xls', 'xlsx']"
+      @upload-success="fileUploaded"
+    >
+    </import-file>
+    <!-- ModifyAbilityDim -->
+    <modify-ability-dim
+      ref="ModifyAbilityDim"
+      :instance="curRow"
+      :dict-data="dataList"
+      @modified="modified"
+    ></modify-ability-dim>
+  </div>
+</template>
+
+<script>
+import ImportFile from "@/components/ImportFile";
+import ModifyAbilityDim from "./ModifyAbilityDim.vue";
+
+export default {
+  name: "dimension-ability-list",
+  components: { ImportFile, ModifyAbilityDim },
+  props: {
+    course: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      dataList: [],
+      curRow: {},
+      loading: false,
+      // upload
+      uploadUrl: "yourUploadPath",
+      downloadUrl: "/path/要下载的文件.xls",
+      downloadFilename: "要下载的文件.xls",
+      uploadData: {}
+    };
+  },
+  mounted() {
+    this.getDict();
+  },
+  methods: {
+    getList() {},
+    getDict() {},
+    toImport() {
+      this.$refs.ImportFile.open();
+    },
+    fileUploaded() {
+      this.$message.success("导入成功!");
+      this.getList();
+    },
+    modified(data) {
+      this.dataList.push(data);
+      // TODO:排序
+    },
+    toAdd() {
+      this.curRow = {
+        courseCode: this.course.courseCode,
+        courseName: this.course.courseName
+      };
+      this.$refs.ModifyAbilityDim.open();
+    },
+    toEdit(row) {
+      this.curRow = row;
+      this.$refs.ModifyAbilityDim.open();
+    },
+    toDelete({ $index }) {
+      this.dataList.splice($index, 1);
+    },
+    toUp({ row, $index }) {
+      const pos = $index;
+      const curRowCode = row.firstCode;
+      const prevRowCode = this.dataList[$index - 1].firstCode;
+      this.dataList.splice(pos, 1);
+      this.dataList.splice(pos - 1, 0, row);
+      this.dataList[pos].firstCode = curRowCode;
+      this.dataList[pos - 1].firstCode = prevRowCode;
+    },
+    toDown({ row, $index }) {
+      const pos = $index;
+      const curRowCode = row.firstCode;
+      const nextRowCode = this.dataList[$index + 1].firstCode;
+      this.dataList.splice(pos, 1);
+      this.dataList.splice(pos, 0, row);
+      this.dataList[pos].firstCode = curRowCode;
+      this.dataList[pos + 1].firstCode = nextRowCode;
+    }
+  }
+};
+</script>

+ 59 - 0
src/modules/analysis/components/baseConfig/DimensionConfig.vue

@@ -0,0 +1,59 @@
+<template>
+  <div class="dimension-config">
+    <div class="mb-4 tab-btns">
+      <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>
+
+    <component :is="compName" :course="course"></component>
+  </div>
+</template>
+
+<script>
+import DimensionKnowledgeList from "./DimensionKnowledgeList.vue";
+import DimensionAbilityList from "./DimensionAbilityList.vue";
+
+export default {
+  name: "dimension-config",
+  components: { DimensionKnowledgeList, DimensionAbilityList },
+  props: {
+    course: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      curTab: "knowledge",
+      tabs: [
+        {
+          name: "知识维度",
+          val: "knowledge"
+        },
+        {
+          name: "能力维度",
+          val: "ability"
+        }
+      ]
+    };
+  },
+  computed: {
+    compName() {
+      return `dimension-${this.curTab}-list`;
+    }
+  },
+  methods: {
+    selectMenu(tab) {
+      this.curTab = tab;
+    }
+  }
+};
+</script>

+ 184 - 0
src/modules/analysis/components/baseConfig/DimensionKnowledgeList.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="dimension-knowledge-list">
+    <div class="mb-4 box-justify">
+      <el-button type="success" @click="toImport">导入</el-button>
+      <el-button type="primary" @click="toAdd">新增</el-button>
+    </div>
+
+    <div class="part-box part-box-border-bold dimension-table">
+      <el-table ref="TableList" :data="dataList">
+        <el-table-column prop="courseCode" label="课程代码"></el-table-column>
+        <el-table-column prop="courseName" label="课程名称"> </el-table-column>
+        <el-table-column prop="firstName" label="一级知识维度">
+        </el-table-column>
+        <el-table-column prop="firstCode" label="一级维度编号">
+        </el-table-column>
+        <el-table-column prop="secondName" label="二级知识维度">
+        </el-table-column>
+        <el-table-column prop="secondCode" label="二级维度编号">
+        </el-table-column>
+        <el-table-column prop="firsetNameDesc" label="一级维度术语解释">
+        </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="180px"
+          align="center"
+        >
+          <template slot-scope="scope">
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toEdit(scope.row)"
+              >编辑</el-button
+            >
+            <el-button
+              class="btn-danger"
+              type="text"
+              :disabled="loading"
+              @click="toDelete(scope)"
+              >删除</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading || scope.row.isFirstSec"
+              @click="toUp(scope)"
+              >上移</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading || scope.row.isLastSec"
+              @click="toDown(scope)"
+              >下移</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <import-file
+      ref="ImportFile"
+      title="上传文件"
+      :upload-url="uploadUrl"
+      :upload-data="uploadData"
+      :download-url="downloadUrl"
+      :download-filename="downloadFilename"
+      :format="['xls', 'xlsx']"
+      @upload-success="fileUploaded"
+    >
+    </import-file>
+    <!-- ModifyKnowledgeDim -->
+    <modify-knowledge-dim
+      ref="ModifyKnowledgeDim"
+      :instance="curRow"
+      :dict-data="dataDict"
+      @modified="modified"
+    ></modify-knowledge-dim>
+  </div>
+</template>
+
+<script>
+import ImportFile from "@/components/ImportFile";
+import dimenData from "./dimenData";
+import ModifyKnowledgeDim from "./ModifyKnowledgeDim.vue";
+
+export default {
+  name: "dimension-knowledge-list",
+  components: { ImportFile, ModifyKnowledgeDim },
+  props: {
+    course: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      dataList: dimenData,
+      // dataList: [],
+      dataDict: [],
+      curRow: {},
+      loading: false,
+      // upload
+      uploadUrl: "yourUploadPath",
+      downloadUrl: "/path/要下载的文件.xls",
+      downloadFilename: "要下载的文件.xls",
+      uploadData: {}
+    };
+  },
+  mounted() {
+    this.getDict();
+  },
+  methods: {
+    getList() {},
+    getDict() {
+      let dataDict = {};
+      this.dataList.forEach(item => {
+        if (!dataDict[item.firstCode]) {
+          dataDict[item.firstCode] = {
+            name: item.firstName,
+            code: item.firstCode,
+            children: []
+          };
+        }
+        dataDict[item.firstCode].children.push({
+          name: item.secondName,
+          code: item.secondCode
+        });
+      });
+      this.dataDict = Object.values(dataDict);
+    },
+    toImport() {
+      this.$refs.ImportFile.open();
+    },
+    fileUploaded() {
+      this.$message.success("导入成功!");
+      this.getList();
+    },
+    modified(data) {
+      this.dataList.push(data);
+      // TODO:排序
+    },
+    toAdd() {
+      this.curRow = {
+        courseCode: this.course.courseCode,
+        courseName: this.course.courseName
+      };
+      this.$refs.ModifyKnowledgeDim.open();
+    },
+    toEdit(row) {
+      this.curRow = row;
+      this.$refs.ModifyKnowledgeDim.open();
+    },
+    toDelete({ $index }) {
+      this.dataList.splice($index, 1);
+    },
+    toUp({ row, $index }) {
+      const pos = $index;
+      const rowSecondInd = row.secondInd;
+      const rowFirstCode = row.firstCode;
+      this.dataList.splice(pos, 1);
+      this.dataList.splice(pos - 1, 0, row);
+      this.dataList[pos - 1].secondInd = rowSecondInd - 1;
+      this.dataList[pos - 1].secondCode = `${rowFirstCode}${rowSecondInd - 1}`;
+      this.dataList[pos].secondInd = rowSecondInd;
+      this.dataList[pos].secondCode = `${rowFirstCode}${rowSecondInd}`;
+    },
+    toDown({ row, $index }) {
+      const pos = $index;
+      const rowSecondInd = row.secondInd;
+      const rowFirstCode = row.firstCode;
+      this.dataList.splice(pos, 1);
+      this.dataList.splice(pos, 0, row);
+      this.dataList[pos + 1].secondInd = rowSecondInd + 1;
+      this.dataList[pos + 1].secondCode = `${rowFirstCode}${rowSecondInd + 1}`;
+      this.dataList[pos].secondInd = rowSecondInd;
+      this.dataList[pos].secondCode = `${rowFirstCode}${rowSecondInd}`;
+    }
+  }
+};
+</script>

+ 140 - 0
src/modules/analysis/components/baseConfig/ModifyAbilityComment.vue

@@ -0,0 +1,140 @@
+<template>
+  <el-dialog
+    class="modify-ability-comment"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10vh"
+    width="700px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      label-width="100px"
+    >
+      <el-form-item label="等级:">
+        {{ modalForm.level }}
+      </el-form-item>
+      <el-form-item label="水平层次:">
+        {{ modalForm.levelDesc }}
+      </el-form-item>
+      <el-form-item label="划分规则:">
+        <p v-if="modalForm.level === 'A'">
+          百分位等级TOP≤{{ modalForm.endRate }}%
+        </p>
+        <p v-else>
+          {{ modalForm.startRate }}%≤百分位等级TOP≤{{ modalForm.endRate }}%
+        </p>
+      </el-form-item>
+      <el-form-item prop="result" label="诊断结果:">
+        <el-input
+          v-model.trim="modalForm.result"
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 5 }"
+          placeholder="请输入诊断结果"
+          maxlength="9999"
+          show-word-limit
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="suggest" label="学习建议:">
+        <el-input
+          v-model.trim="modalForm.suggest"
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 5 }"
+          placeholder="请输入学习建议"
+          maxlength="9999"
+          show-word-limit
+        ></el-input>
+      </el-form-item>
+    </el-form>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button type="danger" @click="cancel" plain>取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+const initModalForm = {
+  id: null,
+  level: "",
+  levelDesc: "",
+  startRate: "",
+  endRate: "",
+  result: "",
+  suggest: ""
+};
+
+export default {
+  name: "modify-ability-comment",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "划分规则";
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: {},
+      rules: {
+        result: [
+          {
+            required: true,
+            message: "请输入诊断结果",
+            trigger: "change"
+          }
+        ],
+        suggest: [
+          {
+            required: true,
+            message: "请输入学习建议",
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    initData(val) {
+      this.modalForm = this.$objAssign(initModalForm, val);
+    },
+    visibleChange() {
+      this.initData(this.instance);
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      this.$emit("modified", this.modalForm);
+      this.cancel();
+    }
+  }
+};
+</script>

+ 213 - 0
src/modules/analysis/components/baseConfig/ModifyAbilityDim.vue

@@ -0,0 +1,213 @@
+<template>
+  <el-dialog
+    class="modify-ability-dim"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10vh"
+    width="600px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <div class="part-box part-box-pad part-box-border">
+      <el-form
+        ref="modalFormComp"
+        :model="modalForm"
+        :rules="rules"
+        label-width="140px"
+      >
+        <el-form-item prop="courseCode" label="课程代码:" required>
+          <el-input
+            v-model.trim="modalForm.courseCode"
+            placeholder="请输入课程代码"
+            readonly
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="courseName" label="课程名称:" required>
+          <el-input
+            v-model.trim="modalForm.courseName"
+            placeholder="请输入课程名称"
+            readonly
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="firstName" label="一级能力维度:">
+          <el-input
+            v-model.trim="modalForm.firstName"
+            placeholder="请输入一级能力维度"
+            clearable
+            @change="dimValidate"
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="firstCode" label="一级维度编号:">
+          <el-input
+            v-model.trim="modalForm.firstCode"
+            placeholder="请输入一级维度编号"
+            clearable
+            @change="dimValidate"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="一级维度术语解释:">
+          <el-input
+            v-model.trim="modalForm.firsetNameDesc"
+            type="textarea"
+            :autosize="{ minRows: 1, maxRows: 5 }"
+            placeholder="请输入一级维度术语解释"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button type="danger" @click="cancel" plain>取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { updateKnowledgeDimension } from "../../api";
+
+const initModalForm = {
+  id: null,
+  courseName: "",
+  courseCode: "",
+  firstName: "",
+  firstCode: "",
+  firsetNameDesc: ""
+};
+
+export default {
+  name: "modify-ability-dim",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    dictData: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "能力维度";
+    }
+  },
+  data() {
+    const firstNameValidator = (rule, value, callback) => {
+      let existFirstDim = this.dictData.find(item => item.firstName === value);
+
+      if (this.isEdit) {
+        if (existFirstDim && this.instance.firstName !== value) {
+          return callback(new Error("一级能力维度已存在"));
+        }
+      } else {
+        if (existFirstDim) {
+          return callback(new Error("一级能力维度已存在"));
+        }
+      }
+
+      callback();
+    };
+    const firstCodeValidator = (rule, value, callback) => {
+      let existFirstDim = this.dictData.find(item => item.firstCode === value);
+
+      if (this.isEdit) {
+        if (existFirstDim && this.instance.firstCode !== value) {
+          return callback(new Error("一级维度编号已存在"));
+        }
+      } else {
+        if (existFirstDim) {
+          return callback(new Error("一级维度编号已存在"));
+        }
+      }
+
+      callback();
+    };
+
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: {},
+      rules: {
+        firstName: [
+          {
+            required: true,
+            message: "请输入一级能力维度",
+            trigger: "change"
+          },
+          {
+            max: 50,
+            message: "一级能力维度字数不能超过50",
+            trigger: "change"
+          },
+          {
+            validator: firstNameValidator,
+            trigger: "change"
+          }
+        ],
+        firstCode: [
+          {
+            required: true,
+            pattern: /^[A-Z]{1}$/,
+            message: "一级维度编号只能是大写字母A-Z,长度为1",
+            trigger: "change"
+          },
+          {
+            validator: firstCodeValidator,
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    initData(val) {
+      this.modalForm = this.$objAssign(initModalForm, val);
+    },
+    visibleChange() {
+      this.initData(this.instance);
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    dimValidate() {
+      this.$refs.modalFormComp.validateField([
+        "firstName",
+        "firstCode",
+        "secondName",
+        "secondCode"
+      ]);
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const datas = { ...this.modalForm };
+      const data = await updateKnowledgeDimension(datas).catch(() => {});
+      this.isSubmit = false;
+      if (!data) return;
+
+      this.$emit("confirm", this.modalForm);
+      this.cancel();
+    }
+  }
+};
+</script>

+ 143 - 0
src/modules/analysis/components/baseConfig/ModifyKnowledgeComment.vue

@@ -0,0 +1,143 @@
+<template>
+  <el-dialog
+    class="modify-knowledge-comment"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10vh"
+    width="700px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      label-width="100px"
+    >
+      <el-form-item label="等级:">
+        {{ modalForm.level }}
+      </el-form-item>
+      <el-form-item label="水平层次:">
+        {{ modalForm.levelDesc }}
+      </el-form-item>
+      <el-form-item label="划分规则:">
+        <p v-if="modalForm.startRate === 0">
+          个人得分率≥{{ modalForm.startRate }}%
+        </p>
+        <p v-else-if="modalForm.endRate === 100">
+          个人得分率≤{{ modalForm.endRate }}%
+        </p>
+        <p v-else>
+          {{ modalForm.startRate }}%≤个人得分率≤{{ modalForm.endRate }}%
+        </p>
+      </el-form-item>
+      <el-form-item prop="result" label="诊断结果:">
+        <el-input
+          v-model.trim="modalForm.result"
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 5 }"
+          placeholder="请输入诊断结果"
+          maxlength="9999"
+          show-word-limit
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="suggest" label="学习建议:">
+        <el-input
+          v-model.trim="modalForm.suggest"
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 5 }"
+          placeholder="请输入学习建议"
+          maxlength="9999"
+          show-word-limit
+        ></el-input>
+      </el-form-item>
+    </el-form>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button type="danger" @click="cancel" plain>取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+const initModalForm = {
+  id: null,
+  level: "",
+  levelDesc: "",
+  startRate: "",
+  endRate: "",
+  result: "",
+  suggest: ""
+};
+
+export default {
+  name: "modify-knowledge-comment",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "划分规则";
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: {},
+      rules: {
+        result: [
+          {
+            required: true,
+            message: "请输入诊断结果",
+            trigger: "change"
+          }
+        ],
+        suggest: [
+          {
+            required: true,
+            message: "请输入学习建议",
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    initData(val) {
+      this.modalForm = this.$objAssign(initModalForm, val);
+    },
+    visibleChange() {
+      this.initData(this.instance);
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      this.$emit("modified", this.modalForm);
+      this.cancel();
+    }
+  }
+};
+</script>

+ 302 - 0
src/modules/analysis/components/baseConfig/ModifyKnowledgeDim.vue

@@ -0,0 +1,302 @@
+<template>
+  <el-dialog
+    class="modify-knowledge-dim"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10vh"
+    width="600px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <div class="part-box part-box-pad part-box-border">
+      <el-form
+        ref="modalFormComp"
+        :model="modalForm"
+        :rules="rules"
+        label-width="140px"
+      >
+        <el-form-item prop="courseCode" label="课程代码:" required>
+          <el-input
+            v-model.trim="modalForm.courseCode"
+            placeholder="请输入课程代码"
+            readonly
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="courseName" label="课程名称:" required>
+          <el-input
+            v-model.trim="modalForm.courseName"
+            placeholder="请输入课程名称"
+            readonly
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="firstName" label="一级知识维度:">
+          <el-input
+            v-model.trim="modalForm.firstName"
+            placeholder="请输入一级知识维度"
+            clearable
+            @change="dimValidate"
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="firstCode" label="一级维度编号:">
+          <el-input
+            v-model.trim="modalForm.firstCode"
+            placeholder="请输入一级维度编号"
+            clearable
+            @change="dimValidate"
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="secondName" label="二级知识维度:">
+          <el-input
+            v-model.trim="modalForm.secondName"
+            placeholder="请输入二级知识维度"
+            clearable
+            @change="dimValidate"
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="secondCode" label="二级维度编号:">
+          <el-input
+            v-model.trim="modalForm.secondCode"
+            placeholder="请输入二级维度编号"
+            clearable
+            @change="dimValidate"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="一级维度术语解释:">
+          <el-input
+            v-model.trim="modalForm.firsetNameDesc"
+            type="textarea"
+            :autosize="{ minRows: 1, maxRows: 5 }"
+            placeholder="请输入一级维度术语解释"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button type="danger" @click="cancel" plain>取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { updateKnowledgeDimension } from "../../api";
+
+const initModalForm = {
+  id: null,
+  courseName: "",
+  courseCode: "",
+  firstName: "",
+  firstCode: "",
+  secondName: "",
+  secondCode: "",
+  firsetNameDesc: ""
+};
+
+export default {
+  name: "modify-knowledge-dim",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    dictData: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "知识维度";
+    }
+  },
+  data() {
+    const firstNameValidator = (rule, value, callback) => {
+      if (!this.modalForm.firstCode || !value) return callback();
+
+      let existFirstDim = this.dictData.find(
+        item => item.code === this.modalForm.firstCode
+      );
+      if (existFirstDim) {
+        if (existFirstDim.firstName !== value)
+          return callback(new Error("一级知识维度错误"));
+      } else {
+        existFirstDim = this.dictData.find(item => item.name === value);
+        if (existFirstDim) return callback(new Error("一级知识维度已存在"));
+      }
+
+      callback();
+    };
+
+    const secondNameValidator = (rule, value, callback) => {
+      if (
+        !this.modalForm.secondCode ||
+        !value ||
+        !this.modalForm.firstName ||
+        !this.modalForm.firstCode
+      )
+        return callback();
+
+      let existFirstDim = this.dictData.find(
+        item => item.code === this.modalForm.firstCode
+      );
+      if (existFirstDim) {
+        let existSecondDim = existFirstDim.children.find(
+          item => item.code === this.modalForm.secondCode
+        );
+        if (existSecondDim) {
+          return callback();
+        } else {
+          existSecondDim = existFirstDim.children.find(
+            item => item.name === value
+          );
+          if (existSecondDim) return callback(new Error("二级知识维度已存在"));
+        }
+      } else {
+        const secondDimExist = this.dictData.some(item =>
+          item.children.some(elem => elem.name === value)
+        );
+        if (secondDimExist) return callback(new Error("二级知识维度已存在"));
+      }
+
+      callback();
+    };
+
+    const secondCodeValidator = (rule, value, callback) => {
+      if (
+        !this.modalForm.secondCode ||
+        !value ||
+        !this.modalForm.firstName ||
+        !this.modalForm.firstCode
+      )
+        return callback();
+
+      if (value[0] !== this.modalForm.firstCode) {
+        return callback(new Error("二级维度编码首字母应该与一级维度编码一致"));
+      }
+
+      let existFirstDim = this.dictData.find(
+        item => item.code === this.modalForm.firstCode
+      );
+
+      if (existFirstDim) {
+        let existSecondDim = existFirstDim.children.find(
+          item => item.code === this.modalForm.secondCode
+        );
+        if (existSecondDim) return callback(new Error("二级维度编号已存在"));
+      }
+
+      callback();
+    };
+
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: {},
+      rules: {
+        firstName: [
+          {
+            required: true,
+            message: "请输入一级知识维度",
+            trigger: "change"
+          },
+          {
+            max: 50,
+            message: "一级知识维度字数不能超过50",
+            trigger: "change"
+          },
+          {
+            validator: firstNameValidator,
+            trigger: "change"
+          }
+        ],
+        firstCode: [
+          {
+            required: true,
+            pattern: /^[A-Z]{1}$/,
+            message: "一级维度编号只能是大写字母A-Z,长度为1",
+            trigger: "change"
+          }
+        ],
+        secondName: [
+          {
+            required: true,
+            message: "请输入二级知识维度",
+            trigger: "change"
+          },
+          {
+            max: 50,
+            message: "二级知识维度字数不能超过50",
+            trigger: "change"
+          },
+          {
+            validator: secondNameValidator,
+            trigger: "change"
+          }
+        ],
+        secondCode: [
+          {
+            required: true,
+            pattern: /^[A-Z][0-9]{1,}$/,
+            message: "二级维度编号只能是大写字母+数字",
+            trigger: "change"
+          },
+          {
+            validator: secondCodeValidator,
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    initData(val) {
+      this.modalForm = this.$objAssign(initModalForm, val);
+    },
+    visibleChange() {
+      this.initData(this.instance);
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    dimValidate() {
+      this.$refs.modalFormComp.validateField([
+        "firstName",
+        "firstCode",
+        "secondName",
+        "secondCode"
+      ]);
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const datas = { ...this.modalForm };
+      const data = await updateKnowledgeDimension(datas).catch(() => {});
+      this.isSubmit = false;
+      if (!data) return;
+
+      this.$emit("confirm", this.modalForm);
+      this.cancel();
+    }
+  }
+};
+</script>

+ 109 - 0
src/modules/analysis/components/baseConfig/ProficiencyEdit.vue

@@ -0,0 +1,109 @@
+<template>
+  <div class="proficiency-edit">
+    <el-form ref="modalFormComp" label-width="180px">
+      <el-form-item
+        v-for="(item, ind) in modalForm"
+        :key="ind"
+        :label="`${item.title}:`"
+      >
+        <div
+          :class="[
+            'rate-input',
+            { 'rate-input-offset-left': ind === modalForm.length - 1 }
+          ]"
+        >
+          <el-input-number
+            v-if="ind !== modalForm.length - 1"
+            v-model="item.startRate"
+            placeholder="请输入"
+            :min="0"
+            :max="100"
+            :step="1"
+            step-strictly
+            size="small"
+            :controls="false"
+            @change="rateChange"
+          ></el-input-number>
+          <span v-if="ind !== modalForm.length - 1">≤</span>
+          <span>个人得分率</span>
+          <span v-if="ind !== 0">≤</span>
+          <el-input-number
+            v-if="ind !== 0"
+            v-model="item.endRate"
+            placeholder="请输入"
+            :min="0"
+            :max="100"
+            :step="1"
+            step-strictly
+            size="small"
+            :controls="false"
+            @change="rateChange"
+          ></el-input-number>
+        </div>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+const initRateSet = [
+  {
+    title: "熟练掌握",
+    startRate: null,
+    endRate: 100
+  },
+  {
+    title: "较好掌握",
+    startRate: null,
+    endRate: null
+  },
+  {
+    title: "基本掌握",
+    startRate: null,
+    endRate: null
+  },
+  {
+    title: "部分掌握",
+    startRate: null,
+    endRate: null
+  },
+  {
+    title: "没有掌握,需从头再学",
+    startRate: 0,
+    endRate: null
+  }
+];
+
+export default {
+  name: "proficiency-edit",
+  props: {
+    rates: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  data() {
+    return {
+      modalForm: [...initRateSet]
+    };
+  },
+  mounted() {
+    if (!this.rates.length) {
+      this.modalForm = initRateSet.map(item => {
+        return { ...item };
+      });
+    } else {
+      this.modalForm = this.rates.map(item => {
+        return { ...item };
+      });
+    }
+  },
+  methods: {
+    rateChange() {
+      this.$emit("data-change", this.modalForm);
+    }
+  }
+};
+</script>

+ 95 - 0
src/modules/analysis/components/baseConfig/defaultComment.js

@@ -0,0 +1,95 @@
+export const initKnowledgeList = [
+  {
+    level: "A",
+    startRate: 90,
+    endRate: 100,
+    levelDesc: "表现优秀水平",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "B",
+    startRate: 75,
+    endRate: 89,
+    levelDesc: "表现良好水平",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "C",
+    startRate: 55,
+    endRate: 74,
+    levelDesc: "中等水平",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "D",
+    startRate: 40,
+    endRate: 54,
+    levelDesc: "有待提高水平",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "E",
+    startRate: 0,
+    endRate: 39,
+    levelDesc: "本课程没有学好",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  }
+];
+
+export const initAbilityList = [
+  {
+    level: "A",
+    startRate: 0,
+    endRate: 20,
+    levelDesc: "优秀",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "B",
+    startRate: 21,
+    endRate: 40,
+    levelDesc: "良好",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "C",
+    startRate: 41,
+    endRate: 60,
+    levelDesc: "中等",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "D",
+    startRate: 61,
+    endRate: 80,
+    levelDesc: "中等偏下",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  },
+  {
+    level: "E",
+    startRate: 81,
+    endRate: 100,
+    levelDesc: "表现不佳",
+    result:
+      "作答结果反映你在本次测试中表现优秀。你对本学期的知识点掌握的非常牢固,能够将所学的物理概念、规律和结论灵活用于解决相关的物理问题;具有将所学的物理知识,结合一定的数学手段解复杂的或综合性物理问题的能力。",
+    suggest: "希望你在后续课程的的学习中能够继续保持"
+  }
+];

+ 26 - 0
src/modules/analysis/components/baseConfig/dimenData.js

@@ -0,0 +1,26 @@
+let data = [];
+
+const codes = "ABCDEFG";
+for (let i = 0; i < 4; i++) {
+  const firstCode = codes[i];
+  const firstName = `一级知识维度${firstCode}`;
+  for (let j = 0; j < 5; j++) {
+    const ind = i * 5 + j;
+    const secondCode = `${firstCode}${j + 1}`;
+    data[ind] = {
+      id: ind,
+      courseCode: "1100860011012",
+      courseName: "大学物理B(下)",
+      firstName,
+      firstCode,
+      secondName: `二级知识维度${secondCode}`,
+      secondCode,
+      secondInd: j + 1,
+      isFirstSec: j === 0,
+      isLastSec: j === 4,
+      firsetNameDesc: `一级维度术语解释${firstCode}`
+    };
+  }
+}
+
+export default data;

+ 16 - 0
src/modules/analysis/router.js

@@ -0,0 +1,16 @@
+// user
+import DataInitManage from "./views/DataInitManage.vue";
+import AnalysisBatchManage from "./views/AnalysisBatchManage.vue";
+
+export default [
+  {
+    path: "/analysis/data-init-manage",
+    name: "DataInitManage",
+    component: DataInitManage
+  },
+  {
+    path: "/analysis/analysis-batch-manage",
+    name: "AnalysisBatchManage",
+    component: AnalysisBatchManage
+  }
+];

+ 198 - 0
src/modules/analysis/views/AnalysisBatchManage.vue

@@ -0,0 +1,198 @@
+<template>
+  <div class="analysis-batch-manage">
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form ref="FilterForm" label-position="left" label-width="85px" inline>
+        <el-form-item label="分析批次:">
+          <el-select
+            v-model="filter.batchId"
+            placeholder="请选择分析批次"
+            clearable
+          >
+            <el-option
+              v-for="item in batchs"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="toPage(1)">查询</el-button>
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action">
+        <el-button type="danger" :loading="loading" @click="toBatchDelete"
+          >批量删除</el-button
+        >
+        <el-button type="primary" @click="toAdd">新建分析批次</el-button>
+      </div>
+    </div>
+    <div class="part-box part-box-pad">
+      <el-table
+        ref="TableList"
+        :data="dataList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column
+          type="selection"
+          width="55"
+          align="center"
+        ></el-table-column>
+        <el-table-column prop="batchName" label="分析批次"></el-table-column>
+        <el-table-column prop="status" label="状态"> </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="240px"
+          align="center"
+        >
+          <template slot-scope="scope">
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toAddCourse(scope.row)"
+              >添加分析试卷</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toCalc(scope.row)"
+              >开始计算</el-button
+            >
+            <el-button
+              class="btn-danger"
+              type="text"
+              :disabled="loading"
+              @click="toDelete(scope.row)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total,prev, pager, next"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+        >
+        </el-pagination>
+      </div>
+    </div>
+
+    <!-- ModifyAnalysisBatch -->
+    <modify-analysis-batch
+      ref="ModifyAnalysisBatch"
+      :instance="curRow"
+      @modified="getList"
+    ></modify-analysis-batch>
+    <!-- ModifyAnalysisBatchPaper -->
+    <modify-analysis-batch-paper
+      ref="ModifyAnalysisBatchPaper"
+      :instance="curRow"
+    ></modify-analysis-batch-paper>
+  </div>
+</template>
+
+<script>
+import {
+  analysisBatchList,
+  analysisBatchQuery,
+  deleteAnalysisBatch
+} from "../api";
+
+import ModifyAnalysisBatch from "../components/ModifyAnalysisBatch.vue";
+import ModifyAnalysisBatchPaper from "../components/ModifyAnalysisBatchPaper.vue";
+
+export default {
+  name: "analysis-batch-manage",
+  components: { ModifyAnalysisBatch, ModifyAnalysisBatchPaper },
+  data() {
+    return {
+      filter: {
+        batchId: ""
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      dataList: [],
+      curRow: {},
+      batchs: [],
+      loading: false,
+      multipleSelection: []
+    };
+  },
+  mounted() {
+    this.getBatchs();
+    this.toPage(1);
+  },
+  methods: {
+    async getBatchs() {
+      const res = await analysisBatchQuery();
+      this.batchs = res || [];
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      const data = await analysisBatchList(datas);
+      this.dataList = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.multipleSelection = [];
+      this.current = page;
+      this.getList();
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val.map(item => item.id);
+    },
+    async toBatchDelete() {
+      if (!this.multipleSelection.length) {
+        this.$message.error("请选择要删除的批次!");
+        return;
+      }
+
+      const confirm = await this.$confirm(`确定要删除选中的批次吗?`, "提示", {
+        type: "warning"
+      }).catch(() => {});
+      if (confirm !== "confirm") return;
+
+      await deleteAnalysisBatch(this.multipleSelection);
+      this.$message.success("删除成功!");
+      this.deletePageLastItem();
+    },
+    toAdd() {
+      this.curRow = {};
+      this.$refs.ModifyAnalysisBatch.open();
+    },
+    toAddCourse(row) {
+      this.curRow = row;
+      this.$refs.ModifyAnalysisBatchPaper.open();
+    },
+    toCalc(row) {
+      console.log(row);
+    },
+    async toDelete(row) {
+      const confirm = await this.$confirm(
+        `确定要删除批次【${row.name}】吗?`,
+        "提示",
+        {
+          type: "warning"
+        }
+      ).catch(() => {});
+      if (confirm !== "confirm") return;
+
+      await deleteAnalysisBatch([row.id]);
+      this.$message.success("删除成功!");
+      this.deletePageLastItem();
+    }
+  }
+};
+</script>

+ 143 - 0
src/modules/analysis/views/DataInitManage.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="data-init-manage">
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form ref="FilterForm" label-position="left" label-width="55px" inline>
+        <el-form-item label="学期:">
+          <semester-select v-model="filter.semester"></semester-select>
+        </el-form-item>
+        <el-form-item label="考试:">
+          <exam-select
+            v-model="filter.examId"
+            :semester="filter.semester"
+          ></exam-select>
+        </el-form-item>
+        <el-form-item label="课程:">
+          <course-select
+            v-model="filter.courseCode"
+            :exam-id="filter.examId"
+            inspect
+          ></course-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="toPage(1)">查询</el-button>
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action"></div>
+    </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="semester" label="学期"></el-table-column>
+        <el-table-column prop="examName" label="考试"> </el-table-column>
+        <el-table-column prop="courseCode" label="课程(代码)" min-width="120">
+          <span slot-scope="scope">
+            {{ scope.row.courseName }}({{ scope.row.courseCode }})
+          </span>
+        </el-table-column>
+        <el-table-column prop="status" label="状态"> </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="160px"
+          align="center"
+        >
+          <template slot-scope="scope">
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toConfig(scope.row)"
+              >基础配置</el-button
+            >
+            <el-button
+              class="btn-primary"
+              type="text"
+              :disabled="loading"
+              @click="toAssignScore(scope.row)"
+              >赋分管理</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total,prev, pager, next"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+        >
+        </el-pagination>
+      </div>
+    </div>
+    <!-- ModifyBaseConfig -->
+    <modify-base-config
+      ref="ModifyBaseConfig"
+      :instance="curRow"
+    ></modify-base-config>
+  </div>
+</template>
+
+<script>
+import { dataInitList } from "../api";
+import ModifyBaseConfig from "../components/ModifyBaseConfig.vue";
+
+export default {
+  name: "data-init-manage",
+  components: { ModifyBaseConfig },
+  data() {
+    return {
+      filter: {
+        semester: "",
+        examId: "",
+        courseCode: ""
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      dataList: [
+        {
+          id: "1",
+          semester: "第一学期",
+          examName: "期中考试"
+        }
+      ],
+      curRow: {},
+      loading: false
+    };
+  },
+  mounted() {
+    // this.toPage(1);
+  },
+  methods: {
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      const data = await dataInitList(datas);
+      this.dataList = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    toConfig(row) {
+      console.log(row);
+      this.curRow = row;
+      this.$refs.ModifyBaseConfig.open();
+    },
+    async toAssignScore(row) {
+      console.log(row);
+    }
+  }
+};
+</script>

+ 2 - 1
src/router.js

@@ -11,6 +11,7 @@ import exam from "./modules/exam/router";
 import print from "./modules/print/router";
 import customer from "./modules/customer/router";
 import stmms from "./modules/stmms/router";
+import analysis from "./modules/analysis/router";
 // card part
 import card from "./modules/card/router";
 // admin
@@ -42,7 +43,7 @@ let router = new Router({
       path: "/home/:nextRouter?",
       name: "Home",
       component: Home,
-      children: [...base, ...exam, ...print, ...customer, ...stmms]
+      children: [...base, ...exam, ...print, ...customer, ...stmms, ...analysis]
     },
     { ...login },
     { ...admin },