From 285ce38990253ea1622b2b2e5da9b02253711c14 Mon Sep 17 00:00:00 2001
From: In_Chh <2319397152@qq..com>
Date: Fri, 16 Sep 2022 09:42:38 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=B0=8F?=
 =?UTF-8?q?=E7=BB=84=E9=95=BF=E4=B8=BA=E7=BB=84=E5=91=98=E6=89=93=E5=88=86?=
 =?UTF-8?q?=E5=86=99=E8=AF=84=E8=AF=AD=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 mock/student/practice.ts                    | 14 +++
 mock/sys/menu.ts                            | 46 +++++-----
 src/api/student/model/practiceModel.ts      |  5 ++
 src/api/student/practice.ts                 | 21 +++++
 src/views/captain/practical/RemarkModal.vue | 97 +++++++++++++++++++++
 src/views/captain/practical/index.vue       | 21 ++++-
 6 files changed, 180 insertions(+), 24 deletions(-)
 create mode 100644 src/views/captain/practical/RemarkModal.vue

diff --git a/mock/student/practice.ts b/mock/student/practice.ts
index 93ee0ac..d888f09 100644
--- a/mock/student/practice.ts
+++ b/mock/student/practice.ts
@@ -196,4 +196,18 @@ export default [
       return resultSuccess({});
     },
   },
+  {
+    url: "/dev-api/internInfo/score/xz/:id",
+    method: "get",
+    response: () => {
+      return resultSuccess({ score: 99, remark: "表现优秀" });
+    },
+  },
+  {
+    url: "/dev-api/internInfo/mark/xz/:id",
+    method: "put",
+    response: () => {
+      return resultSuccess({});
+    },
+  },
 ] as MockMethod[];
diff --git a/mock/sys/menu.ts b/mock/sys/menu.ts
index 20e40a7..4052d0d 100644
--- a/mock/sys/menu.ts
+++ b/mock/sys/menu.ts
@@ -243,7 +243,7 @@ const accountRoute = {
 // };
 
 // @ts-ignore
-/* const practicalStudent = {
+const practicalStudent = {
   path: "/practical",
   name: "Practical",
   component: "LAYOUT",
@@ -278,28 +278,28 @@ const accountRoute = {
       },
     },
   ],
-}; */
+};
 
 // @ts-ignore
-const practicalTeacher = {
-  path: "/practical",
-  name: "Practical",
-  component: "LAYOUT",
-  meta: {
-    icon: "simple-icons:about-dot-me",
-    title: "实习评价",
-  },
-  children: [
-    {
-      path: "menber",
-      name: "Member",
-      component: "/teacher/practical/member/index.vue",
-      meta: {
-        title: "成员信息",
-      },
-    },
-  ],
-};
+// const practicalTeacher = {
+//   path: "/practical",
+//   name: "Practical",
+//   component: "LAYOUT",
+//   meta: {
+//     icon: "simple-icons:about-dot-me",
+//     title: "实习评价",
+//   },
+//   children: [
+//     {
+//       path: "menber",
+//       name: "Member",
+//       component: "/teacher/practical/member/index.vue",
+//       meta: {
+//         title: "成员信息",
+//       },
+//     },
+//   ],
+// };
 
 const lectureNoteRoute = {
   path: "lectureNoteList",
@@ -370,8 +370,8 @@ export default [
         teachingStudyRoute,
         accountRoute,
         rootRouter,
-        // practicalStudent,
-        practicalTeacher,
+        practicalStudent,
+        // practicalTeacher,
       ];
 
       return resultSuccess(menu);
diff --git a/src/api/student/model/practiceModel.ts b/src/api/student/model/practiceModel.ts
index 09cc6b5..c004b8b 100644
--- a/src/api/student/model/practiceModel.ts
+++ b/src/api/student/model/practiceModel.ts
@@ -76,3 +76,8 @@ export interface LeaderWorkModel {
   classActivity: string;
   docLink: string;
 }
+
+export interface GroupScoreModel {
+  score: number;
+  remark: string;
+}
diff --git a/src/api/student/practice.ts b/src/api/student/practice.ts
index 5ce8b66..28e9676 100644
--- a/src/api/student/practice.ts
+++ b/src/api/student/practice.ts
@@ -1,5 +1,6 @@
 import {
   GroupMemberListResultModel,
+  GroupScoreModel,
   LeaderWorkModel,
   LectureNoteItemModel,
   LectureNoteListResultModel,
@@ -35,6 +36,8 @@ enum Api {
   GetGroupNumber = "/group/leader/list",
   GetLeaderWorkInfo = "/leaderWork/getInfo",
   SaveOrUpdateLeaderWorkInfo = "/leaderWork/saveOrUpdate",
+  GetGroupScore = "/internInfo/score/xz",
+  SetGroupScore = "/internInfo/mark/xz",
 }
 
 /**
@@ -281,3 +284,21 @@ export const saveOrUpdateLeaderWorkInfo = (leaderWork: LeaderWorkModel) =>
     url: Api.SaveOrUpdateLeaderWorkInfo,
     params: leaderWork,
   });
+
+/**
+ * 实习小组组长获取实习生小组成绩信息
+ * @param userId 实习生id
+ */
+export const getGroupScoreByUserId = (userId: number) =>
+  defHttp.get<GroupScoreModel>({
+    url: Api.GetGroupScore + `/${userId}`,
+  });
+
+export const setGroupScore = (userId: number, score: number, remark: string) =>
+  defHttp.put({
+    url: Api.SetGroupScore + `/${userId}`,
+    params: {
+      score,
+      remark,
+    },
+  });
diff --git a/src/views/captain/practical/RemarkModal.vue b/src/views/captain/practical/RemarkModal.vue
new file mode 100644
index 0000000..21e793f
--- /dev/null
+++ b/src/views/captain/practical/RemarkModal.vue
@@ -0,0 +1,97 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" title="表现评价" @ok="submit">
+    <BasicForm @register="registerForm" @submit="handleSubmit" :model="userData" />
+  </BasicModal>
+</template>
+
+<script lang="ts">
+  import { defineComponent, ref } from "vue";
+  import { BasicModal, useModalInner } from "/@/components/Modal";
+  import { BasicForm, FormSchema, useForm } from "/@/components/Form";
+  import { setGroupScore } from "/@/api/student/practice";
+  import { useMessage } from "/@/hooks/web/useMessage";
+
+  export default defineComponent({
+    name: "RemarkEdit",
+    components: { BasicForm, BasicModal },
+    setup() {
+      const defaultUserData = { userId: 0, score: 0, remark: "" };
+      const userData = ref(defaultUserData);
+      const formSchema: FormSchema[] = [
+        {
+          field: "score",
+          label: "评分",
+          component: "InputNumber",
+          colProps: {
+            span: 24,
+          },
+          rules: [
+            {
+              type: "number",
+              required: true,
+              validator: async (_rule, value) => {
+                if (!value) {
+                  return Promise.reject("评分不能为空");
+                }
+                if (value < 0 || value > 100 || value % 1 != 0) {
+                  return Promise.reject("请输入0-100之间的一个整数");
+                }
+                return Promise.resolve();
+              },
+              trigger: "change",
+            },
+          ],
+        },
+        {
+          field: "remark",
+          label: "评语",
+          component: "InputTextArea",
+          required: true,
+          colProps: {
+            span: 24,
+          },
+          componentProps: {
+            row: 4,
+          },
+        },
+      ];
+
+      const [registerForm, { submit }] = useForm({
+        labelWidth: 120,
+        schemas: formSchema,
+        showResetButton: false,
+        showSubmitButton: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      const [registerModal, { closeModal }] = useModalInner((data) => {
+        userData.value = data;
+      });
+
+      const { createMessage } = useMessage();
+
+      function handleSubmit(value) {
+        setGroupScore(userData.value.userId, value.score, value.remark).then(() => {
+          createMessage.success("提交成功");
+          closeModal();
+        });
+      }
+
+      function handleModalClose() {
+        userData.value = defaultUserData;
+        return Promise.resolve(true);
+      }
+
+      return {
+        registerModal,
+        registerForm,
+        handleSubmit,
+        handleModalClose,
+        submit,
+        userData,
+      };
+    },
+  });
+</script>
diff --git a/src/views/captain/practical/index.vue b/src/views/captain/practical/index.vue
index acbea61..4369e9f 100644
--- a/src/views/captain/practical/index.vue
+++ b/src/views/captain/practical/index.vue
@@ -24,11 +24,17 @@
                 icon: 'ant-design:info-circle-outlined',
                 onClick: handleTeachingStudyDesc.bind(null, record),
               },
+              {
+                label: '表现打分',
+                icon: 'ant-design:info-circle-outlined',
+                onClick: handleEditRemark.bind(null, record),
+              },
             ]"
           />
         </template>
       </template>
     </BasicTable>
+    <RemarkModal @register="registerRemarkModal" />
   </div>
 </template>
 
@@ -36,14 +42,17 @@
   import { defineComponent } from "vue";
   import { BasicColumn, BasicTable, TableAction, useTable } from "/@/components/Table";
   import { useRouter } from "vue-router";
-  import { getGroupNumberPageByGroupId } from "/@/api/student/practice";
+  import { getGroupNumberPageByGroupId, getGroupScoreByUserId } from "/@/api/student/practice";
   import { MarkTypeEnum } from "/@/enums/markTypeEnum";
+  import { useModal } from "/@/components/Modal";
+  import RemarkModal from "./RemarkModal.vue";
 
   export default defineComponent({
     name: "GroupLeaderMark",
     components: {
       BasicTable,
       TableAction,
+      RemarkModal,
     },
     setup() {
       const columns: BasicColumn[] = [
@@ -86,6 +95,9 @@
           fixed: "right",
         },
       });
+
+      const [registerRemarkModal, { openModal: openRemarkModal }] = useModal();
+
       const router = useRouter();
 
       function handleReloadCurrent() {
@@ -116,12 +128,19 @@
         });
       }
 
+      async function handleEditRemark(record) {
+        const score = await getGroupScoreByUserId(record.userId);
+        openRemarkModal(true, { ...score, userId: record.userId });
+      }
+
       return {
         registerTable,
+        registerRemarkModal,
         handleReloadCurrent,
         handleLectureNoteDesc,
         handleLessonPlanDesc,
         handleTeachingStudyDesc,
+        handleEditRemark,
       };
     },
   });
-- 
Gitee


From 75f3782f8b1014b16c3f4f1c5fa837e463ad4947 Mon Sep 17 00:00:00 2001
From: In_Chh <2319397152@qq..com>
Date: Fri, 16 Sep 2022 10:46:38 +0800
Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=AE=9E?=
 =?UTF-8?q?=E4=B9=A0=E7=94=9F=E5=B0=8F=E7=BB=84=E7=9A=84=E5=A2=9E=E5=88=A0?=
 =?UTF-8?q?=E6=94=B9=E6=9F=A5=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/teacher/model/practiceModel.ts      |  11 ++
 src/api/teacher/practice.ts                 |  50 ++++++++-
 src/views/teacher/practical/group/Desc.vue  |  55 ++++++++++
 src/views/teacher/practical/group/Edit.vue  | 111 +++++++++++++++++++
 src/views/teacher/practical/group/index.vue | 114 ++++++++++++++++++++
 5 files changed, 340 insertions(+), 1 deletion(-)
 create mode 100644 src/views/teacher/practical/group/Desc.vue
 create mode 100644 src/views/teacher/practical/group/Edit.vue
 create mode 100644 src/views/teacher/practical/group/index.vue

diff --git a/src/api/teacher/model/practiceModel.ts b/src/api/teacher/model/practiceModel.ts
index d1a741a..f91dccc 100644
--- a/src/api/teacher/model/practiceModel.ts
+++ b/src/api/teacher/model/practiceModel.ts
@@ -1,4 +1,5 @@
 import { IntershipTypeEnum } from "/@/enums/intershipTypeEnum";
+import { BasicFetchResult } from "/@/api/model/baseModel";
 
 export interface IntershipInfoModel {
   type: IntershipTypeEnum;
@@ -35,3 +36,13 @@ export interface ReportModel {
   jxpfCollege: number;
   groupScore: number;
 }
+
+export interface GroupItemModel {
+  groupId: number;
+  groupName: string;
+  total: number;
+  stock: number;
+  introduce: string;
+}
+
+export type GroupListResultModel = BasicFetchResult<GroupItemModel>;
diff --git a/src/api/teacher/practice.ts b/src/api/teacher/practice.ts
index f213288..e8eec3d 100644
--- a/src/api/teacher/practice.ts
+++ b/src/api/teacher/practice.ts
@@ -1,7 +1,13 @@
 import { BasicPageParams } from "/@/api/model/baseModel";
 import { defHttp } from "/@/utils/http/axios";
 import { GroupMemberListResultModel, LeaderWorkModel } from "/@/api/student/model/practiceModel";
-import { IntershipInfoModel, RemarkModel, ReportModel } from "/@/api/teacher/model/practiceModel";
+import {
+  GroupItemModel,
+  GroupListResultModel,
+  IntershipInfoModel,
+  RemarkModel,
+  ReportModel,
+} from "/@/api/teacher/model/practiceModel";
 import { UserInfo } from "/#/store";
 
 enum Api {
@@ -18,6 +24,10 @@ enum Api {
   SetGxRemark = "/internInfo/remark/gx",
   GetReportByUserId = "/internInfo/getReport",
   GetLeaderWorkInfo = "/leaderWork/getInfo",
+  GetPracticalGroupPage = "/group/practicalPage",
+  SavePracticalGroup = "/group/savePractical",
+  UpdatePracticalGroup = "/group/update",
+  RemovePracticalGroup = "/group/remove",
 }
 
 /**
@@ -171,3 +181,41 @@ export const getReportByUserId = (userId: number) =>
   defHttp.get<ReportModel>({
     url: Api.GetReportByUserId + `/${userId}`,
   });
+
+/**
+ * 分页查询实习小组信息
+ * @param params 分页查询参数
+ */
+export const getPracticalGroupPage = (params: BasicPageParams) =>
+  defHttp.get<GroupListResultModel>({
+    url: Api.GetPracticalGroupPage,
+    params,
+  });
+/**
+ * 添加实习小组
+ * @param group 实习小组信息对象
+ */
+export const savePracticalGroup = (group: GroupItemModel) =>
+  defHttp.get<GroupListResultModel>({
+    url: Api.SavePracticalGroup,
+    params: group,
+  });
+
+/**
+ * 更新实习小组信息
+ * @param group 实习小组信息对象
+ */
+export const updatePracticalGroup = (group: GroupItemModel) =>
+  defHttp.put({
+    url: Api.UpdatePracticalGroup,
+    params: group,
+  });
+
+/**
+ * 删除实习小组
+ * @param groupId 实习小组id
+ */
+export const removePracticalGroupById = (groupId: number) =>
+  defHttp.delete({
+    url: Api.RemovePracticalGroup + `/${groupId}`,
+  });
diff --git a/src/views/teacher/practical/group/Desc.vue b/src/views/teacher/practical/group/Desc.vue
new file mode 100644
index 0000000..0821f25
--- /dev/null
+++ b/src/views/teacher/practical/group/Desc.vue
@@ -0,0 +1,55 @@
+<template>
+  <BasicModal v-bind="$attrs" title="详情" @register="registerModal" width="520px">
+    <Description @register="registerDesc" :column="1" size="middle" />
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref } from "vue";
+  import { DescItem, Description, useDescription } from "/@/components/Description";
+  import { BasicModal, useModalInner } from "/@/components/Modal";
+
+  export default defineComponent({
+    name: "GroupDesc",
+    components: {
+      Description,
+      BasicModal,
+    },
+    props: { userData: { type: Object } },
+    setup() {
+      const schema: DescItem[] = [
+        {
+          field: "groupName",
+          label: "小组名称",
+          contentMinWidth: 300,
+        },
+        {
+          field: "total",
+          label: "可选人数",
+          contentMinWidth: 300,
+        },
+        {
+          field: "stock",
+          label: "剩余可选人数",
+          contentMinWidth: 300,
+        },
+        {
+          field: "introduce",
+          label: "小组介绍",
+          contentMinWidth: 300,
+        },
+      ];
+      const userData = ref({});
+      const [registerModal] = useModalInner((data) => {
+        userData.value = data;
+      });
+      const [registerDesc] = useDescription({
+        schema,
+        data: userData,
+      });
+      return {
+        registerDesc,
+        registerModal,
+      };
+    },
+  });
+</script>
diff --git a/src/views/teacher/practical/group/Edit.vue b/src/views/teacher/practical/group/Edit.vue
new file mode 100644
index 0000000..b63a53c
--- /dev/null
+++ b/src/views/teacher/practical/group/Edit.vue
@@ -0,0 +1,111 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    :title="operType === 'update' ? '编辑' : '添加'"
+    @register="registerModal"
+    width="520px"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" :model="group" />
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref } from "vue";
+  import { BasicModal, useModalInner } from "/@/components/Modal";
+  import { BasicForm, useForm } from "/@/components/Form";
+  import { TableOperationTypeEnum } from "/@/enums/tableOperationTypeEnum";
+  import { savePracticalGroup, updatePracticalGroup } from "/@/api/teacher/practice";
+  import { useMessage } from "/@/hooks/web/useMessage";
+
+  export default defineComponent({
+    name: "GroupEdit",
+    components: {
+      BasicForm,
+      BasicModal,
+    },
+    setup() {
+      const defaultFormData = {
+        groupId: undefined,
+        groupName: "",
+        total: 0,
+        introduce: "",
+      };
+
+      const group = ref(defaultFormData);
+      const operType = ref("");
+
+      const [registerForm, { validate, setFieldsValue }] = useForm({
+        labelWidth: 100,
+        schemas: [
+          {
+            field: "groupId",
+            label: "id",
+            component: "Input",
+            show: false,
+          },
+          {
+            field: "groupName",
+            label: "小组名称",
+            component: "Input",
+            required: true,
+          },
+          {
+            field: "total",
+            label: "小组可选人数",
+            component: "InputNumber",
+            required: true,
+          },
+          {
+            field: "introduce",
+            label: "小组介绍",
+            component: "InputTextArea",
+            colProps: {
+              span: 24,
+            },
+            componentProps: {
+              rows: 4,
+            },
+          },
+        ],
+        showActionButtonGroup: false,
+      });
+
+      const [registerModal, { closeModal }] = useModalInner(({ group, operType: type }) => {
+        operType.value = type;
+        if (type === TableOperationTypeEnum.UPDATE) {
+          setFieldsValue({
+            ...group,
+          });
+        } else if (type === TableOperationTypeEnum.SAVE) {
+          setFieldsValue(defaultFormData);
+        }
+      });
+
+      const { createMessage } = useMessage();
+
+      async function handleSubmit() {
+        const value = await validate();
+        if (operType.value === TableOperationTypeEnum.SAVE) {
+          await savePracticalGroup(value);
+          createMessage.info("添加成功");
+          closeModal();
+          return;
+        } else if (operType.value === TableOperationTypeEnum.UPDATE) {
+          await updatePracticalGroup(value);
+          createMessage.info("更新成功");
+          closeModal();
+          return;
+        }
+        return Promise.reject("未知操作");
+      }
+
+      return {
+        registerForm,
+        registerModal,
+        handleSubmit,
+        group,
+        operType,
+      };
+    },
+  });
+</script>
diff --git a/src/views/teacher/practical/group/index.vue b/src/views/teacher/practical/group/index.vue
new file mode 100644
index 0000000..a01dad7
--- /dev/null
+++ b/src/views/teacher/practical/group/index.vue
@@ -0,0 +1,114 @@
+<template>
+  <div class="p-4">
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleSave"> 新增</a-button>
+        <a-button type="primary" @click="handleReload"> 刷新</a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            stopButtonPropagation
+            :actions="[
+              {
+                label: '详情',
+                icon: 'ant-design:info-circle-outlined',
+                onClick: handleDesc.bind(null, record),
+              },
+              {
+                label: '编辑',
+                icon: 'akar-icons:edit',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                label: '删除',
+                icon: 'ic:outline-delete-outline',
+                popConfirm: {
+                  title: '确认删除?',
+                  okText: '确认',
+                  cancelText: '取消',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <GroupDesc @register="registerDescModal" />
+    <GroupEdit @register="registerEditModal" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { TableAction, useTable } from "/@/components/Table";
+  import { BasicTable } from "/@/components/Table";
+  import { TableOperationTypeEnum } from "/@/enums/tableOperationTypeEnum";
+  import { useModal } from "/@/components/Modal";
+  import GroupDesc from "./Desc.vue";
+  import GroupEdit from "./Edit.vue";
+  import { getPracticalGroupPage, removePracticalGroupById } from "/@/api/teacher/practice";
+  import { GroupItemModel } from "/@/api/teacher/model/practiceModel";
+  import { useMessage } from "/@/hooks/web/useMessage";
+
+  const [registerTable, { reload }] = useTable({
+    title: "实习小组",
+    api: getPracticalGroupPage,
+    fetchSetting: {
+      pageField: "pageNum",
+      listField: "content",
+    },
+    columns: [
+      {
+        title: "Id",
+        dataIndex: "groupId",
+        defaultHidden: true,
+      },
+      {
+        title: "小组名称",
+        dataIndex: "groupName",
+      },
+      {
+        title: "可选人数",
+        dataIndex: "total",
+        sorter: true,
+      },
+      {
+        title: "剩余可选人数",
+        dataIndex: "stock",
+        sorter: true,
+      },
+    ],
+    rowKey: "groupId",
+    pagination: { pageSize: 10 },
+    actionColumn: {
+      title: "操作",
+      dataIndex: "action",
+      fixed: "right",
+    },
+  });
+
+  function handleReload() {
+    reload();
+  }
+
+  const [registerDescModal, { openModal: openDescModal }] = useModal();
+  const [registerEditModal, { openModal: openEditModal }] = useModal();
+
+  function handleDesc(group: GroupItemModel) {
+    openDescModal(true, group);
+  }
+
+  function handleEdit(group: GroupItemModel) {
+    openEditModal(true, { group, operType: TableOperationTypeEnum.UPDATE });
+  }
+
+  function handleSave() {
+    openEditModal(true, { operType: TableOperationTypeEnum.SAVE });
+  }
+
+  const { createMessage } = useMessage();
+  async function handleDelete(record) {
+    await removePracticalGroupById(record.groupId);
+    createMessage.info("删除成功");
+  }
+</script>
-- 
Gitee