wuheng 1 tahun lalu
induk
melakukan
3263bde81c

TEMPAT SAMPAH
src/public/java.pdf


+ 2 - 0
src/typings/page-route.d.ts

@@ -57,6 +57,7 @@ declare namespace PageRoute {
     | 'archives_students'
     | 'archives_other'
     | 'archives_attendance'
+    | 'archives_students_component'
     | 'lesson'
     | 'lesson_calendar'
     | 'lesson_checkin'
@@ -137,6 +138,7 @@ declare namespace PageRoute {
     | 'archives_students'
     | 'archives_other'
     | 'archives_attendance'
+    | 'archives_students_component'
     | 'management_attendance'
     | 'management_auth'
     | 'management_role'

+ 28 - 0
src/views/archives/students/api.ts

@@ -0,0 +1,28 @@
+import { request } from '@/service/request';
+
+interface GroupStudentsPojo {
+  studentId: number;
+  studentName: string;
+  avatar: string;
+  studentNumber: string;
+  managerName: string;
+  phone: string;
+  email: string;
+  gender: string;
+  enrollmentDate: string;
+  morning?: string;
+  afternoon?: string;
+  checkinDate: Date;
+  admissionsName: string;
+  scheduleId?: number;
+  category?: string;
+  subject?: string;
+  teacher?: string;
+  teacherPhone?: string;
+  groupId?: string;
+  groupName?: string;
+}
+
+export function getStudentByKeyword(keyword: string): Promise<Service.RequestResult<GroupStudentsPojo[]>> {
+  return request.get(`/student/getStudentByKeyword?keyword=${keyword}`);
+}

+ 51 - 0
src/views/archives/students/component/api.ts

@@ -0,0 +1,51 @@
+import { request } from '@/service/request';
+// 参数接口
+export interface ArchivesParams {
+  id?: number;
+  archiveNumber?: string;
+  studentNumber?: string;
+  filePath?: string;
+  arctype?: string;
+  remarks?: string;
+  filetype?: string;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  validityTime?: Record<string, unknown>;
+  managerId?: number;
+  createDate?: Record<string, unknown>;
+  createUid?: number;
+}
+
+// 响应接口
+export interface ArchivesRes {
+  status: boolean;
+  msg: string;
+  data: any;
+  code: number;
+}
+
+/**
+ * 获取档案
+ * @param {object} params EasArcArchives
+ * @param {number} params.id
+ * @param {string} params.archiveNumber 文件电子档案号
+ * @param {string} params.studentNumber 当前电子档案归属那一个学员档案下
+ * @param {string} params.filePath 文件存储的路径
+ * @param {string} params.arctype 档案类型
+ * @param {string} params.remarks 文件备注
+ * @param {string} params.filetype 文件类型
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {object} params.validityTime 档案有效期截至时间
+ * @param {number} params.managerId 档案归属负责人
+ * @param {object} params.createDate 档案创建时间, 用于文件归档用
+ * @param {number} params.createUid 创建用户ID
+ * @returns
+ */
+export function getArchives(params: ArchivesParams): Promise<Service.RequestResult<ArchivesParams[]>> {
+  return request.post(`/archive/getArchives`, params);
+}
+
+export function getFile(archiveNumber: string): Promise<Service.RequestResult<ArchivesRes>> {
+  return request.get(`/archive/getTokenByArchiveNumber?archiveNumber=${archiveNumber}`);
+}

+ 181 - 0
src/views/archives/students/component/crud.ts

@@ -0,0 +1,181 @@
+import type { CreateCrudOptionsRet, CreateCrudOptionsProps } from '@fast-crud/fast-crud';
+import dayjs from 'dayjs';
+import { dict } from '@fast-crud/fast-crud';
+import { getArchives, getFile } from './api';
+export default function createCrudOptions(crudOptionsProps: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  return {
+    crudOptions: {
+      pagination: {
+        show: false
+      },
+      request: {
+        pageRequest: async ({ page, query }) => {
+          query.studentNumber = crudOptionsProps.context?.studentNumber;
+          const { data } = await getArchives(query);
+          return { records: data, total: 0, currentPage: page.offset, pageSize: page.limit };
+        },
+        addRequest: () => {
+          return Promise.resolve(true);
+        },
+        editRequest: () => {
+          return Promise.resolve(true);
+        },
+        delRequest: () => {
+          return Promise.resolve(true);
+        }
+      },
+      rowHandle: {
+        show: true,
+        buttons: {
+          remove: {
+            show: false
+          },
+          edit: {
+            show: false
+          },
+          view: {
+            show: false
+          },
+          review: {
+            text: null,
+            size: 'small',
+            icon: 'lucide:view',
+            tooltip: {
+              slots: {
+                default() {
+                  return '查看文件';
+                }
+              }
+            },
+            click: async ({ row }) => {
+              const { data } = await getFile(row.archiveNumber);
+              crudOptionsProps.context?.viewActiveFunc(row.arctype, data);
+            }
+          }
+        }
+      },
+      toolbar: {
+        show: false
+      },
+      actionbar: {
+        show: false
+      },
+      search: {
+        show: false
+      },
+      columns: {
+        studentNumber: {
+          title: '学员编号',
+          search: {
+            show: true
+          },
+          type: 'text',
+          column: {
+            align: 'center'
+          },
+          form: {
+            show: true
+          }
+        },
+        arctype: {
+          title: '档案类型',
+          type: 'text',
+          column: {
+            align: 'center'
+          }
+        },
+        filetype: {
+          title: '类别',
+          type: 'dict-select',
+          dict: dict({
+            data: [
+              { value: 'avatar', label: '头像' },
+              { value: 'prefile', label: '个人资料' },
+              { value: 'scores', label: '考核' },
+              { value: 'attendance', label: '出勤' },
+              { value: 'other', label: '其他' }
+            ]
+          })
+        },
+        remarks: {
+          title: '备注',
+          type: 'text',
+          column: {
+            align: 'center'
+          }
+        },
+        validityTime: {
+          title: '档案有效期',
+          type: 'datetime',
+          column: {
+            align: 'center'
+          },
+          form: {
+            show: false
+          },
+          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');
+            }
+          }
+        },
+        createTime: {
+          key: 'createTime',
+          title: '创建时间',
+          type: 'datetime',
+          column: {
+            align: 'center'
+          },
+          form: {
+            show: false
+          },
+          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: {
+            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');
+            }
+          }
+        }
+      }
+    }
+  };
+}

+ 57 - 0
src/views/archives/students/component/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <div class="wh-full bg-white">
+    <fs-crud ref="crudRef" v-bind="crudBinding" />
+
+    <n-drawer v-model:show="active" default-width="80%" placement="left" resizable>
+      <n-drawer-content title="在线预览文件">
+        <ExcelView v-if="fileType === 'XLSX'" :url="fileURL" />
+        <WordView v-if="fileType === 'DOCX'" :url="fileURL" />
+        <ImageView v-if="fileType === 'IMAGE'" :url="fileURL" />
+        <PdfView v-if="fileType === 'PDF'" :url="fileURL" />
+      </n-drawer-content>
+    </n-drawer>
+  </div>
+</template>
+<script setup lang="ts">
+import { watch, ref } from 'vue';
+import { useFs } from '@fast-crud/fast-crud';
+import createCrudOptions from './crud';
+import ExcelView from './excelView.vue';
+import WordView from './wordView.vue';
+import ImageView from './imageView.vue';
+import PdfView from './pdfView.vue';
+
+const fileURL = ref<string>('');
+const fileType = ref<string>('');
+const active = ref<boolean>(false);
+
+const props = defineProps({
+  studentNumber: {
+    type: String,
+    default: 'default'
+  }
+});
+
+const context = {
+  studentNumber: props.studentNumber,
+  viewActiveFunc: (type: string, token: string) => {
+    fileURL.value = `http://localhost:3200/proxy-pattern/archive/getFileByToken?archiveToken=${token}`;
+    fileType.value = type;
+    active.value = true;
+  }
+};
+
+const { crudRef, crudBinding, crudExpose } = useFs({ createCrudOptions, context });
+
+watch(
+  () => props.studentNumber,
+  () => {
+    context.studentNumber = 'default';
+    if (props.studentNumber) {
+      context.studentNumber = props.studentNumber;
+    }
+    crudExpose.doRefresh();
+  }
+);
+</script>
+<style scoped lang="scss"></style>

+ 66 - 3
src/views/archives/students/index.vue

@@ -1,5 +1,68 @@
 <template>
-  <div></div>
+  <div class="wh-full bg-white">
+    <div class="search-box">
+      <n-gradient-text
+        :gradient="{
+          from: '#1890ff',
+          to: '#bc3c1a'
+        }"
+      >
+        <h1>请搜索学员后查看学员档案</h1>
+      </n-gradient-text>
+      <n-select
+        v-model:value="studentNumber"
+        size="large"
+        filterable
+        placeholder="搜索学员"
+        :options="options"
+        :loading="loading"
+        clearable
+        remote
+        @update:value="goToList"
+        @search="handleSearch"
+      />
+    </div>
+    <ArchivesList :student-number="studentNumber" />
+  </div>
 </template>
-<script setup lang="ts"></script>
-<style scoped></style>
+<script setup lang="ts">
+import { ref } from 'vue';
+import type { SelectOption } from 'naive-ui';
+import { getStudentByKeyword } from './api';
+import ArchivesList from './component/index.vue';
+
+const options = ref<SelectOption[]>([]);
+
+const loading = ref(false);
+const studentNumber = ref<string>('');
+
+function handleSearch(query: string) {
+  if (!query.length) {
+    options.value = [];
+    return;
+  }
+  loading.value = true;
+  getStudentByKeyword(query).then(result => {
+    const optionData = result.data?.map(res => {
+      return {
+        label: res.studentName,
+        value: res.studentNumber
+      };
+    });
+    options.value = optionData as SelectOption[];
+    loading.value = false;
+  });
+}
+function goToList(value: string) {
+  studentNumber.value = value;
+}
+</script>
+<style scoped>
+.search-box {
+  width: 26%;
+  margin: 0 auto;
+}
+h1 {
+  font-size: 36px;
+}
+</style>

+ 1 - 4
src/views/dashboard/analysis/index.vue

@@ -2,15 +2,12 @@
   <n-space :vertical="true" :size="16">
     <top-chart />
     <data-card />
-    <div>
-      <PDFView :pdf-url="jsPdf" />
-    </div>
+    <div></div>
     <bottom-part />
   </n-space>
 </template>
 
 <script lang="ts" setup>
-import jsPdf from '@/public/java.pdf';
 import { BottomPart, DataCard, TopChart } from './components';
 </script>
 

+ 6 - 5
src/views/index.ts

@@ -10,6 +10,11 @@ export const views: Record<
   login: () => import('./_builtin/login/index.vue'),
   'not-found': () => import('./_builtin/not-found/index.vue'),
   about: () => import('./about/index.vue'),
+  archives_attendance: () => import('./archives/attendance/index.vue'),
+  archives_other: () => import('./archives/other/index.vue'),
+  archives_scores: () => import('./archives/scores/index.vue'),
+  archives_students_component: () => import('./archives/students/component/index.vue'),
+  archives_students: () => import('./archives/students/index.vue'),
   'auth-demo_permission': () => import('./auth-demo/permission/index.vue'),
   'auth-demo_super': () => import('./auth-demo/super/index.vue'),
   component_button: () => import('./component/button/index.vue'),
@@ -34,15 +39,11 @@ export const views: Record<
   function_tab: () => import('./function/tab/index.vue'),
   lesson_calendar: () => import('./lesson/calendar/index.vue'),
   lesson_checkin: () => import('./lesson/checkin/index.vue'),
-  lesson_score: () => import('./lesson/score/index.vue'),
   lesson_classroom: () => import('./lesson/classroom/index.vue'),
   lesson_group: () => import('./lesson/group/index.vue'),
   lesson_schedule: () => import('./lesson/schedule/index.vue'),
+  lesson_score: () => import('./lesson/score/index.vue'),
   lesson_student: () => import('./lesson/student/index.vue'),
-  archives_scores: () => import('./archives/scores/index.vue'),
-  archives_students: () => import('./archives/students/index.vue'),
-  archives_other: () => import('./archives/other/index.vue'),
-  archives_attendance: () => import('./archives/attendance/index.vue'),
   management_attendance: () => import('./management/attendance/index.vue'),
   management_auth: () => import('./management/auth/index.vue'),
   management_role: () => import('./management/role/index.vue'),