Browse Source

feat: 细节优化

chenhao 2 năm trước cách đây
mục cha
commit
adce2d9175

+ 1 - 1
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vite + Vue + TS</title>
+    <title>试卷结构管理工具</title>
   </head>
   <body>
     <div id="app"></div>

+ 1 - 1
src/apis/exam.ts

@@ -20,6 +20,6 @@ export const editExamInfoHttp = (data: BaseExamInfo) => {
 /**
  * @description 考试数据同步
  */
-export const syncExamDataHttp = (data: { schoolId: string }) => {
+export const syncExamDataHttp = (data: { schoolId: string | number }) => {
   return request.post<unknown, null>("/api/exam/sync", data);
 };

+ 9 - 9
src/assets/less/global.less

@@ -10,7 +10,7 @@ body {
 }
 
 #app {
-  height: 100%;
+  min-height: 100%;
 }
 
 a {
@@ -22,20 +22,20 @@ svg {
 }
 
 ::-webkit-scrollbar{
-  width:10px;
-  height:10px;
+  width:8px;
+  height:8px;
 }
 ::-webkit-scrollbar-track{
-  background: rgb(239, 239, 239);
-  border-radius:2px;
+  background-color: transparent;
+  border-radius:8px;
 }
 ::-webkit-scrollbar-thumb{
-  background: #bfbfbf;
-  border-radius:10px;
+  background: #ddd;
+  border-radius:4px;
 }
 ::-webkit-scrollbar-thumb:hover{
-  background: #333;
+  background-color: #ccc;
 }
 ::-webkit-scrollbar-corner{
-  background: #179a16;
+  background-color: transparent;
 }

+ 1 - 0
src/assets/less/var.less

@@ -4,6 +4,7 @@
 @table-font-size: @font-size-small;
 @select-background: @bg-color;
 @border-radius-base: 8px;
+@background-color-base: @bg-color;
 @font-size-base: 14px;
 @font-size-small: 12px;
 @height-base: 32px;

+ 14 - 0
src/constants/dicts.ts

@@ -0,0 +1,14 @@
+/** 考试状态 */
+export const EXAM_STATUS = {
+  EDIT: "开放上报",
+  FINISH: "停止上报",
+  CLOSE: "关闭考试",
+};
+
+/** 角色 */
+
+export const ROLE = {
+  SUPER_ADMIN: "超级管理员",
+  SCHOOL_ADMIN: "机构管理员",
+  SECTION_LEADER: "科组长",
+};

+ 3 - 3
src/layout/index.vue

@@ -16,16 +16,16 @@ import LeftMenu from "@/layout/left-menu.vue";
 <style scoped lang="less">
 .layout {
   width: 100vw;
-  height: 100vh;
+  min-height: 100vh;
   display: flex;
   .layout-left {
     width: 200px;
-    height: 100%;
+    min-height: 100%;
     background: @white;
   }
   .layout-content {
     flex: 1 1 0;
-    height: 100%;
+    min-height: 100%;
     overflow: auto;
     padding: 24px;
   }

+ 5 - 4
src/layout/left-menu.vue

@@ -13,7 +13,7 @@
     </div>
     <div class="menu-footer">
       <div class="user-info">
-        <div class="user-name">{{mainStore.systemUserInfo?.name}}</div>
+        <div class="user-name">{{ mainStore.systemUserInfo?.name }}</div>
         <div class="exit-login" @click="handleExitLogin">
           <SvgIcon class="exit-icon" name="exit-icon" />
         </div>
@@ -25,9 +25,9 @@
 <script setup lang="ts" name="LayoutLeftMenu">
 import MenuItem from "@/layout/menu-item.vue";
 import { exitLogin } from "@/utils/common";
-import useMainStore from "@/store/main";
+import { useMainStore } from "@/store/main";
 
-const mainStore = useMainStore()
+const mainStore = useMainStore();
 const menu = [
   { path: "/school", label: "学校管理", iconName: "school-icon" },
   {
@@ -49,7 +49,7 @@ const handleExitLogin = () => {
 <style scoped lang="less">
 .menu {
   width: 100%;
-  height: 100%;
+  min-height: 100%;
   display: flex;
   flex-direction: column;
   .menu-header {
@@ -67,6 +67,7 @@ const handleExitLogin = () => {
   .menu-content {
     flex: 1 1 0;
     padding: 0 32px;
+    overflow-y: auto;
     .root-menu-item {
       padding: 25px 0;
       border-bottom: 1px solid @border-color;

+ 39 - 30
src/pages/exam-manage/index.vue

@@ -27,7 +27,7 @@
           >
         </a-form-item>
       </a-form>
-      <a-button
+      <!-- <a-button
         type="primary"
         class="tw-flex tw-items-center operation-button"
         @click="syncExamData"
@@ -36,7 +36,7 @@
           <CloudSyncOutlined />
         </template>
         同步
-      </a-button>
+      </a-button> -->
       <a-button
         type="primary"
         class="tw-flex tw-items-center operation-button"
@@ -53,6 +53,12 @@
         :columns="columns"
         :data-source="examTableData.result"
         emptyText="暂无考试信息"
+        :loading="tableLoading"
+        :pagination="{
+          total: examTableData.totalCount,
+          pageSize: query.pageSize,
+        }"
+        @change="currentPageChange"
         :row-class-name="
           (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
         "
@@ -62,13 +68,7 @@
             {{ index + 1 }}
           </template>
           <template v-else-if="column.dataIndex === 'examStatus'">
-            {{
-              record.examStatus === "EDIT"
-                ? "开放上报"
-                : record.examStatus === "FINISH"
-                ? "停止上报"
-                : "关闭卡松是"
-            }}
+            {{ EXAM_STATUS[record.examStatus as keyof typeof EXAM_STATUS] }}
           </template>
           <template v-else-if="column.dataIndex === 'operation'">
             <div class="tw-flex tw-items-center">
@@ -84,18 +84,19 @@
     </Block>
     <a-modal
       v-model:visible="showModal"
-      title="新增考试"
+      :title="`${examInfo.id ? '编辑' :'新增'}考试`"
       okText="确定"
       cancelText="取消"
       :maskClosable="false"
       @ok="onAddNewExam"
-      :afterClose="resetExamInfo"
+      :afterClose="resetFields"
     >
       <a-form :labelCol="{ span: 6 }">
         <a-form-item label="学校名称" v-bind="validateInfos.schoolId">
           <a-select
             v-model:value="examInfo.schoolId"
             show-search
+            :disabled="!!examInfo.id"
             @search="querySchoolList"
             :filterOption="false"
             placeholder="学校名称"
@@ -113,9 +114,15 @@
         </a-form-item>
         <a-form-item label="状态" v-bind="validateInfos.examStatus">
           <a-select v-model:value="examInfo.examStatus">
-            <a-select-option value="EDIT">开放上报</a-select-option>
-            <a-select-option value="FINISH">停止上报</a-select-option>
-            <a-select-option value="CLOSE">关闭考试</a-select-option>
+            <a-select-option value="EDIT">{{
+              EXAM_STATUS.EDIT
+            }}</a-select-option>
+            <a-select-option value="FINISH">{{
+              EXAM_STATUS.FINISH
+            }}</a-select-option>
+            <a-select-option value="CLOSE">{{
+              EXAM_STATUS.CLOSE
+            }}</a-select-option>
           </a-select>
         </a-form-item>
       </a-form>
@@ -125,7 +132,7 @@
 
 <script setup lang="ts" name="PageExam">
 import { reactive, ref, watch } from "vue";
-import { PlusCircleOutlined, CloudSyncOutlined } from "@ant-design/icons-vue";
+import { PlusCircleOutlined } from "@ant-design/icons-vue";
 import { getSchoolListHttp } from "@/apis/school";
 import {
   getExamListHttp,
@@ -135,10 +142,14 @@ import {
 import Block from "@/components/block/index.vue";
 import { message, TableColumnType } from "ant-design-vue";
 import { Form } from "ant-design-vue";
-
 import { throttle } from "lodash-es";
+import { EXAM_STATUS } from "@/constants/dicts";
+import { useMainStore } from "@/store/main";
+
+const userInfo = useMainStore();
 
 const showModal = ref(false);
+const tableLoading = ref(false);
 
 const examInfo = ref<BaseExamInfo>({
   examStatus: "",
@@ -153,14 +164,17 @@ const examRules = {
   schoolId: [{ required: true, message: "请选择学校" }],
 };
 
-const { validate, validateInfos } = Form.useForm(examInfo.value, examRules);
+const { validate, validateInfos, resetFields } = Form.useForm(
+  examInfo.value,
+  examRules
+);
 
 /** 请求参数 */
 const query = reactive<FetchExamListQuery>({
   name: "",
-  schoolId: "",
+  schoolId: userInfo.systemUserInfo?.schoolId || "",
   pageNumber: 1,
-  pageSize: 10,
+  pageSize: 8,
 });
 
 /** table配置 */
@@ -188,11 +202,13 @@ const examTableData = reactive<MultiplePageData<ExamListInfo>>({
 /** 查询学校列表 */
 const querySchoolList = throttle(async (name: string = "") => {
   try {
+    tableLoading.value = true;
     const { result = [], totalCount } = await getSchoolListHttp({
       pageNumber: 1,
       pageSize: 10,
       name,
     });
+    tableLoading.value = false;
     Object.assign(schoolTableData, { result, totalCount });
   } catch (error) {
     console.error(error);
@@ -217,10 +233,9 @@ const queryExamList = async () => {
 watch(() => query.pageNumber, queryExamList);
 
 /** 编辑考试 */
-
 const onEdit = (record: ExamListInfo) => {
-  examInfo.value = Object.assign(examInfo.value, { ...record });
-   toggleAddExamModal(true);
+  Object.assign(examInfo.value, { ...record });
+  toggleAddExamModal(true);
 };
 
 /** 新增考试 */
@@ -236,14 +251,8 @@ const onAddNewExam = () => {
   });
 };
 
-/** 初始化examInfo */
-const resetExamInfo = () => {
-  examInfo.value = Object.assign(examInfo.value, {
-    examStatus: "",
-    name: "",
-    schoolId: "",
-    id: void 0,
-  });
+const currentPageChange = ({ current }: { current: number }) => {
+  query.pageNumber = current;
 };
 
 /** 同步考试数据 */

+ 6 - 3
src/pages/school-manage/index.vue

@@ -39,7 +39,8 @@
           (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
         "
       >
-        <template #bodyCell="{ column, record, index }">
+        <template #bodyCell="{ column, record, index,text }">
+
           <template v-if="column.dataIndex === 'index'">
             {{ index + 1 }}
           </template>
@@ -51,6 +52,9 @@
               <CloseCircleFilled style="color: #f4664a" />
             </template>
           </template>
+          <template v-else-if="column.dataIndex === 'updateTime'">
+           {{text || record['createTime']}}
+          </template>
           <template v-else-if="column.dataIndex === 'operation'">
             <div class="tw-flex tw-items-center">
               <span
@@ -193,7 +197,6 @@ const toggleAddSchoolModal = (show: boolean = true) => {
 };
 
 const currentPageChange = ({ current }: { current: number }) => {
-  console.log("page change", current);
   query.pageNumber = current;
 };
 
@@ -218,7 +221,7 @@ const updateSchoolStatus = (record: SchoolListInfo) => {
 
 /** 编辑学校 */
 const onEdit = (record: SchoolListInfo) => {
-  schoolInfo.value = Object.assign(schoolInfo.value, { ...record });
+  Object.assign(schoolInfo.value, { ...record });
   toggleAddSchoolModal(true);
 };
 

+ 25 - 3
src/pages/subjects-manage/index.vue

@@ -29,7 +29,7 @@
             <a-select-option
               v-for="exam in examTableData.result"
               :key="exam.id"
-              :value="exam.id"
+              :value="`${exam.id}`"
               >{{ exam.name }}</a-select-option
             >
           </a-select>
@@ -90,6 +90,11 @@
       <a-table
         :columns="columns"
         :data-source="subjectsTableData.result"
+        :pagination="{
+          total: subjectsTableData.totalCount,
+          pageSize: query.pageSize,
+        }"
+        @change="currentPageChange"
         :row-class-name="
           (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
         "
@@ -158,6 +163,9 @@ import {
 } from "@/apis/struct";
 import { getSchoolListHttp } from "@/apis/school";
 import { getExamListHttp } from "@/apis/exam";
+import { useMainStore } from "@/store/main";
+
+const userInfo = useMainStore();
 
 const showImportModal = ref(false);
 const importType = ref("subject");
@@ -176,7 +184,7 @@ const query = reactive<
   /** 	分组状态 */
   groupFinish: 0,
   /** 学校id */
-  schoolId: "",
+  schoolId: userInfo.systemUserInfo?.schoolId || '',
   /** 总分截止值 */
   totalScoreMax: "",
   /** 总分起始值 */
@@ -230,12 +238,16 @@ const querySchoolList = async (name?: string) => {
 /** 查询考试列表 */
 const queryExamList = async (name?: string) => {
   try {
+    if(!query.schoolId){
+      return 
+    }
     const { result = [], totalCount } = await getExamListHttp({
       pageNumber: 1,
       pageSize: 10,
       name,
       schoolId: query.schoolId,
     });
+    query.examId = `${result?.[0]?.id || ''}`
     Object.assign(examTableData, { result, totalCount });
   } catch (error) {
     console.error(error);
@@ -261,10 +273,20 @@ watch(
   () => {
     query.examId = "";
     Object.assign(examTableData, { result: [], totalCount: 0 });
-    queryExamList();
+    queryExamList().then(()=>{
+      query.pageNumber = 1
+      querySubjectsList()
+    });
+  },
+  {
+    immediate: true
   }
 );
 
+const currentPageChange = ({ current }: { current: number }) => {
+  query.pageNumber = current;
+};
+
 /** 导入科目 */
 const importSubject = async () => {
   try {

+ 9 - 1
src/pages/user-manage/index.vue

@@ -58,6 +58,10 @@
       <a-table
         :columns="columns"
         :data-source="userTableData.result"
+        :pagination="{
+          total: userTableData.totalCount,
+          pageSize: query.pageSize,
+        }"
         :row-class-name="
           (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
         "
@@ -377,7 +381,7 @@ const clearFileList = () => {
 };
 
 const downloadTemplate = () => {
-  downloadImportUserHttp()
+  downloadImportUserHttp();
 };
 
 const onImportUserList = () => {
@@ -404,6 +408,10 @@ const onUpdateUserPwd = () => {
   });
 };
 
+const currentPageChange = ({ current }: { current: number }) => {
+  query.pageNumber = current;
+};
+
 /** 初始化userInfo */
 const resetUserInfo = () => {
   userInfo.value = {

+ 1 - 3
src/store/main.ts

@@ -1,6 +1,6 @@
 import { defineStore } from "pinia";
 
-const useMainStore = defineStore<"main", Store.MainStoreState>("main", {
+export const useMainStore = defineStore<"main", Store.MainStoreState>("main", {
   state() {
     return {
       loginResult: null,
@@ -9,5 +9,3 @@ const useMainStore = defineStore<"main", Store.MainStoreState>("main", {
   },
 });
 
-
-export default useMainStore

+ 1 - 1
src/utils/auth.ts

@@ -1,6 +1,6 @@
 import { sessionStorageTool } from "@/utils/storage";
 import { SESSION_STORAGE_KEYS } from "@/constants/storage";
-import useMainStore from "@/store/main";
+import { useMainStore } from "@/store/main";
 
 export const getLoginResult = (): LoginResult | null => {
   return sessionStorageTool.get(SESSION_STORAGE_KEYS.LOGIN_RESULT);

+ 2 - 2
types/project.d.ts

@@ -142,7 +142,7 @@ interface FetchExamListQuery extends BaseMutPageQuery {
   /** 考试名称 */
   name?: string;
   /** 学校ID */
-  schoolId?: string;
+  schoolId?: number | string;
 }
 
 interface BaseExamInfo {
@@ -177,7 +177,7 @@ interface FetchSubjectsListQuery extends BaseMutPageQuery {
   /** 	分组状态 */
   groupFinish?: boolean;
   /** 学校id */
-  schoolId: string;
+  schoolId: number | string;
   /** 总分截止值 */
   totalScoreMax: string;
   /** 总分起始值 */

+ 1 - 1
vite.config.ts

@@ -55,7 +55,7 @@ export default defineConfig({
   server: {
     proxy: {
       '^/api': {
-        target: 'http://192.168.10.39:7100'
+        target: 'http://192.168.10.83:7101'
       }
     }
   }