Kaynağa Gözat

实习报告

Xiao_123 2 ay önce
ebeveyn
işleme
403feee469

+ 1 - 5
components.d.ts

@@ -31,7 +31,6 @@ declare module 'vue' {
     CtTextField: typeof import('./src/components/CtVuetify/CtTextField/index.vue')['default']
     DatePicker: typeof import('./src/components/DatePicker/index.vue')['default']
     Echarts: typeof import('./src/components/Echarts/index.vue')['default']
-    ElCascader: typeof import('element-plus/es')['ElCascader']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     Empty: typeof import('./src/components/Empty/index.vue')['default']
     File: typeof import('./src/components/Upload/file.vue')['default']
@@ -46,7 +45,7 @@ declare module 'vue' {
     IndustryTypeCard: typeof import('./src/components/industryTypeCard/index.vue')['default']
     Info: typeof import('./src/components/Enterprise/info.vue')['default']
     InitPay: typeof import('./src/components/personalRecharge/initPay.vue')['default']
-    Item: typeof import('./src/components/PositionLongStrip/item.vue')['default']
+    Item: typeof import('./src/components/Position/item.vue')['default']
     JobTypeCard: typeof import('./src/components/jobTypeCard/index.vue')['default']
     ListGroup: typeof import('./src/components/FormUI/nestedListGroup/components/listGroup.vue')['default']
     Loading: typeof import('./src/components/Loading/index.vue')['default']
@@ -76,7 +75,4 @@ declare module 'vue' {
     VerifySlide: typeof import('./src/components/Verifition/Verify/VerifySlide.vue')['default']
     WangEditor: typeof import('./src/components/FormUI/wangEditor/index.vue')['default']
   }
-  export interface ComponentCustomProperties {
-    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
-  }
 }

+ 115 - 0
src/views/recruit/teacher/internshipReport/index copy.vue

@@ -0,0 +1,115 @@
+<!-- 实习报告 -->
+<template>
+  <v-card class="px-3">
+    <!-- 筛选条件 -->
+    <div class="d-flex justify-space-between mt-8 mb-10">
+      <div class="d-flex align-center">
+        <!-- <span class="mx-3 color-666 font-size-14">院系</span> -->
+        <Autocomplete class="mr-3" v-model="query.collegeId" :item="yuanXi"></Autocomplete>
+        <v-btn color="primary" class="half-button ml-3" @click="handleSearch()">查 询</v-btn>
+        <v-btn class="half-button ml-3" prepend-icon="mdi-refresh" variant="outlined" color="primary" @click="handleSearch(true)">刷 新</v-btn>
+      </div>
+      <v-btn :loading="exportLoading" prepend-icon="mdi-export-variant" color="primary" variant="tonal" class="ml-3" @click="null">导出</v-btn>
+    </div>
+    
+    <!-- 列表 -->
+    <div class="mt-5" style="min-height: 500px;">
+      <CtTable
+        :items="tableData"
+        :headers="headers"
+        :loading="loading"
+        :elevation="0"
+        :is-tools="false"
+        :showPage="true"
+        :total="total"
+        :page-info="query"
+        itemKey="id"
+        @pageHandleChange="handleChangePage"
+      >
+        <template #studentName="{ item }">
+          <div class="d-flex align-center">
+            <v-avatar size="40" :image="getUserAvatar(item?.person?.avatar, item?.person?.sex)"></v-avatar>
+            <span class="ml-3">{{ item?.person?.name }}</span>
+          </div>
+        </template>
+        <template #actions="{ item }">
+          <v-btn v-if="!item?.recommendationLetter" color="primary" variant="text" @click="handleUploadLetter(item.id)">上传推荐信</v-btn>
+          <v-btn v-if="!item?.evaluate" color="#00897B" variant="text" @click="handleIssueCertificate(item.id)">颁发实习证书</v-btn>
+        </template>
+      </CtTable>
+      <!-- <Loading :visible="loading"></Loading> -->
+    </div>
+  </v-card >
+</template>
+
+<script setup>
+defineOptions({name: 'internship-report'})
+import { ref } from 'vue'
+import Snackbar from '@/plugins/snackbar'
+import { formatName } from '@/utils/getText'
+import { getUserAvatar } from '@/utils/avatar'
+
+const loading = ref(false)
+const query = ref({
+  pageSize: 20,
+  pageNo: 1,
+  collegeId: null,
+})
+
+const headers = [
+  { title: '学生姓名', key: 'studentName', sortable: false },
+  { title: '学生学号', key: 'studentName', sortable: false },
+  { title: '所属专业', key: 'studentName', sortable: false },
+  { title: '录用企业', key: 'studentName', sortable: false, value: item => formatName(item.studentName) },
+  { title: '录用部门', key: 'studentName', sortable: false, value: item => formatName(item.studentName) },
+  { title: '录用岗位', key: 'studentName', sortable: false, value: item => formatName(item.studentName) },
+  { title: '操作', key: 'actions', sortable: false }
+]
+
+const tableData = ref([{ studentName: '123'}])
+const total = ref(0)
+// 列表
+const getData = async (isRefresh = false) => {
+  // const { list, total: number } = await getInterviewInvitePage(query.value)
+  // tableData.value = list
+  // total.value = number
+  if (isRefresh) Snackbar.success('刷新成功')
+}
+
+const handleChangePage = (val) => {
+	query.value.pageNo = val
+	getData()
+}
+
+const handleSearch = (refresh = false) => {
+  query.value.pageNo = 1
+  getData(refresh)
+}
+
+const yuanXi = ref({ width: 300, items: [], clearable: false, hideDetails: true, label: '请选择院系' })
+// 列表
+const getYuanXiItem = async () => {
+  // const { list } = await getInterviewInvitePage(query.value)
+  yuanXi.value.items = [
+    { label: '中文系', value: '中文系' },
+    { label: '人文学院', value: '人文学院' },
+  ]
+  if (yuanXi.value.items?.length) {
+    query.value.collegeId = yuanXi.value.items[0].value
+    getData()
+  }
+}
+getYuanXiItem()
+
+const exportLoading = ref(false)
+</script>
+<style lang="scss" scoped>
+.title {
+  color: var(--color-333);
+  font-weight: 600;
+  font-size: 16px;
+}
+.left {
+  min-width: 200px;
+}
+</style>

+ 186 - 65
src/views/recruit/teacher/internshipReport/index.vue

@@ -1,19 +1,27 @@
-<!-- 实习报告 -->
 <template>
-  <v-card class="px-3">
-    <!-- 筛选条件 -->
-    <div class="d-flex justify-space-between mt-8 mb-10">
-      <div class="d-flex align-center">
-        <!-- <span class="mx-3 color-666 font-size-14">院系</span> -->
-        <Autocomplete class="mr-3" v-model="query.collegeId" :item="yuanXi"></Autocomplete>
-        <v-btn color="primary" class="half-button ml-3" @click="handleSearch()">查 询</v-btn>
-        <v-btn class="half-button ml-3" prepend-icon="mdi-refresh" variant="outlined" color="primary" @click="handleSearch(true)">刷 新</v-btn>
-      </div>
-      <v-btn :loading="exportLoading" prepend-icon="mdi-export-variant" color="primary" variant="tonal" class="ml-3" @click="null">导出</v-btn>
+  <v-card class="card-box d-flex pa-3">
+    <div style="width: 20%; border-right: 1px solid #ccc;">
+      <v-treeview
+        :items="treeData"
+        activatable
+        color="primary"
+        item-value="id"
+        open-all
+        open-strategy="single"
+        density="compact"
+        @update:activated="handleClick"
+        @update:opened="handleClick"
+      >
+        <template v-slot:title="{ item }">
+          <div class="treeTitle font-size-15" v-ellipse-tooltip style="max-width: 100%;">{{ formatName(item.title) }}</div>
+        </template>
+      </v-treeview>
     </div>
-    
-    <!-- 列表 -->
-    <div class="mt-5" style="min-height: 500px;">
+    <div style="width: 80%" class="ml-3">
+      <div class="d-flex justify-space-between px-3">
+        <TextInput v-model="query.name" :item="textItem" @change="getUserList"></TextInput>
+        <v-btn class="mr-3" width="100" color="primary" prepend-icon="mdi-refresh" variant="outlined" @click="getTreeData">刷 新</v-btn>
+      </div>
       <CtTable
         :items="tableData"
         :headers="headers"
@@ -28,88 +36,201 @@
       >
         <template #studentName="{ item }">
           <div class="d-flex align-center">
-            <v-avatar size="40" :image="getUserAvatar(item?.person?.avatar, item?.person?.sex)"></v-avatar>
-            <span class="ml-3">{{ item?.person?.name }}</span>
+            <v-avatar size="40" :image="getUserAvatar(item.headImg, item.teacherSex)"></v-avatar>
+            <span class="ml-3">{{ item?.studentName }}</span>
           </div>
         </template>
         <template #actions="{ item }">
-          <v-btn v-if="!item?.recommendationLetter" color="primary" variant="text" @click="handleUploadLetter(item.id)">上传推荐信</v-btn>
-          <v-btn v-if="!item?.evaluate" color="#00897B" variant="text" @click="handleIssueCertificate(item.id)">颁发实习证书</v-btn>
+          <v-btn color="primary" variant="text" @click="handleReport(item)">实习报告</v-btn>
         </template>
       </CtTable>
-      <!-- <Loading :visible="loading"></Loading> -->
     </div>
-  </v-card >
+
+    <v-navigation-drawer v-model="showDetail" absolute location="right" rounded temporary width="700" class="pa-5">
+      <p class="text-center color-primary font-weight-bold mb-5 font-size-20">{{ detailTitle }}</p>
+      <div v-if="reportList && reportList.length > 0">
+        <div v-for="item in reportList" :key="item.date" class="mb-3">
+          <div class="title-date">{{ item.date }}</div>
+          <div class="d-flex flex-wrap">
+            <img 
+              v-for="(src, index) in item.arr" 
+              :key="index" 
+              :src="src" 
+              @click="handlePreview(item.arr, index)" 
+              class="cursor-pointer" 
+              style="width: 200px; height: 250px;"
+            />
+          </div>
+        </div>
+      </div>
+      <Empty v-else :elevation="false" />
+	  </v-navigation-drawer>
+  </v-card>
+
+  <PreviewImage v-if="showPreview" :initialIndex="initialIndex" :urlList="urlsList" @close="handleClosePreview" />
 </template>
 
 <script setup>
-defineOptions({name: 'internship-report'})
+defineOptions({ name: 'group-account'})
 import { ref } from 'vue'
-import Snackbar from '@/plugins/snackbar'
-import { formatName } from '@/utils/getText'
+import { useI18n } from '@/hooks/web/useI18n'
+import { getEnterpriseTree } from '@/api/recruit/enterprise/system/group'
 import { getUserAvatar } from '@/utils/avatar'
+import { formatName } from '@/utils/getText';
 
+const { t } = useI18n()
+const total = ref(0)
 const loading = ref(false)
 const query = ref({
-  pageSize: 20,
+  pageSize: 10,
   pageNo: 1,
-  collegeId: null,
+  enterpriseId: '',
+  name: null
 })
 
+// 企业基本信息
+const schoolInfo = ref(localStorage.getItem('schoolInfo') ? JSON.parse(localStorage.getItem('schoolInfo')) : {})
+
+const tableData = ref([
+  {
+  "id": "1899374563922436098",
+  "userId": "1899373349776244738",
+  "personId": "1899374563842744322",
+  "graduationStatus": null,
+  "status": null,
+  "enterpriseId": null,
+  "studentNo": "200004512",
+  "idCardName": null,
+  studentName: '张三',
+  "idCardNo": "440104199908129861",
+  "idCardImg1": null,
+  "idCardImg2": null,
+  "authStatus": "0",
+  "schoolId": "1899055558628085760",
+  "schoolName": "辞图科技",
+  "schoolClassId": null,
+  "schoolDepartmentName": "外语系",
+  "schoolClassName": "德语一班",
+  "majorId": null,
+  "majorName": "德语",
+  "majorCode": null,
+  teacherSex: '1',
+  headImg: '',
+  enterpriseName: '企业1',
+  "emergencyContactName": "吴轩",
+  "emergencyContactPhone": "13229740017",
+  "createTime": 1741681159370
+}
+])
+const treeData = ref([
+  {
+    title: '农学',
+    children: [{ title: '农学1' }, { title: '农学2' }]
+  },
+  {
+    title: '文学',
+    children: [{ title: '文学1' }, { title: '文学2' }]
+  }
+])
 const headers = [
   { title: '学生姓名', key: 'studentName', sortable: false },
-  { title: '学生学号', key: 'studentName', sortable: false },
-  { title: '所属专业', key: 'studentName', sortable: false },
-  { title: '录用企业', key: 'studentName', sortable: false, value: item => formatName(item.studentName) },
-  { title: '录用部门', key: 'studentName', sortable: false, value: item => formatName(item.studentName) },
-  { title: '录用岗位', key: 'studentName', sortable: false, value: item => formatName(item.studentName) },
-  { title: '操作', key: 'actions', sortable: false }
+  { title: '实习企业', key: 'enterpriseName', sortable: false },
+  { title: '所属院系', key: 'schoolDepartmentName', sortable: false },
+  { title: '所属专业', key: 'majorName', sortable: false },
+  { title: '所在班级', key: 'schoolClassName', sortable: false },
+  { title: '学号', key: 'studentNo', sortable: false },
+  { title: t('common.actions'), key: 'actions', sortable: false }
 ]
+const textItem = ref({
+  type: 'text',
+  value: null,
+  width: 250,
+  clearable: true,
+  label: '请输入学生名称搜索'
+})
 
-const tableData = ref([{ studentName: '123'}])
-const total = ref(0)
-// 列表
-const getData = async (isRefresh = false) => {
-  // const { list, total: number } = await getInterviewInvitePage(query.value)
-  // tableData.value = list
-  // total.value = number
-  if (isRefresh) Snackbar.success('刷新成功')
+
+// 获取用户列表
+const getUserList = async () => {
+  // loading.value = true
+  // try {
+  //   const { list, total: number } = await getEnterpriseUserList(query.value)
+  //   tableData.value = list
+  //   total.value = number
+  // } finally {
+  //   loading.value = false
+  // }
+}
+
+// 获取树形列表
+const getTreeData = async () => {
+  treeData.value = []
+  try {
+    const data = await getEnterpriseTree()
+    if (!data) return
+    treeData.value[0] = data
+    query.value.enterpriseId = data.id
+    // 获取用户列表
+    getUserList()
+  } catch {}
 }
+// getTreeData()
 
-const handleChangePage = (val) => {
-	query.value.pageNo = val
-	getData()
+// 分页
+const handleChangePage = (e) => {
+  query.value.pageNo = e
+  getUserList()
 }
 
-const handleSearch = (refresh = false) => {
-  query.value.pageNo = 1
-  getData(refresh)
+// 树形click
+const handleClick = (e) => {
+  if (!e.length) return
+  query.value.enterpriseId = e[0]
+  getUserList()
 }
 
-const yuanXi = ref({ width: 300, items: [], clearable: false, hideDetails: true, label: '请选择院系' })
-// 列表
-const getYuanXiItem = async () => {
-  // const { list } = await getInterviewInvitePage(query.value)
-  yuanXi.value.items = [
-    { label: '中文系', value: '中文系' },
-    { label: '人文学院', value: '人文学院' },
-  ]
-  if (yuanXi.value.items?.length) {
-    query.value.collegeId = yuanXi.value.items[0].value
-    getData()
+// 查看实习报告
+const reportList = ref([
+  {
+    date: '2023-01-01',
+    arr: ['https://menduner.citupro.com:3443/dev/person/1899373349776244738/img/c1e6d4d93ef29bf62e07eec698b8a44a1cf690aa1f5c0d36065f0f2fb1144956.png']
   }
+])
+const detailTitle = ref('实习报告')
+const showDetail = ref(false)
+const handleReport = (item) => {
+  detailTitle.value = item.studentName + ' - 实习报告'
+  showDetail.value = true
+}
+
+// 图片预览
+const showPreview = ref(false)
+const initialIndex = ref(0)
+const urlsList = ref([])
+const handlePreview = (arr, index) => {
+  urlsList.value = arr
+  initialIndex.value = index
+  showPreview.value = true
 }
-getYuanXiItem()
 
-const exportLoading = ref(false)
+const handleClosePreview = () => {
+  showPreview.value = false
+  initialIndex.value = 0
+  urlsList.value = []
+}
 </script>
-<style lang="scss" scoped>
-.title {
-  color: var(--color-333);
-  font-weight: 600;
-  font-size: 16px;
+
+<style scoped lang="scss">
+.title-date {
+	border-left: 5px solid var(--v-primary-base);
+	padding-left: 12px;
+	line-height: 17px;
 }
-.left {
-  min-width: 200px;
+.treeTitle {
+  width: 100%;
+  max-width: 100%;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
 }
 </style>

+ 0 - 73
src/views/recruit/teacher/internshipSituation/CertificateForm.vue

@@ -1,73 +0,0 @@
-<template>
-	<div>
-		<CtForm ref="CtFormRef" class="mt-3" :items="formItems">
-			<template #uploadFile="{ item }">
-				<TextInput v-model="item.value" :item="item" @click="openFileInput"></TextInput>
-				<File ref="uploadFile" @success="handleUploadResume"></File>
-			</template>
-		</CtForm>
-		<div class="color-666" style="font-size: 13px;">* 仅支持DOC、DOCX、PDF文件且大小不能超过20MB</div>
-	</div>
-</template>
-
-<script setup>
-defineOptions({ name: 'CertificateForm'})
-import { ref } from 'vue'
-
-const CtFormRef = ref()
-const formItems = ref({
-  options: [
-    {
-      type: 'textarea',
-      key: 'evaluate',
-      value: null,
-      rows: 5,
-      counter: 60,
-      label: '点评内容 *',
-      outlined: true,
-      rules: [v => !!v || '点评不能为空']
-    },
-    {
-      slotName: 'uploadFile',
-      key: 'certificate',
-      value: '',
-      truthValue: '',
-      label: '点击上传附件 *',
-      outline: true,
-      accept: '.doc, .docx, .pdf',
-      prependInnerIcon: 'mdi-file-document-outline',
-      rules: [v => !!v || '附件不能为空']
-    }
-  ]
-})
-
-// 选择文件
-const uploadFile = ref()
-const openFileInput = () => {
-  uploadFile.value.trigger()
-}
-
-// 上传附件
-const handleUploadResume = async (url, title, filename) => {
-  const obj = formItems.value.options.find(e => e.key === 'certificate')
-  obj.value = filename
-  obj.truthValue = url
-}
-
-const getQuery = () => {
-	let obj = {}
-	formItems.value.options.forEach(e => {
-		obj[e.key] = e.truthValue || e.value
-	})
-	return obj
-}
-
-defineExpose({
-	getQuery,
-	CtFormRef
-})
-</script>
-
-<style scoped lang="scss">
-
-</style>

+ 0 - 61
src/views/recruit/teacher/internshipSituation/RecommendationLetterForm.vue

@@ -1,61 +0,0 @@
-<template>
-	<CtForm ref="CtFormRef" class="mt-3" :items="formItems">
-    <template #uploadFile="{ item }">
-      <TextInput v-model="item.value" :item="item" @click="openFileInput"></TextInput>
-      <File ref="uploadFile" @success="handleUploadResume"></File>
-    </template>
-  </CtForm>
-  <div class="color-666" style="font-size: 13px;">* 仅支持DOC、DOCX、PDF文件且大小不能超过20MB</div>
-</template>
-
-<script setup>
-defineOptions({ name: 'RecommendationLetterForm'})
-import { ref } from 'vue'
-
-const CtFormRef = ref()
-const formItems = ref({
-  options: [
-    {
-      slotName: 'uploadFile',
-      key: 'url',
-      value: '',
-      truthValue: '',
-      label: '点击上传推荐信 *',
-      outline: true,
-      accept: '.doc, .docx, .pdf',
-      prependInnerIcon: 'mdi-file-document-outline',
-      rules: [v => !!v || '推荐信不能为空']
-    }
-  ]
-})
-
-// 选择文件
-const uploadFile = ref()
-const openFileInput = () => {
-  uploadFile.value.trigger()
-}
-
-// 上传附件
-const handleUploadResume = async (url, title, filename) => {
-  const obj = formItems.value.options.find(e => e.key === 'url')
-  obj.value = filename
-  obj.truthValue = url
-}
-
-const getQuery = () => {
-	let obj = {}
-	formItems.value.options.forEach(e => {
-		obj[e.key] = e.truthValue
-	})
-	return obj
-}
-
-defineExpose({
-	getQuery,
-	CtFormRef
-})
-</script>
-
-<style scoped lang="scss">
-
-</style>

+ 11 - 4
src/views/recruit/teacher/internshipSituation/index.vue

@@ -69,6 +69,10 @@
 			</template>
     </CtTable>
   </CtDialog>
+
+	<v-navigation-drawer v-model="showDetail" absolute location="right" rounded temporary width="700" class="pa-5">
+		111
+	</v-navigation-drawer>
 </template>
 
 <script setup>
@@ -190,6 +194,7 @@ const drill = ref({
 		studentPracticeStatus: '实习中'
 	}],
   headers: [
+    { title: '状态', key: 'studentPracticeStatus', sortable: false },
     { title: '学生姓名', key: 'studentName', sortable: false },
 		{ title: '实习企业', key: 'enterpriseName', sortable: false },
     { title: '联系电话', key: 'phone', sortable: false },
@@ -197,7 +202,6 @@ const drill = ref({
     { title: '所属专业', key: 'majorName', sortable: false },
     { title: '所在班级', key: 'schoolClassName', sortable: false },
     { title: '学号', key: 'studentNo', sortable: false },
-    { title: '状态', key: 'studentPracticeStatus', sortable: false },
   ]
 })
 // 学生列表
@@ -206,13 +210,16 @@ const handleDetail = (item, label) => {
 	drill.value.query.current = 1
   drill.value.show = true
 }
-
+const handleChangeDrillPage = (page) => {}
 const handleClose = () => {
   drill.value.show = false
-  drill.value.list = []
+  // drill.value.list = []
 }
 
-const handleToStudentDetail = (id) => {}
+const showDetail = ref(false)
+const handleToStudentDetail = (id) => {
+	showDetail.value = true
+}
 </script>
 
 <style scoped lang="scss">