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