wuheng 1 年之前
父節點
當前提交
a73fae52ed

+ 1 - 1
src/locales/lang/zh-cn.ts

@@ -74,7 +74,7 @@ const locale: LocaleMessages<I18nType.Schema> = {
         _value: '系统管理',
         auth: '权限管理',
         role: '角色管理',
-        route: '路由管理',
+        route: '课程分类',
         user: '用户管理',
         sort: '课程分类',
         student: '学生管理',

+ 1 - 1
src/router/modules/management.ts

@@ -74,7 +74,7 @@ const management: AuthRoute.Route = {
       path: '/management/route',
       component: 'self',
       meta: {
-        title: '路由管理',
+        title: '系列分类',
         i18nTitle: 'message.routes.management.route',
         requiresAuth: true,
         icon: 'material-symbols:route'

+ 1 - 1
src/views/lesson/schedule/api.ts

@@ -159,7 +159,7 @@ export function querySubject(
   pageSize: number,
   params: SubjectParams
 ): Promise<Service.RequestResult<SubjectParams[]>> {
-  return request.post(`/subject/selectByCondition?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+  return request.post(`/subject/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
 }
 
 export interface ClassParams {

+ 83 - 0
src/views/management/route/api.ts

@@ -0,0 +1,83 @@
+import { request } from '@/service/request';
+
+// 参数接口
+export interface QueryParams {
+  id?: number;
+  name?: string;
+  description?: string;
+  categoryId?: number;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+  disabled?: string;
+}
+
+// 响应接口
+export interface Res {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+  total: number;
+}
+
+export function search(
+  pageNum: number,
+  pageSize: number,
+  params: QueryParams
+): Promise<Service.RequestResult<QueryParams[]>> {
+  return request.post(`/subject/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}
+
+export function add(params: QueryParams): Promise<Service.RequestResult<Res>> {
+  return request.post(`/subject/add`, params);
+}
+
+export function edit(params: QueryParams): Promise<Service.RequestResult<Res>> {
+  return request.post(`/subject/update`, params);
+}
+
+export function del(id: number): Promise<Service.RequestResult<Res>> {
+  return request.delete(`/subject/delete/${id}`);
+}
+
+export interface CateGoryParams {
+  id?: number;
+  name?: string;
+  description?: string;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+  disabled?: string;
+}
+
+export function queryCateGory(
+  pageNum: number,
+  pageSize: number,
+  params: CateGoryParams
+): Promise<Service.RequestResult<CateGoryParams[]>> {
+  return request.post(`/category/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}
+
+// 参数接口
+export interface ScoreParams {
+  id?: number;
+  studentNumber?: string;
+  categoryId?: number;
+  subjectId?: number;
+  testDate?: Record<string, unknown>;
+  score?: number;
+  passRate?: number;
+  excelRate?: number;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+  comment?: string;
+}
+
+export function queryScore(
+  pageNum: number,
+  pageSize: number,
+  params: ScoreParams
+): Promise<Service.RequestResult<ScoreParams[]>> {
+  return request.post(`/scores/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}

+ 151 - 0
src/views/management/route/component/crud.ts

@@ -0,0 +1,151 @@
+import type { CreateCrudOptionsRet, CreateCrudOptionsProps } from '@fast-crud/fast-crud';
+import dayjs from 'dayjs';
+import { queryScore } from '../api';
+export default function createCrudOptions(crudOptionsProps: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  return {
+    crudOptions: {
+      request: {
+        pageRequest: async ({ page, query }) => {
+          query.subjectId = crudOptionsProps.context?.subjectId;
+          const { total, data } = await queryScore(page.offset + 1, page.limit, query);
+          return { records: data, total, currentPage: page.offset, pageSize: page.limit };
+        },
+        addRequest: () => {
+          return Promise.resolve(true);
+        },
+        editRequest: () => {
+          return Promise.resolve(true);
+        },
+        delRequest: () => {
+          return Promise.resolve(true);
+        }
+      },
+      rowHandle: {
+        show: false
+      },
+      toolbar: {
+        show: false
+      },
+      actionbar: {
+        show: false
+      },
+      search: {
+        show: false,
+        buttons: {
+          search: {
+            show: false
+          },
+          reset: {
+            show: false
+          }
+        }
+      },
+      columns: {
+        studentNumber: {
+          title: '学员编号',
+          search: { show: false },
+          type: 'text',
+          column: {
+            align: 'center',
+            width: 140
+          },
+          form: {
+            show: false
+          }
+        },
+        testDate: {
+          title: '考试日期',
+          type: 'datetime',
+          search: { show: false },
+          column: {
+            align: 'center'
+          },
+          form: {
+            show: false
+          },
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+        createTime: {
+          key: 'createTime',
+          title: '创建时间',
+          type: 'datetime',
+          column: {
+            width: 250,
+            align: 'center'
+          },
+          search: { show: false },
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+        modifyTime: {
+          title: '修改时间',
+          key: 'modifyTime',
+          type: 'datetime',
+          align: 'center',
+          column: {
+            width: 250,
+            align: 'center'
+          },
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+        passRate: {
+          title: '及格率',
+          type: 'text',
+          search: { show: false },
+          column: {
+            align: 'center'
+          }
+        },
+        excelRate: {
+          title: '通过率',
+          type: 'text',
+          search: { show: false },
+          column: {
+            align: 'center'
+          }
+        },
+        comment: {
+          title: '备注信息',
+          type: 'text',
+          search: { show: false },
+          column: {
+            align: 'center',
+            width: 200
+          }
+        }
+      }
+    }
+  };
+}

+ 26 - 0
src/views/management/route/component/index.vue

@@ -0,0 +1,26 @@
+<template>
+  <div class="h-full bg-white">
+    <fs-crud ref="crudRef" v-bind="crudBinding" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted } from 'vue';
+import { useFs } from '@fast-crud/fast-crud';
+import createCrudOptions from './crud';
+const props = defineProps({
+  subjectId: {
+    type: Number,
+    default: 0
+  }
+});
+const context = {
+  subjectId: props.subjectId
+};
+const { crudRef, crudBinding, crudExpose } = useFs({ createCrudOptions, context });
+onMounted(() => {
+  crudExpose.doRefresh();
+});
+</script>
+
+<style scoped></style>

+ 188 - 0
src/views/management/route/crud.ts

@@ -0,0 +1,188 @@
+import type { CreateCrudOptionsRet, CreateCrudOptionsProps } from '@fast-crud/fast-crud';
+import { dict } from '@fast-crud/fast-crud';
+import dayjs from 'dayjs';
+import { search, add, edit, del, queryCateGory } from './api';
+export default function createCrudOptions(crudOptionsProps: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  return {
+    crudOptions: {
+      container: {
+        is: 'fs-layout-card'
+      },
+      request: {
+        pageRequest: async ({ page, query }) => {
+          const { total, data } = await search(page.offset + 1, page.limit, query);
+          return { records: data, total, currentPage: page.offset, pageSize: page.limit };
+        },
+        addRequest: ({ form }) => {
+          form.depname = form.name;
+          return add(form);
+        },
+        editRequest: ({ form }) => {
+          form.depname = form.name;
+          edit(form);
+        },
+        delRequest: ({ row }) => {
+          return del(row.id);
+        }
+      },
+      columns: {
+        id: {
+          title: 'ID',
+          key: 'id',
+          type: 'text',
+          search: { show: true },
+          column: {
+            width: 50,
+            align: 'center'
+          },
+          form: {
+            show: false
+          }
+        },
+        categoryId: {
+          title: '类别',
+          key: 'categoryId',
+          type: 'dict-select',
+          dict: dict({
+            async getData() {
+              const result = await queryCateGory(1, 1000, {});
+              return result.data?.map(r => {
+                return {
+                  label: r.name,
+                  value: r.id
+                };
+              }) as any[];
+            }
+          }),
+          search: { show: true },
+          column: {
+            show: false
+          },
+          form: {
+            show: true
+          }
+        },
+        name: {
+          title: '类别名称',
+          search: { show: true },
+          key: 'name',
+          type: 'text',
+          column: {
+            width: 150,
+            align: 'center'
+          },
+          form: {
+            show: true
+          }
+        },
+        description: {
+          title: '描述',
+          key: 'description',
+          type: 'text',
+          search: { show: false },
+          column: {
+            align: 'center'
+          }
+        },
+        createTime: {
+          key: 'createTime',
+          title: '创建时间',
+          type: 'datetime',
+          column: {
+            width: 250,
+            align: 'center'
+          },
+          search: { show: true },
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+        modifyTime: {
+          title: '修改时间',
+          key: 'modifyTime',
+          type: 'datetime',
+          align: 'center',
+          column: {
+            width: 250,
+            align: 'center'
+          },
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+        disabled: {
+          key: 'disabled',
+          title: '状态',
+          type: 'dict-select',
+          dict: dict({
+            data: [
+              { value: 'N', label: '启用' },
+              { value: 'Y', label: '禁用' }
+            ]
+          }),
+          search: { show: true },
+          column: {
+            width: 100,
+            align: 'center'
+          }
+        }
+      },
+      rowHandle: {
+        buttons: {
+          scores: {
+            text: null,
+            size: 'small',
+            icon: 'carbon:result-draft',
+            tooltip: {
+              slots: {
+                default() {
+                  return '录入成绩';
+                }
+              }
+            },
+            click: ({ row }) => {
+              if (crudOptionsProps.context) {
+                crudOptionsProps.context.importActiveFunc(row.id);
+              }
+            }
+          },
+          query: {
+            text: null,
+            size: 'small',
+            icon: 'icon-park-outline:history-query',
+            tooltip: {
+              slots: {
+                default() {
+                  return '查看成绩';
+                }
+              }
+            },
+            click: ({ row }) => {
+              if (crudOptionsProps.context) {
+                crudOptionsProps.context.viewActiveFunc(row.id);
+              }
+            }
+          }
+        }
+      }
+    }
+  };
+}

+ 57 - 6
src/views/management/route/index.vue

@@ -1,13 +1,64 @@
 <template>
-  <div>路由管理</div>
+  <div class="h-full bg-white">
+    <fs-crud ref="crudRef" v-bind="crudBinding" />
+
+    <n-drawer v-model:show="importActive" default-width="40%" placement="right" resizable>
+      <n-drawer-content title="导入科目学员成绩">
+        <n-space> 当前上传操作用于处理 批量导入 学员成绩分数功能 </n-space>
+        <n-upload
+          class="flex-col-center"
+          style="margin-top: 30%"
+          multiple
+          directory-dnd
+          action="https://www.mocky.io/v2/5e4bafc63100007100d8b70f"
+          :max="1"
+        >
+          <n-upload-dragger>
+            <div>
+              <svg-icon icon="material-symbols:upload" class="w-30 h-30" style="margin: 0 auto" />
+            </div>
+            <n-text style="font-size: 16px"> 点击或者拖动文件到该区域来上传 </n-text>
+            <n-p depth="3" style="margin: 8px 0 0 0">
+              请不要上传敏感数据,比如你的银行卡号和密码,信用卡号有效期和安全码 上传成功后, 后台会自动解析
+              学员的成绩分数, 并录入成绩库
+            </n-p>
+          </n-upload-dragger>
+        </n-upload>
+      </n-drawer-content>
+    </n-drawer>
+
+    <n-drawer v-model:show="viewActive" default-width="50%" placement="left" resizable>
+      <n-drawer-content title="查看科目学员成绩">
+        <ScoresView :subject-id="subjectId" />
+      </n-drawer-content>
+    </n-drawer>
+  </div>
 </template>
 
 <script setup lang="ts">
-import type { QueryParams } from '~/src/service/api/user';
-import { query } from '~/src/service/api/user';
-const queryData: QueryParams = {};
-
-query(1, 20, queryData);
+import { onMounted, ref } from 'vue';
+import { useFs } from '@fast-crud/fast-crud';
+import createCrudOptions from './crud';
+import ScoresView from './component/index.vue';
+const importActive = ref<boolean>(false);
+const viewActive = ref<boolean>(false);
+const subjectId = ref<number>(0);
+const context: any = {
+  importActiveFunc: (id: number) => {
+    if (id > 0) {
+      importActive.value = true;
+    }
+  },
+  viewActiveFunc: (id: number) => {
+    subjectId.value = id;
+    viewActive.value = true;
+  }
+};
+const { crudRef, crudBinding, crudExpose } = useFs({ createCrudOptions, context });
+onMounted(() => {
+  crudExpose.doRefresh();
+});
 </script>
 
 <style scoped></style>
+./component/scoreCrud

+ 1 - 3
src/views/management/student/index.vue

@@ -16,9 +16,7 @@
         >
           <n-upload-dragger>
             <div style="margin-bottom: 12px">
-              <n-icon size="48" :depth="3">
-                <archive-icon />
-              </n-icon>
+              <svg-icon icon="material-symbols:upload" class="w-30 h-30" style="margin: 0 auto" />
             </div>
             <n-text style="font-size: 16px"> 点击或者拖动文件到该区域来上传 </n-text>
             <n-p depth="3" style="margin: 8px 0 0 0">