Browse Source

第一次提交3

baiseventeen 2 years ago
parent
commit
c1cc589f16

+ 14 - 0
src/apis/user.ts

@@ -0,0 +1,14 @@
+import axiosInstance from "@/apis/axios.config";
+import { type ILoginUserFrom } from "@/types/user";
+
+const USER_PREFIX = "/api/user"
+
+const userApis = {
+    login: (userForm: ILoginUserFrom) => {
+        return axiosInstance.post(`${USER_PREFIX}/login`, {
+            ...userForm
+        })
+    }
+}
+
+export default userApis

+ 61 - 0
src/components/ViewsWordEditor/ViewsWordEditor.vue

@@ -0,0 +1,61 @@
+<!--
+  Description: 显示作业要求的组件,由写作页面发起。
+  Author: BaiQi
+  Created Date: 2024-6-21
+-->
+<template>
+  <div class="view-word-editor">
+    <el-dialog
+        v-model="alertVisible"
+        center
+        align-center
+        width="60%"
+        class="full-modal"
+        @close="handleClose"
+    >
+      <iframe
+          :src="`https://view.officeapps.live.com/op/view.aspx?src=${props.docxInfo.docxUrl}`"
+          :title="docxInfo.docxTitle"
+          style="width: 100%; height: 75vh;"
+      ></iframe>
+      <template #footer>
+        <div class="button-right">
+          <el-button @click="handleClose">取消</el-button>
+          <el-button type="primary" @click="handleClose">OK</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import {onMounted, ref, watch} from 'vue';
+import './index.scss';
+
+const props = defineProps({
+  alert: Object,
+  docxInfo: Object,
+});
+
+let alertVisible = ref(props.alert.open);
+
+watch(
+    () => props.alert.open,
+    (newVal) => {
+      alertVisible.value = newVal;
+    }
+);
+
+const handleClose = () => {
+  alertVisible.value = false;
+  if (props.alert.onCancel) {
+    props.alert.onCancel();
+  }
+};
+</script>
+
+<script lang="ts">
+  export default {
+    name: "ViewsWordEditor"
+  }
+</script>

+ 0 - 0
src/components/WordEditor/WordEditor.module.scss


+ 144 - 0
src/components/WordEditor/WordEditor.vue

@@ -0,0 +1,144 @@
+<!--
+  Description: onlyoffice组件
+  Author: BaiQi
+  Created Date: 2024-6-21
+-->
+<template>
+    <DocumentEditor
+        id="docxEditor"
+        documentServerUrl="http://47.111.23.171:8082/"
+        :config="config"
+        @events_onDocumentReady="onDocumentReady"
+        @onLoadComponentError="onLoadComponentError"
+        @events_onDocumentStateChange="onDocumentStateChange"
+        v-if="props.documentKey && props.documentTitle && props.documentUrl"
+    ></DocumentEditor>
+</template>
+
+<script lang="ts" setup>
+  import "./WordEditor.module.scss"
+  import {ref, watch, onMounted, defineProps, reactive} from 'vue';
+  import { ElMessage } from 'element-plus';
+  import { DocumentEditor } from '@onlyoffice/document-editor-vue'
+
+  interface IProps {
+    onValueChange?: (state: boolean) => void;
+    documentKey: string;
+    documentTitle: string;
+    documentUrl: string;
+    userId: number;
+    username: string;
+  }
+
+  const props = defineProps<IProps>()
+
+  const documentServerUrl = 'http://47.111.23.171:8082/';
+
+  // OnlyOffice编辑器配置
+  let config = reactive({
+    width: '100%',
+    height: '100%',
+    type: 'desktop',
+    documentType: 'word',
+    document: {
+      fileType: 'docx',
+      key: props.documentKey,
+      title: props.documentTitle,
+      url: props.documentUrl,
+      permissions: {
+        chat: false,
+        comment: false,
+        copy: true,
+        deleteCommentAuthorOnly: false,
+        download: false,
+        edit: true,
+        editCommentAuthorOnly: false,
+        fillForms: false,
+        modifyContentControl: false,
+        print: false,
+        protect: false,
+        review: false,
+      },
+    },
+    editorConfig: {
+      lang: 'zh-CN',
+      callbackUrl: 'http://47.111.23.171:8081/api/onlyoffice/callback',
+      customization: {
+        autosave: false,
+        comments: false,
+        compactHeader: true,
+        compactToolbar: false,
+        compatibleFeatures: false,
+        forcesave: true,
+        help: false,
+        hideRightMenu: true,
+        hideRulers: true,
+        macros: false,
+        mentionShare: false,
+        mobileForceView: false,
+        plugins: false,
+        toolbarHideFileName: true,
+        toolbarNoTabs: false,
+        uiTheme: 'theme-light',
+      },
+      user: {
+        id: props.userId.toString(),
+        name: props.username,
+      },
+    },
+  });
+
+  // 监听 props 中的变化,更新 config
+  watch(
+    () => [props.documentKey, props.documentTitle, props.documentUrl, props.userId, props.username],
+    () => {
+      config = {
+        ...config,
+        document: {
+          ...config.document,
+          key: props.documentKey,
+          title: props.documentTitle,
+          url: props.documentUrl,
+        },
+        editorConfig: {
+          ...config.editorConfig,
+          user: {
+            id: props.userId.toString(),
+            name: props.username,
+          },
+        },
+      };
+    }
+  );
+
+  // 监听 OnlyOffice组件中的文档准备事件
+  const onDocumentReady = (event: any) => {
+    console.log('Document is loaded');
+  };
+
+  // 监听 OnlyOffice组件中的加载组件错误事件
+  const onLoadComponentError = (errorCode: number, errorDescription: string) => {
+    switch (errorCode) {
+      case -1:// Unknown error loading component
+        console.log(errorDescription);
+        break;
+      case -2:// Error load DocsAPI from http://documentserver/
+        console.log(errorDescription);
+        break;
+      case -3:// DocsAPI is not defined
+        console.log(errorDescription);
+        break;
+    }
+  };
+
+  // 监听 OnlyOffice组件中的文档状态变化事件
+  const onDocumentStateChange = (event: any) => {
+    props.onValueChange?.(event.data);
+  };
+</script>
+
+<script lang="ts">
+export default {
+  name: "WordEditor"
+}
+</script>

+ 40 - 0
src/hooks/useCountdown.ts

@@ -0,0 +1,40 @@
+/**
+ * Description: 倒计时,默认60s开始
+ * Author: BaiQi
+ * Created Date: 2024-06-28
+ */
+import { ref, onUnmounted } from 'vue';
+
+export function useCountdown(initCount = 60, interval = 1) {
+    const countdown = ref(0);
+    const isStart = ref(false);
+    let time = null;
+
+    const stop = () => {
+        clearInterval(time);
+    };
+
+    const start = () => {
+        countdown.value = initCount;
+        isStart.value = true;
+        time = setInterval(() => {
+            countdown.value -= interval;
+            if (countdown.value <= 0) {
+                clearInterval(time);
+                isStart.value = false;
+                countdown.value = 0;
+            }
+        }, 1000);
+    };
+
+    onUnmounted(() => {
+        clearInterval(time);
+    });
+
+    return {
+        stop,
+        start,
+        countdown,
+        isStart,
+    };
+}

+ 19 - 0
src/types/user.ts

@@ -0,0 +1,19 @@
+export interface IUser {
+    id: number;
+    name: string;
+    officialEmail: string;
+    officialNumber: string;
+    role: "STUDENT"|"TEACHER"|"ADMIN",
+    userAvatar: string,
+    createTime: string,
+    englishName: string,
+    gender: "MAN"|"FEMALE"|null,
+    birthday: string|null,
+    phone: string|null,
+    contentEmail: string|null,
+}
+
+export interface ILoginUserFrom {
+    officialNumber: string;
+    password: string;
+}

+ 88 - 0
src/types/vo.ts

@@ -0,0 +1,88 @@
+import {IUser} from "@/types/user";
+import {dayjs} from "element-plus";
+
+export interface engagementVO {
+    "id": number,
+    "assignmentId": number,
+    "studentId": number,
+    "score": number,
+    "remark": string,
+    "fileUrl": string,
+    "version": number,
+    "status": string,
+    "fileKey": string,
+}
+
+export interface engagementDetailVO {
+    "id": number,
+    "assignmentVO": IAssignment,
+    "userVO": IUser,
+    "score": number|null,
+    "remark": string|null,
+    "fileUrl": string,
+    "version": number,
+    "status": string,
+    "fileKey": string,
+}
+
+export interface IAssignment {
+    assignmentId: number;
+
+    assignmentName: string;
+
+    description: string;
+
+    descriptionFile: string|null; // 作业要求,Word/Pdf文件
+
+    attachments: string[]|null; // 作业附件
+
+    teacherId: number; // 发布作业的老师的Id
+
+    courseId: number; // 哪个课程下的assignment
+
+    startTime: string;
+
+    endTime: string;
+
+    createTime: string;
+
+    status: string;
+}
+
+export interface IAssignmentTableColumn {
+    title: string;
+    dataIndex: 'desc' | 'publisher' | 'startDate' | 'endDate' | 'details' | 'writing' | 'assignmentId';
+    key: 'desc' | 'publisher' | 'startDate' | 'endDate' | 'details' | 'writing' | 'assignmentId';
+}
+
+export interface IAssignmentTableItem {
+    desc: string;
+    publisher: string;
+    startDate: string;
+    endDate: string;
+    assignmentId: number;
+}
+
+
+export interface ITranslationVO {
+    queryText: string;
+
+    queryResult: string;
+
+    targetLanguage: string; // 目标语言类型
+
+    queryTime: string;
+}
+
+export interface CourseVO {
+    courseId: number;
+    courseName: string;
+    teacherIds: number[];
+    courseImages: string[];
+    targetGrade: string;
+    startTime: string;
+    endTime: string;
+    createTime: string;
+    description: string;
+}
+

+ 20 - 0
vite.config.ts

@@ -0,0 +1,20 @@
+import { fileURLToPath, URL } from 'node:url'
+
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [
+    vue(),
+  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    }
+  },
+  server: {
+    host: '127.0.0.1',
+    port: 4000
+  }
+})