zhangjie 1 год назад
Родитель
Сommit
b1f1d9ff64

+ 103 - 74
src/components/CommonRangeConfig.vue

@@ -1,54 +1,68 @@
 <template>
   <a-modal
-    v-model:open="rangeConfigVisible"
+    v-model:open="visible"
     title="分段设置"
     okText="确定"
     cancelText="取消"
     @ok="handleOk"
   >
-    <div v-if="selectedRangeConfig">
-      <a-timeline>
-        <a-timeline-item
-          v-for="(item, index) in selectedRangeConfig"
-          :key="index"
-        >
-          {{
-            `${item.baseScore + item.adjustScore}(${
-              RANGE_POINT_TYPE[item.type]
-            }${item.adjustScore > 0 ? "+" : ""}${item.adjustScore})`
-          }}
-
-          <a-button
-            v-if="item.type !== 'ZERO'"
-            @click="handleDeleteRangePoint(item)"
-            >删除</a-button
+    <div class="common-range-config" v-if="selectedRangeConfig">
+      <a-form
+        ref="formRef"
+        :labelCol="{ style: { width: '70px' } }"
+        :model="formData"
+        :rules="rules"
+      >
+        <a-form-item label="基础分" name="type">
+          <a-select
+            v-model:value="formData.type"
+            placeholder="请选择"
+            style="width: 120px"
           >
-        </a-timeline-item>
-      </a-timeline>
+            <a-select-option value="NATIONAL_SCORE">国家单科线</a-select-option>
+            <a-select-option value="RETEST_SCORE">复试单科线</a-select-option>
+            <a-select-option value="CUSTOM">自定义</a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="调整分" name="adjustScore">
+          <a-input-number
+            v-model:value="formData.adjustScore"
+            placeholder="请输入"
+          ></a-input-number>
+        </a-form-item>
+      </a-form>
 
-      <div class="tw-my-4 tw-flex tw-items-center">
-        <span style="width: 60px">基础分</span>
-        <a-select v-model:value="rangePoint.type" style="width: 100%">
-          <a-select-option value="NATIONAL_SCORE">国家单科线</a-select-option>
-          <a-select-option value="RETEST_SCORE">复试单科线</a-select-option>
-          <!-- <a-select-option value="NATIONAL_TOTAL_SCORE">
-            国家总分线
-          </a-select-option>
-          <a-select-option value="RETEST_TOTAL_SCORE">
-            复试总分线
-          </a-select-option>
-          <a-select-option value="TOTAL_SCORE_LINE">国家满分线</a-select-option> -->
-          <a-select-option value="CUSTOM">自定义</a-select-option>
-        </a-select>
-      </div>
-      <div class="tw-my-4 tw-flex tw-items-center">
-        <span style="width: 55px">调整分</span>
-        <a-input-number
-          v-model:value="rangePoint.adjustScore"
-          class="tw-rounded-xl"
-        ></a-input-number>
+      <div class="range-timeline">
+        <div class="range-action">
+          <a-button type="link" @click="newRangePoint">
+            <template #icon>
+              <PlusCircleOutlined />
+            </template>
+            新增分割点
+          </a-button>
+        </div>
+
+        <a-timeline>
+          <a-timeline-item
+            v-for="(item, index) in selectedRangeConfig"
+            :key="index"
+          >
+            <p>
+              {{
+                `${item.baseScore + item.adjustScore}(${
+                  RANGE_POINT_TYPE[item.type]
+                }${item.adjustScore > 0 ? "+" : ""}${item.adjustScore})`
+              }}
+            </p>
+            <svg-icon
+              v-if="item.type !== 'ZERO'"
+              name="delete"
+              color="#f53f3f"
+              @click="handleDeleteRangePoint(item)"
+            ></svg-icon>
+          </a-timeline-item>
+        </a-timeline>
       </div>
-      <a-button type="primary" @click="newRangePoint">新增分割点</a-button>
     </div>
   </a-modal>
 </template>
@@ -57,7 +71,14 @@
 import { getProjectCourseList } from "@/api/projectParamsManagementPage";
 import { RANGE_POINT_TYPE } from "@/constants/constants";
 import { ProjectCourse, RangeConfig } from "@/types";
-import { onUpdated, reactive, watch } from "vue";
+import { onUpdated, reactive, watch, ref } from "vue";
+import type { Rule, FormInstance } from "ant-design-vue/es/form";
+import { PlusCircleOutlined } from "@ant-design/icons-vue";
+import useModal from "@/hooks/modal";
+
+/* modal */
+const { visible, open, close } = useModal();
+defineExpose({ open, close });
 
 const emit = defineEmits(["updated"]);
 
@@ -67,12 +88,6 @@ const props = defineProps<{
   rangeConfig: RangeConfig[];
 }>();
 
-let rangeConfigVisible = $ref(false);
-const showModal = () => {
-  rangeConfigVisible = true;
-};
-defineExpose({ showModal });
-
 let selectedRangeConfig = $ref<RangeConfig[]>([]);
 let courseSetting = $ref({} as ProjectCourse);
 
@@ -99,44 +114,58 @@ onUpdated(async () => {
   courseSetting = res.data.content[0];
 });
 
-let rangePoint = reactive({
+const defaultFormData = {
   baseScore: 0,
   adjustScore: 0,
   type: "",
-});
+};
+type FormDataType = typeof defaultFormData;
+const formRef = ref<FormInstance>();
+const formData = reactive<FormDataType>({ ...defaultFormData });
+const rules: Record<string, Rule[]> = {
+  type: [
+    {
+      required: true,
+      message: "请选择基础分",
+    },
+  ],
+  adjustScore: [
+    {
+      required: true,
+      message: "请输入调整分",
+    },
+  ],
+};
 
-function newRangePoint() {
-  if (!rangePoint.type) return;
-  if (!rangePoint.adjustScore) {
-    rangePoint.adjustScore = 0;
-  }
-  if (rangePoint.type === "NATIONAL_SCORE") {
-    rangePoint.baseScore = courseSetting.nationalScore;
+async function newRangePoint() {
+  const valid = await formRef.value?.validate().catch(() => {});
+  if (!valid) return;
+
+  if (formData.type === "NATIONAL_SCORE") {
+    formData.baseScore = courseSetting.nationalScore;
   }
-  if (rangePoint.type === "RETEST_SCORE") {
-    rangePoint.baseScore = courseSetting.retestScore;
+  if (formData.type === "RETEST_SCORE") {
+    formData.baseScore = courseSetting.retestScore;
   }
-  if (rangePoint.type === "NATIONAL_TOTAL_SCORE") {
-    rangePoint.baseScore = courseSetting.nationalTotalScore;
+  if (formData.type === "NATIONAL_TOTAL_SCORE") {
+    formData.baseScore = courseSetting.nationalTotalScore;
   }
-  if (rangePoint.type === "RETEST_TOTAL_SCORE") {
-    rangePoint.baseScore = courseSetting.retestTotalScore;
+  if (formData.type === "RETEST_TOTAL_SCORE") {
+    formData.baseScore = courseSetting.retestTotalScore;
   }
-  if (rangePoint.type === "TOTAL_SCORE_LINE") {
-    rangePoint.baseScore = courseSetting.totalScoreLine;
+  if (formData.type === "TOTAL_SCORE_LINE") {
+    formData.baseScore = courseSetting.totalScoreLine;
   }
-  if (rangePoint.type === "ZERO") {
-    rangePoint.baseScore = 0;
-    rangePoint.adjustScore = 0;
+  if (formData.type === "ZERO") {
+    formData.baseScore = 0;
+    formData.adjustScore = 0;
   }
-  selectedRangeConfig.push({ ...rangePoint } as RangeConfig);
-  // let t = toRaw(selectedRangeConfig);
-  // t.sort((a, b) => a.baseScore + a.adjustScore - (b.baseScore + b.adjustScore));
-  // console.log(t);
+  selectedRangeConfig.push({ ...formData } as RangeConfig);
+
   selectedRangeConfig = selectedRangeConfig.sort(
     (a, b) => a.baseScore + a.adjustScore - (b.baseScore + b.adjustScore)
   );
-  Object.assign(rangePoint, {
+  Object.assign(formData, {
     baseScore: 0,
     adjustScore: 0,
     type: "",
@@ -149,6 +178,6 @@ function handleDeleteRangePoint(item: RangeConfig) {
 
 function handleOk() {
   emit("updated", selectedRangeConfig);
-  rangeConfigVisible = false;
+  close();
 }
 </script>

+ 1 - 2
src/features/allAnalysis/ScoreRate.vue

@@ -274,13 +274,12 @@ let selectedRangeConfig = $ref([]);
 let selectedCourseId = $ref(0);
 
 let rangeConfigRef = $ref<InstanceType<typeof CommonRangeConfig>>();
-
 const openRangeConfigModal = (item: SasCourse) => {
   selectedCourseId = item.courseId;
   selectedRangeConfig = JSON.parse(JSON.stringify(item.rangeConfig));
   // @ts-ignore https://github.com/vuejs/vue-next/issues/4397
   // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-  rangeConfigRef.showModal();
+  rangeConfigRef?.open();
 };
 
 async function handleRangeConfigUpdate(rangeConfig: RangeConfig) {

+ 2 - 2
src/features/report/ReportBatchDownload.vue

@@ -192,7 +192,7 @@ async function startTask() {
     params: {
       projectId: props.curProject.id,
       paperId: curPaperId,
-      compareProjectId,
+      compareProjectId: compareProjectId.join(),
       viewType: "frame",
     },
     query: {
@@ -211,7 +211,7 @@ async function finishTask() {
   if (res.data.status === "SUCCESS" && res.data.filePath) {
     updateProgress(100);
     closeLoadModal();
-    void message.info("开始下载报告!");
+    void message.info("获取报告成功,开始下载报告!");
     downloadByLink(res.data.filePath);
     // window.open(res.data.filePath);
     return;

+ 2 - 1
src/features/report/ReportMain.vue

@@ -137,7 +137,8 @@ onMounted(async () => {
     } else {
       projectId = +route.params.projectId;
       paperId = +route.params.paperId;
-      compareProjectId = props.compareProjectId as number[];
+      const ids = (route.params.compareProjectId as string) || "";
+      compareProjectId = ids.split(",").map((item) => +item);
       viewType = route.params.viewType as string;
 
       if (viewType !== "frame") {

+ 68 - 0
src/styles/pages.less

@@ -96,4 +96,72 @@
   .ant-steps .ant-steps-item .ant-steps-item-icon {
     margin-inline-end: 6px;
   }
+  .ant-steps-item .ant-steps-item-content {
+    min-height: 38px;
+  }
+}
+
+// common-range-config
+.common-range-config {
+  .range-timeline {
+    background-color: var(--color-background);
+    padding: 15px 20px;
+    margin: 0 -20px;
+  }
+  .range-action {
+    margin-bottom: 15px;
+
+    .ant-btn-link {
+      &:hover {
+        background-color: #fff;
+      }
+    }
+  }
+  .ant-timeline {
+    background-color: #fff;
+    padding: 22px 16px 0;
+    border-radius: 6px;
+    height: 168px;
+    overflow-y: auto;
+  }
+  .ant-timeline-item {
+    padding-bottom: 6px;
+
+    &:last-child {
+      padding-bottom: 0;
+    }
+  }
+  .ant-timeline-item-head-blue {
+    border-color: #8c8c8c;
+    width: 8px;
+    height: 8px;
+    border-width: 2px;
+    left: 1px;
+  }
+  .ant-timeline-item-tail {
+    border-color: #d9d9d9;
+    height: calc(100% - 12px);
+  }
+
+  .ant-timeline-item-content {
+    padding: 5px 8px;
+    border-radius: var(--border-radius);
+    inset-block-start: -12px;
+    margin-inline-start: 12px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    min-height: 32px !important;
+
+    &:hover {
+      background-color: #f0f0f0;
+    }
+
+    .svg-icon {
+      cursor: pointer;
+      &:hover {
+        opacity: 0.5;
+      }
+    }
+  }
 }