Browse Source

学生-实习证书

Xiao_123 2 tháng trước cách đây
mục cha
commit
48d521b661

+ 3 - 0
components.d.ts

@@ -32,6 +32,9 @@ declare module 'vue' {
     Echarts: typeof import('./src/components/Echarts/index.vue')['default']
     ElCascader: typeof import('element-plus/es')['ElCascader']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
+    ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElTree: typeof import('element-plus/es')['ElTree']
+    ElUpload: typeof import('element-plus/es')['ElUpload']
     Empty: typeof import('./src/components/Empty/index.vue')['default']
     File: typeof import('./src/components/Upload/file.vue')['default']
     HeadSearch: typeof import('./src/components/headSearch/index.vue')['default']

+ 17 - 0
src/api/recruit/personal/student.js

@@ -0,0 +1,17 @@
+import request from '@/config/axios'
+
+// 获取企业推荐信分页
+export const getRecommendationPage = async (data) => {
+	return await request.post({
+		url: '/app-api/flames/student/recommendation/list',
+		data
+	})
+}
+
+// 获取实习证书分页
+export const getCertificatePage = async (data) => {
+	return await request.post({
+		url: '/app-api/flames/student/internship/certificate/list',
+		data
+	})
+}

+ 4 - 1
src/store/personCenter.js

@@ -4,16 +4,19 @@ export const usePersonCenterStore = defineStore('personCenter',
 	{
 		state: () => ({
 			initialIndex: 0,
+			fileName: '',
 			urlsList: []
 		}),
 		actions: {
-			setPreviewData (arr, index) {
+			setPreviewData (arr, index, fileName) {
 				this.urlsList = arr
 				this.initialIndex = index
+				this.fileName = fileName
 			},
 			clearPreviewData () {
 				this.urlsList = []
 				this.initialIndex = 0
+				this.fileName = ''
 			}
 		}
 	},

+ 3 - 1
src/views/recruit/personal/PersonalCenter/index.vue

@@ -45,7 +45,7 @@
     </v-card>
   </div>
 
-  <PreviewImage v-if="showPreview" :initialIndex="initialIndex" :urlList="urlsList" @close="handleClosePreview" />
+  <PreviewImage v-if="showPreview" :initialIndex="initialIndex" :fileName="fileName" :urlList="urlsList" @close="handleClosePreview" />
 </template>
 
 <script setup>
@@ -96,10 +96,12 @@ const personCenterStore = usePersonCenterStore()
 const showPreview = ref(false)
 const initialIndex = ref(0)
 const urlsList = ref([])
+const fileName = ref('')
 personCenterStore.$subscribe((mutation, state) => {
   if (state.urlsList.length > 0) {
     urlsList.value = state.urlsList
     initialIndex.value = state.initialIndex
+    fileName.value = state.fileName
     showPreview.value = true
   }
 })

+ 51 - 0
src/views/recruit/personal/PersonalCenter/student/EnterpriseRecommendationLetter/index.vue

@@ -4,6 +4,57 @@
 
 <script setup>
 defineOptions({ name: 'EnterpriseRecommendationLetter' })
+import { ref } from 'vue'
+import { getBlob, saveAs, previewFile } from '@/utils'
+import { timesTampChange } from '@/utils/date'
+import { getRecommendationPage } from '@/api/recruit/personal/student'
+
+const loading = ref(false)
+const list = ref([
+	{
+		enterpriseName: '企业1',
+		createTime: 1668476800000,
+		url: 'https://menduner.citupro.com:3443/dev/person/1893630489546350594/attachment/7cde29dc69c1403649be55d4c2bfd3d8304c088dc79ab25afe9c4bf55d3b382f.docx'
+	},
+	{
+		enterpriseName: '企业2',
+		createTime: 1668476800000,
+		url: 'https://menduner.citupro.com:3443/dev/person/1893630489546350594/attachment/7cde29dc69c1403649be55d4c2bfd3d8304c088dc79ab25afe9c4bf55d3b382f.docx'
+	}
+])
+const total = ref(2)
+const query = ref({
+	pageNo: 1,
+	pageSize: 10
+})
+
+const headers = [
+  { title: '推荐方企业', key: 'enterpriseName', sortable: false },
+  { title: '创建时间', key: 'createTime', sortable: false, value: item => timesTampChange(item.createTime, 'Y-M-D h:m') },
+  { title: '操作', key: 'actions', sortable: false }
+]
+
+const getList = async () => {
+	loading.value = true
+	try {
+		const result = await getRecommendationPage(query.value)
+		console.log(result, '企业推荐信')
+	} finally {
+		loading.value = false
+	}
+}
+
+const handleChangePage = (val) => {
+	query.value.pageNo = val
+	getList()
+}
+
+// 下载附件
+const handleDownload = (k) => {
+  getBlob(k.url).then(blob => {
+    saveAs(blob, k.title)
+  })
+}
 </script>
 
 <style scoped lang="scss">

+ 189 - 3
src/views/recruit/personal/PersonalCenter/student/InternshipCertificate/index.vue

@@ -1,11 +1,197 @@
 <template>
-	<div>xxx</div>
+	<div class="resume-box">
+		<div class="resume-header">
+      <div class="resume-title">实习证书</div>
+    </div>
+		<CtTable
+      class="mt-3"
+      :items="list"
+      :headers="headers"
+      :loading="loading"
+      :elevation="0"
+      :isTools="false"
+      :showPage="true"
+      :showSelect="false"
+      itemKey="id"
+			:total="total"
+			:page-info="query"
+			@pageHandleChange="handleChangePage"
+    >
+			<template #comment="{ item }">
+				<p v-ellipse-tooltip style="max-width: 300px;">{{ item.comment }}</p>
+			</template>
+      <template #actions="{ item }">
+        <v-btn color="primary" @click.stop="handlePreview(item)" variant="text">预览</v-btn>
+				<!-- 有附件的则需要提供下载按钮 -->
+        <v-btn color="primary" @click.stop="handleDownload(item)" variant="text">下载</v-btn>
+      </template>
+    </CtTable>
+
+		<!-- 生成实习证书 -->
+		<div class="position-absolute position-relative" style="left: -9999px; bottom: 0;" ref="share">
+			<img src="https://minio.citupro.com/dev/static/bgc.jpg" width="500" height="700" cover />
+			<div class="cer-introduce">
+				兹有
+				<span class="cer-text">{{ itemData?.schoolName }}</span>
+        <span class="cer-text">{{ itemData?.majorName }}</span>
+        专业<span class="cer-text">{{ itemData?.studentName }}</span>
+        同学于<span class="cer-text">{{ itemData?.startTime ? timesTampChange(itemData?.startTime, 'Y-M-D') : '' }}</span>
+        至<span class="cer-text">{{ itemData?.endTime ? timesTampChange(itemData?.endTime, 'Y-M-D') : '' }}</span>
+        在<span class="cer-text">{{ itemData?.enterpriseName ? formatName(itemData?.enterpriseName) : '' }}</span>
+        <span class="cer-text">{{ itemData?.deptName }}</span>岗位实习。
+			</div>
+			<div class="cer-comment">{{ itemData?.comment }}</div>
+			<div class="cer-prove">特此证明。</div>
+			<div class="cer-end">
+        <div>{{ itemData?.createTime ? timesTampChange(itemData?.createTime, 'Y-M-D') : '' }}</div>
+      </div>
+		</div>
+	</div>
+
+	<Loading :visible="showLoading"></Loading>
 </template>
 
 <script setup>
-defineOptions({ name: 'InternshipCertificate'})
+defineOptions({ name: 'PersonalCenterStudentInternshipCertificate' })
+import { ref } from 'vue'
+import { getBlob, saveAs } from '@/utils'
+import { timesTampChange } from '@/utils/date'
+import { getCertificatePage } from '@/api/recruit/personal/student'
+import Snackbar from '@/plugins/snackbar'
+import html2canvas from 'html2canvas'
+import { DPR } from '@/utils'
+import { usePersonCenterStore } from '@/store/personCenter'
+import { formatName } from '@/utils/getText'
+
+const share = ref(null)
+const loading = ref(false)
+const showLoading = ref(false)
+const list = ref([
+	{
+		enterpriseName: '门墩儿科技有限公司',
+		createTime: 1668476800000,
+		schoolName: '学校1',
+		majorName: '专业1',
+		startTime: 1668476800000,
+		endTime: 1668476800000,
+		deptName: '部门1',
+		studentName: '张三',
+		comment: '备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1备注1',
+		url: 'https://menduner.citupro.com:3443/dev/person/1893630489546350594/attachment/7cde29dc69c1403649be55d4c2bfd3d8304c088dc79ab25afe9c4bf55d3b382f.docx'
+	},
+	{
+		enterpriseName: '北京金融街资本运营集团有限公司西单美爵酒店分公司',
+		createTime: 1668476800000,
+		schoolName: '学校1',
+		majorName: '专业1',
+		startTime: 1668476800000,
+		endTime: 1668476800000,
+		deptName: '部门1',
+		studentName: '张三',
+		comment: '备注1',
+		url: 'https://menduner.citupro.com:3443/dev/person/1893630489546350594/attachment/7cde29dc69c1403649be55d4c2bfd3d8304c088dc79ab25afe9c4bf55d3b382f.docx'
+	}
+])
+const total = ref(2)
+const query = ref({
+	pageNo: 1,
+	pageSize: 10
+})
+const itemData = ref()
+const headers = [
+  { title: '发放企业', key: 'enterpriseName', sortable: false },
+  { title: '实习点评', key: 'comment', sortable: false },
+  { title: '创建时间', key: 'createTime', sortable: false, value: item => timesTampChange(item.createTime, 'Y-M-D h:m') },
+  { title: '操作', key: 'actions', sortable: false }
+]
+
+const getList = async () => {
+	loading.value = true
+	try {
+		const result = await getCertificatePage(query.value)
+		console.log(result, '实习证书')
+	} finally {
+		loading.value = false
+	}
+}
+
+const handleChangePage = (val) => {
+	query.value.pageNo = val
+	getList()
+}
+
+// 生成实习证书图片
+const personCenterStore = usePersonCenterStore()
+const generateAndDownloadImage = async () => {
+  try {  
+    const canvas = await html2canvas(share.value, { scale: DPR(), useCORS: true })
+    const image = canvas.toDataURL().replace(/^data:image\/(png|jpg);base64,/, '')
+
+		const fileName = `实习证书 - ${formatName(itemData.value?.enterpriseName)}`
+		personCenterStore.setPreviewData([`data:image/png;base64,${image}`], 0, fileName)
+    showLoading.value = false
+  } catch (error) {
+    console.error('图片生成失败', error)
+		Snackbar.warning('加载失败,请稍后重试')
+		showLoading.value = false
+  }
+}
+
+const handlePreview = (item) => {
+	itemData.value = item
+	if (!share.value) return
+	showLoading.value = true
+	setTimeout(() => {
+		generateAndDownloadImage()
+	}, 1000)
+}
+
+// 下载附件
+const handleDownload = (k) => {
+  getBlob(k.url).then(blob => {
+    saveAs(blob, k.title)
+  })
+}
 </script>
 
 <style scoped lang="scss">
-
+.cer-text{
+  text-decoration: underline;
+  margin: 0 3px;
+	font-weight: 700;
+}
+.cer-introduce{
+  width: 70%;
+  position: absolute;
+  top: 51%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+  text-indent: 2em;
+}
+.cer-comment{
+	width: 70%;
+  position: absolute;
+  top: 68%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+	text-indent: 2em;
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-line-clamp: 3;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+.cer-prove{
+  width: 70%;
+  position: absolute;
+  top: 82%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+  text-indent: 2em;
+}
+.cer-end{
+  position: absolute;
+  top: 87%;
+  right: 16%;
+}
 </style>