提交 cb3225f6 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 a4686548
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"dayjs": "^1.11.6", "dayjs": "^1.11.6",
"element-plus": "^2.2.21", "element-plus": "^2.2.21",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html-to-image": "^1.10.8",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"pinia": "^2.0.24", "pinia": "^2.0.24",
"qs": "^6.11.0", "qs": "^6.11.0",
...@@ -2798,6 +2799,11 @@ ...@@ -2798,6 +2799,11 @@
"resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.4.2.tgz", "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.4.2.tgz",
"integrity": "sha512-6rOvaUiNKy9lET1X0ECnyZ5O5kSV0PJbtA5yZUgdEF7fGJEVwSLSislltyt7nFwVVALYHQJtfGeAR2Y0A0uJkg==" "integrity": "sha512-6rOvaUiNKy9lET1X0ECnyZ5O5kSV0PJbtA5yZUgdEF7fGJEVwSLSislltyt7nFwVVALYHQJtfGeAR2Y0A0uJkg=="
}, },
"node_modules/html-to-image": {
"version": "1.10.8",
"resolved": "https://registry.npmmirror.com/html-to-image/-/html-to-image-1.10.8.tgz",
"integrity": "sha512-t+JyFJwKDCp4ZwBp4iC/wqw0meQDDc77Qs8OFl5P7RGlIP3LQMvwpD7VXxqQfC7/TfC+GKYlFP6WDYfXTmXHfw=="
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz",
...@@ -7060,6 +7066,11 @@ ...@@ -7060,6 +7066,11 @@
"resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.4.2.tgz", "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.4.2.tgz",
"integrity": "sha512-6rOvaUiNKy9lET1X0ECnyZ5O5kSV0PJbtA5yZUgdEF7fGJEVwSLSislltyt7nFwVVALYHQJtfGeAR2Y0A0uJkg==" "integrity": "sha512-6rOvaUiNKy9lET1X0ECnyZ5O5kSV0PJbtA5yZUgdEF7fGJEVwSLSislltyt7nFwVVALYHQJtfGeAR2Y0A0uJkg=="
}, },
"html-to-image": {
"version": "1.10.8",
"resolved": "https://registry.npmmirror.com/html-to-image/-/html-to-image-1.10.8.tgz",
"integrity": "sha512-t+JyFJwKDCp4ZwBp4iC/wqw0meQDDc77Qs8OFl5P7RGlIP3LQMvwpD7VXxqQfC7/TfC+GKYlFP6WDYfXTmXHfw=="
},
"http-errors": { "http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz",
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
"dayjs": "^1.11.6", "dayjs": "^1.11.6",
"element-plus": "^2.2.21", "element-plus": "^2.2.21",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html-to-image": "^1.10.8",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"pinia": "^2.0.24", "pinia": "^2.0.24",
"qs": "^6.11.0", "qs": "^6.11.0",
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { getExperimentReport } from '../api' import { getExperimentReport } from '../api'
const props = defineProps({ id: String }) const props = defineProps({ id: String })
const emit = defineEmits(['ready'])
let experiment = $ref() let experiment = $ref()
let report = $ref() let report = $ref()
...@@ -24,7 +25,7 @@ function fetchInfo() { ...@@ -24,7 +25,7 @@ function fetchInfo() {
report = res.data.report report = res.data.report
let detail = [] let detail = []
// 已批改 // 已批改
if (report.status === '3') { if (report.is_comment === '1') {
try { try {
detail = JSON.parse(report.score_detail).map(item => { detail = JSON.parse(report.score_detail).map(item => {
return { ...item, commit_score: parseFloat(item.commit_score) } return { ...item, commit_score: parseFloat(item.commit_score) }
...@@ -40,9 +41,12 @@ function fetchInfo() { ...@@ -40,9 +41,12 @@ function fetchInfo() {
} }
} }
report = Object.assign(report, { detail, score: parseFloat(report.score) }) report = Object.assign(report, { detail, score: parseFloat(report.score) })
nextTick(() => {
emit('ready')
})
}) })
} }
onMounted(() => { watchEffect(() => {
fetchInfo() fetchInfo()
}) })
...@@ -54,6 +58,7 @@ function handleClose() { ...@@ -54,6 +58,7 @@ function handleClose() {
<template> <template>
<div class="report-preview"> <div class="report-preview">
<div class="report-preview__inner">
<h1 class="report-title">实验报告</h1> <h1 class="report-title">实验报告</h1>
<el-form label-suffix=":" hide-required-asterisk v-if="experiment"> <el-form label-suffix=":" hide-required-asterisk v-if="experiment">
<el-row> <el-row>
...@@ -107,7 +112,7 @@ function handleClose() { ...@@ -107,7 +112,7 @@ function handleClose() {
<el-form-item v-for="(item, index) in report.detail" :key="item.id" class="report-form-item"> <el-form-item v-for="(item, index) in report.detail" :key="item.id" class="report-form-item">
<div class="form-hd"> <div class="form-hd">
<h3>{{ index + 1 }}、{{ item.name }}</h3> <h3>{{ index + 1 }}、{{ item.name }}</h3>
<p>得分:{{ item.commit_score }}分</p> <p v-if="isCommit">得分:{{ item.commit_score }}分</p>
</div> </div>
<!-- 内容 --> <!-- 内容 -->
<template v-if="item.type === 1"> <template v-if="item.type === 1">
...@@ -143,6 +148,7 @@ function handleClose() { ...@@ -143,6 +148,7 @@ function handleClose() {
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div>
<el-row justify="center"> <el-row justify="center">
<el-button type="primary" plain auto-insert-space @click="handleClose">关闭</el-button> <el-button type="primary" plain auto-insert-space @click="handleClose">关闭</el-button>
</el-row> </el-row>
...@@ -150,6 +156,10 @@ function handleClose() { ...@@ -150,6 +156,10 @@ function handleClose() {
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.report-preview__inner {
padding: 40px;
background-color: #fff;
}
.report-title { .report-title {
padding: 20px; padding: 20px;
font-size: 20px; font-size: 20px;
......
<script setup lang="ts"> <script setup lang="ts">
import type { ExperimentRecord } from '../types' import type { ExperimentRecord, ExperimentRecordFile } from '../types'
import { ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import ImageViewer from '@/components/ImageViewer.vue' import ImageViewer from '@/components/ImageViewer.vue'
import { uploadExperimentPicture } from '../api' import { uploadExperimentPicture, getExperimentReport, getExperimentReportCache } from '../api'
const ResultScoreDialog = defineAsyncComponent(() => import('./ResultScoreDialog.vue')) const ResultScoreDialog = defineAsyncComponent(() => import('./ResultScoreDialog.vue'))
interface Props { interface Props {
...@@ -29,7 +29,40 @@ function handlePreview(index: number) { ...@@ -29,7 +29,40 @@ function handlePreview(index: number) {
imageViewerIndex = index imageViewerIndex = index
} }
// 删除 // 删除
function handleRemove(index: number) { async function handleRemove(index: number, file: ExperimentRecordFile) {
if (!props.experiment_id) return
let reportDetail: any = []
await getExperimentReportCache({ experiment_id: props.experiment_id }).then(res => {
const report = res.data.report
if (report.detail) {
try {
reportDetail = JSON.parse(report.detail)
} catch (error) {
console.log(error)
}
}
})
await getExperimentReport({ experiment_id: props.experiment_id }).then(res => {
const report = res.data.report
if (report.detail) {
try {
reportDetail = JSON.parse(report.detail)
} catch (error) {
console.log(error)
}
}
})
const reportFiles: any[] = reportDetail.reduce((result: any[], item: any) => {
if (item.type === 2) {
result = result.concat(item.files)
}
return result
}, [])
const found = reportFiles.find(item => item.url === file.url)
if (found) {
ElMessage.error('不能删除实验报告中的截图,请先删除实验报告关联的截图!')
return
}
ElMessageBox.confirm('删除之后无法恢复,确认删除该截图吗?', '提示').then(() => { ElMessageBox.confirm('删除之后无法恢复,确认删除该截图吗?', '提示').then(() => {
if (!props.experiment_id) return if (!props.experiment_id) return
const pictures = detail?.pictures.filter((item, i) => i !== index) const pictures = detail?.pictures.filter((item, i) => i !== index)
...@@ -60,7 +93,7 @@ function handleRemove(index: number) { ...@@ -60,7 +93,7 @@ function handleRemove(index: number) {
<div class="cover"> <div class="cover">
<div class="cover-inner"> <div class="cover-inner">
<el-button type="primary" plain round @click="handlePreview(index)">查看</el-button> <el-button type="primary" plain round @click="handlePreview(index)">查看</el-button>
<el-button type="primary" plain round @click="handleRemove(index)" v-if="canRemove">删除</el-button> <el-button type="primary" plain round @click="handleRemove(index, item)" v-if="canRemove">删除</el-button>
</div> </div>
</div> </div>
</li> </li>
......
...@@ -8,6 +8,7 @@ import { upload } from '@/utils/upload' ...@@ -8,6 +8,7 @@ import { upload } from '@/utils/upload'
import { getExperiment, getExperimentRecord, uploadExperimentPicture, submitExperimentRecord } from '../api' import { getExperiment, getExperimentRecord, uploadExperimentPicture, submitExperimentRecord } from '../api'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { saveAs } from 'file-saver' import { saveAs } from 'file-saver'
import { toBlob } from 'html-to-image'
const Info = defineAsyncComponent(() => import('../components/Info.vue')) const Info = defineAsyncComponent(() => import('../components/Info.vue'))
const Book = defineAsyncComponent(() => import('../components/Book.vue')) const Book = defineAsyncComponent(() => import('../components/Book.vue'))
...@@ -18,7 +19,7 @@ const ReportDialog = defineAsyncComponent(() => import('../components/ReportDial ...@@ -18,7 +19,7 @@ const ReportDialog = defineAsyncComponent(() => import('../components/ReportDial
const ReportFilePreview = defineAsyncComponent(() => import('../components/ReportFilePreview.vue')) const ReportFilePreview = defineAsyncComponent(() => import('../components/ReportFilePreview.vue'))
const PrepareDialog = defineAsyncComponent(() => import('../components/PrepareDialog.vue')) const PrepareDialog = defineAsyncComponent(() => import('../components/PrepareDialog.vue'))
const ResultDialog = defineAsyncComponent(() => import('../components/ResultDialog.vue')) const ResultDialog = defineAsyncComponent(() => import('../components/ResultDialog.vue'))
// const ReportPreview = defineAsyncComponent(() => import('../components/ReportPreview.vue')) const ReportPreview = defineAsyncComponent(() => import('../components/ReportPreview.vue'))
const route = useRoute() const route = useRoute()
...@@ -179,16 +180,30 @@ function handleReportView() { ...@@ -179,16 +180,30 @@ function handleReportView() {
} }
// 导出实验报告 // 导出实验报告
let isExport = $ref(false)
function handleReportExport() { function handleReportExport() {
if (!detail) return if (!detail) return
const fileName = `${detail.student.sno_number}_${detail.student.name}_${detail.experiment.name}_实验报告` const fileName = `${detail.student.sno_number}_${detail.student.name}_${detail.experiment.name}_实验报告`
// 在线报告 // 在线报告
if (experimentInfo?.report_upload_way === 2) { if (experimentInfo?.report_upload_way === 2) {
console.log('在线报告导出') console.log('在线报告导出')
isExport = true
} else { } else {
saveAs(detail.file.url, fileName) saveAs(detail.file.url, fileName)
} }
} }
function handleReportPreviewReady() {
if (!detail) return
const fileName = `${detail.student.sno_number}_${detail.student.name}_${detail.experiment.name}_实验报告`
const el: HTMLElement | null = document.querySelector('.report-preview__inner')
if (!el) return
setTimeout(() => {
toBlob(el).then(res => {
res && saveAs(res, fileName)
isExport = false
})
}, 100)
}
</script> </script>
<template> <template>
...@@ -296,9 +311,9 @@ function handleReportExport() { ...@@ -296,9 +311,9 @@ function handleReportExport() {
v-if="resultDialogVisible && experimentInfo"></ResultDialog> v-if="resultDialogVisible && experimentInfo"></ResultDialog>
<!-- 导出在线报告 --> <!-- 导出在线报告 -->
<!-- <template v-if="experimentInfo?.id"> <template v-if="experimentInfo?.id && isExport">
<ReportPreview :id="experimentInfo?.id"></ReportPreview> <ReportPreview :id="experimentInfo?.id" @ready="handleReportPreviewReady"></ReportPreview>
</template> --> </template>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论