Selaa lähdekoodia

feat: 审核首页

zhangjie 9 kuukautta sitten
vanhempi
commit
983ccfce02

+ 6 - 0
src/render/ap/base.ts

@@ -8,3 +8,9 @@ export const subjectList = (data: ExamParams): Promise<SubjectItem[]> =>
     method: "post",
     data,
   });
+export const examList = (): Promise<Exam[]> =>
+  request({
+    url: "/api/admin/course/list",
+    method: "post",
+    data,
+  });

+ 6 - 0
src/render/ap/types/base.ts

@@ -3,3 +3,9 @@ export interface SubjectItem {
   subjectCode: string;
   subjectName: string;
 }
+
+// export interface ExamItem {
+//   id: number;
+//   name: string;
+//   mode: string;
+// }

BIN
src/render/assets/imgs/icon-done.png


BIN
src/render/assets/imgs/icon-wait.png


+ 0 - 9
src/render/components/MyModal/index.vue

@@ -375,7 +375,6 @@ onMounted(() => {
     }
 
     .ant-modal-close {
-      top: 6px;
       right: 30px;
       background-color: transparent;
       cursor: inherit;
@@ -392,10 +391,6 @@ onMounted(() => {
       }
 
       .ant-modal-close-x {
-        width: 50px;
-        height: 50px;
-        line-height: 44px;
-
         .ant-space {
           width: 100%;
           height: 100%;
@@ -414,10 +409,6 @@ onMounted(() => {
       padding-top: 0;
       overflow: hidden;
 
-      .ant-modal-header {
-        padding-top: 20px;
-      }
-
       .ant-modal-body {
         flex: auto;
         height: 100%;

+ 9 - 0
src/render/router/routes.ts

@@ -101,6 +101,15 @@ const routes: RouteRecordRaw[] = [
           title: "结果导出",
         },
       },
+      // 审核
+      {
+        path: "audit",
+        name: "Audit",
+        component: () => import("@/views/Audit/Main/index.vue"),
+        meta: {
+          title: "审核",
+        },
+      },
     ],
   },
 ];

+ 5 - 0
src/render/styles/antui-reset.less

@@ -35,4 +35,9 @@
   .ant-modal-body {
     padding: 20px;
   }
+
+  .ant-modal-footer {
+    margin: 0;
+    padding: 0 20px 20px;
+  }
 }

+ 198 - 0
src/render/styles/pages.less

@@ -1,3 +1,201 @@
+// home
+.home {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+
+  &-head {
+    flex-grow: 0;
+    flex-shrink: 0;
+    background-color: #fff;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 11px 16px 10px;
+    border-bottom: 1px solid @border-color1;
+
+    .head-no {
+      display: inline-block;
+      height: 24px;
+      line-height: 24px;
+      background: linear-gradient(135deg, #fdd62d 0%, #faad14 100%);
+      border-radius: 4px;
+      border: 1px solid #ffc53d;
+      color: #fff;
+      padding: 0 8px;
+    }
+    .head-mode {
+      line-height: 22px;
+    }
+    .head-name {
+      height: 24px;
+      font-weight: 500;
+      font-size: 16px;
+      line-height: 24px;
+    }
+  }
+  &-body {
+    flex-grow: 2;
+    background-image: url(../assets/imgs/cur_exam_bg.png);
+    background-size: cover;
+    background-repeat: no-repeat;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+
+    .audit-box {
+      height: 222px;
+      background: #ffffff;
+      border-radius: 8px;
+      border: 1px solid @border-color1;
+      margin: 0 8px;
+
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+
+      &-head,
+      &-foot {
+        flex-grow: 0;
+        flex-shrink: 0;
+      }
+
+      &-head {
+        padding: 16px 16px 0 16px;
+      }
+
+      &-foot {
+        padding: 16px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      }
+
+      &-head {
+        h4 {
+          font-weight: 500;
+          font-size: 16px;
+          line-height: 24px;
+        }
+      }
+
+      &-body {
+        flex-grow: 2;
+        padding: 0 16px;
+
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        overflow: hidden;
+      }
+
+      &.img-check {
+        .audit-card {
+          height: 86px;
+          &:first-child {
+            margin-right: 16px;
+          }
+        }
+
+        .audit-box-foot {
+          color: @text-color2;
+          border-top: 1px solid @border-color1;
+          .ant-input {
+            width: 40px;
+            background: #f3f4f6;
+            padding-left: 5px;
+            padding-right: 5px;
+            text-align: center;
+          }
+          .ant-btn {
+            padding-left: 12px;
+            padding-right: 12px;
+          }
+          .ant-tag {
+            line-height: 32px;
+            font-size: 14px;
+          }
+          .anticon {
+            color: #bfbfbf;
+          }
+        }
+      }
+    }
+
+    .audit-card {
+      width: 244px;
+      height: 114px;
+      border-radius: 6px;
+      border: 1px solid @border-color1;
+      padding: 30px 16px;
+
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      &-icon,
+      &-action {
+        flex-grow: 0;
+        flex-shrink: 0;
+      }
+      &-icon {
+        width: 54px;
+        height: 54px;
+        padding: 15px 16px;
+        border-radius: 6px;
+        margin-right: 12px;
+
+        &.audit-wait {
+          background: #fff7e8;
+          background-image: url(../assets/imgs/icon-wait.png);
+          background-repeat: no-repeat;
+          background-size: 22px 24px;
+          background-position: 16px 16px;
+        }
+        &.audit-done {
+          background-color: #e8ffea;
+          background-image: url(../assets/imgs/icon-done.png);
+          background-repeat: no-repeat;
+          background-size: 22px 24px;
+          background-position: 16px 16px;
+        }
+      }
+      &-content {
+        flex-grow: 2;
+
+        > p:nth-of-type(1) {
+          height: 22px;
+          font-weight: 400;
+          font-size: 14px;
+          color: @text-color2;
+          line-height: 22px;
+        }
+        > p:nth-of-type(2) {
+          height: 26px;
+          font-weight: 500;
+          font-size: 18px;
+          color: @text-color1;
+          line-height: 26px;
+          margin-top: 6px;
+        }
+      }
+
+      &-action {
+        margin-left: 8px;
+        color: @brand-color;
+        font-weight: 400;
+        cursor: pointer;
+
+        &:hover {
+          opacity: 0.8;
+        }
+      }
+    }
+  }
+}
+
 // arbitrate
 .arbitrate {
   height: 100%;

+ 9 - 0
src/render/views/Audit/InTime/index.vue

@@ -0,0 +1,9 @@
+<template>
+  <div></div>
+</template>
+
+<script setup lang="ts">
+defineOptions({
+  name: "InTime",
+});
+</script>

+ 122 - 0
src/render/views/Audit/Main/SelectExamDialog.vue

@@ -0,0 +1,122 @@
+<template>
+  <a-modal
+    v-model:open="visible"
+    :width="410"
+    style="top: 10vh"
+    title="切换考试"
+    @ok="confirm"
+  >
+    <div class="exam-list">
+      <a-radio-group v-model:value="choosedExamId">
+        <a-radio v-for="item in dataList" :key="item.id" :value="item.id">
+          <a-space class="radio-content" align="center" :size="10">
+            <div class="rc-id">No.{{ item.id }}</div>
+            <div class="rc-name">{{ item.name }}</div>
+            <div class="rc-mode">{{ item.mode }}</div>
+          </a-space>
+        </a-radio>
+      </a-radio-group>
+    </div>
+  </a-modal>
+</template>
+
+<script setup lang="ts">
+import { ref, watch } from "vue";
+import { message } from "ant-design-vue";
+import { examList } from "@/ap/base";
+import useModal from "@/hooks/useModal";
+import { useUserStore } from "@/store";
+
+defineOptions({
+  name: "SelectExamDailog",
+});
+
+/* modal */
+const { visible, open, close } = useModal();
+defineExpose({ open, close });
+
+const userStore = useUserStore();
+
+const dataList = ref<Exam[]>([]);
+const choosedExamId = ref(0);
+async function getExamList() {
+  const res = await examList();
+  dataList.value = res || [];
+}
+
+// TODO: 测试数据
+dataList.value = "#"
+  .repeat(16)
+  .split("")
+  .map((item, index) => {
+    return {
+      enable: true,
+      id: index,
+      mode: "common",
+      name: `考试${index + 1}`,
+      schoolName: "string",
+      updateTime: 123456789,
+    };
+  });
+
+// getExamList();
+
+function confirm() {
+  console.log(choosedExamId.value);
+
+  if (!choosedExamId.value) {
+    message.error("请选择考试");
+    return;
+  }
+
+  const curExam = dataList.value.find(
+    (item) => item.id === choosedExamId.value
+  );
+  if (!curExam) return;
+
+  userStore.setCurExam(curExam);
+  close();
+}
+
+/* init modal */
+watch(
+  () => visible.value,
+  (val) => {
+    if (val) {
+      modalOpenHandle();
+    }
+  },
+  {
+    immediate: true,
+  }
+);
+
+function modalOpenHandle() {
+  choosedExamId.value = userStore.curExam?.id;
+}
+</script>
+
+<style lang="less" scoped>
+.radio-content {
+  .rc-id {
+    width: 60px;
+  }
+  .rc-name {
+    width: 200px;
+  }
+  .rc-mode {
+    width: 60px;
+    color: @text-color3;
+  }
+}
+.exam-list {
+  height: 320px;
+  overflow-y: auto;
+  overflow-x: hidden;
+
+  .ant-radio-wrapper {
+    margin-bottom: 16px;
+    margin-right: 0;
+  }
+}
+</style>

+ 119 - 0
src/render/views/Audit/Main/index.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="home audit">
+    <div class="home-head">
+      <div>
+        <a-space v-if="userStore.curExam" :size="6">
+          <span class="head-no">No.{{ userStore.curExam.id }}</span>
+          <a-tag class="head-mode" color="blue"
+            >{{ userStore.curExam.mode }}模式</a-tag
+          >
+          <h3 class="head-name">{{ userStore.curExam.name }}</h3>
+        </a-space>
+      </div>
+      <div>
+        <a-button @click="onSwitchExam">
+          <template #icon><SwapOutlined /></template>切换考试
+        </a-button>
+      </div>
+    </div>
+    <div class="home-body">
+      <div class="audit-box">
+        <div class="audit-box-head">
+          <h4>实时审核</h4>
+        </div>
+        <div class="audit-box-body">
+          <div class="audit-card">
+            <div class="audit-card-icon audit-wait"></div>
+            <div class="audit-card-content">
+              <p>待审核</p>
+              <p>1</p>
+            </div>
+            <div class="audit-card-action">进入 <RightOutlined /></div>
+          </div>
+        </div>
+      </div>
+
+      <div class="audit-box">
+        <div class="audit-box-head">
+          <h4>人工绑定审核</h4>
+        </div>
+        <div class="audit-box-body">
+          <div class="audit-card">
+            <div class="audit-card-icon audit-wait"></div>
+            <div class="audit-card-content">
+              <p>待审核</p>
+              <p>1</p>
+            </div>
+            <div class="audit-card-action">进入 <RightOutlined /></div>
+          </div>
+        </div>
+      </div>
+
+      <div class="audit-box img-check">
+        <div class="audit-box-head">
+          <h4>图片检查</h4>
+        </div>
+        <div class="audit-box-body">
+          <div class="audit-card">
+            <div class="audit-card-icon audit-done"></div>
+            <div class="audit-card-content">
+              <p>已审核</p>
+              <p>1</p>
+            </div>
+          </div>
+
+          <div class="audit-card">
+            <div class="audit-card-icon audit-wait"></div>
+            <div class="audit-card-content">
+              <p>待审核</p>
+              <p>1</p>
+            </div>
+            <div class="audit-card-action">进入 <RightOutlined /></div>
+          </div>
+        </div>
+        <div class="audit-box-foot">
+          <a-tag :bordered="false">
+            <template #icon><PieChartFilled /></template>抽查比例:0%
+          </a-tag>
+          <a-space :size="8">
+            <span>轮播时间配置:</span>
+            <a-input></a-input>
+            <span>秒/张</span>
+            <a-button type="primary">设置</a-button>
+          </a-space>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- SelectExamDialog -->
+  <SelectExamDialog ref="selectExamDialogRef" />
+</template>
+
+<script setup lang="ts">
+import { ref } from "vue";
+import {
+  SwapOutlined,
+  RightOutlined,
+  PieChartFilled,
+} from "@ant-design/icons-vue";
+import { useRouter } from "vue-router";
+import { useUserStore } from "@/store";
+import SelectExamDialog from "./SelectExamDialog.vue";
+
+defineOptions({
+  name: "Audit",
+});
+
+const router = useRouter();
+const userStore = useUserStore();
+
+function toPage(name: string) {
+  router.push({ name });
+}
+
+const selectExamDialogRef = ref();
+function onSwitchExam() {
+  selectExamDialogRef.value?.open();
+}
+</script>

+ 5 - 0
src/render/views/Login/AdminLogin.vue

@@ -57,6 +57,11 @@ const fields = ref([
       size: "large",
       onClick: () => {
         //todo模拟登录请求...
+        if (params.a === "audit") {
+          router.push({ name: "Audit" });
+          window.electronApi.changeWinSize("big");
+          return;
+        }
         router.push({ name: "CurExam" });
         window.electronApi.changeWinSize("big");
       },