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

chore: update

上级 e07a9edb
VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index
VITE_LAB_URL=https://bi.ezijing.com/bi/ VITE_LAB_URL=https://digitalmarketinglab.ezijing.com
差异被折叠。
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
"@element-plus/icons-vue": "^2.0.10", "@element-plus/icons-vue": "^2.0.10",
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"@vant/area-data": "^1.3.2", "@vant/area-data": "^1.3.2",
"@vueuse/core": "^9.4.0", "@vueuse/core": "^9.5.0",
"@vueuse/head": "^0.9.8", "@vueuse/head": "^1.0.16",
"@vueuse/math": "^9.4.0", "@vueuse/math": "^9.5.0",
"ali-oss": "^6.17.1", "ali-oss": "^6.17.1",
"axios": "^1.1.3", "axios": "^1.1.3",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
"element-plus": "^2.2.21", "element-plus": "^2.2.21",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"pinia": "^2.0.23", "pinia": "^2.0.24",
"qs": "^6.11.0", "qs": "^6.11.0",
"ua-parser-js": "^1.0.32", "ua-parser-js": "^1.0.32",
"video.js": "^7.20.3", "video.js": "^7.20.3",
...@@ -50,12 +50,12 @@ ...@@ -50,12 +50,12 @@
"@vue/eslint-config-typescript": "^11.0.2", "@vue/eslint-config-typescript": "^11.0.2",
"@vue/tsconfig": "^0.1.3", "@vue/tsconfig": "^0.1.3",
"chalk": "^5.1.2", "chalk": "^5.1.2",
"eslint": "^8.26.0", "eslint": "^8.27.0",
"eslint-plugin-vue": "^9.7.0", "eslint-plugin-vue": "^9.7.0",
"sass": "^1.56.1", "sass": "^1.56.1",
"typescript": "~4.8.4", "typescript": "~4.9.3",
"unplugin-auto-import": "^0.11.4", "unplugin-auto-import": "^0.11.4",
"vite": "^3.2.3", "vite": "^3.2.4",
"vite-plugin-checker": "^0.5.1", "vite-plugin-checker": "^0.5.1",
"vue-tsc": "^1.0.9" "vue-tsc": "^1.0.9"
} }
......
import type { Router, RouteRecordRaw } from 'vue-router' import type { Router, RouteRecordRaw } from 'vue-router'
export default function ({ router }: { router: Router }) { export default function ({ router }: { router: Router }) {
const modules: Array<{ routes: Array<RouteRecordRaw> }> = Object.values(import.meta.globEager('./**/index.ts')) const modules: Array<{ routes: Array<RouteRecordRaw> }> = Object.values(
import.meta.glob('./**/index.ts', { eager: true })
)
modules.forEach(({ routes = [] }) => { modules.forEach(({ routes = [] }) => {
// 注册路由 // 注册路由
routes.forEach(route => { routes.forEach(route => {
......
...@@ -79,3 +79,34 @@ export function getExperimentResult(params: { experiment_id: string }) { ...@@ -79,3 +79,34 @@ export function getExperimentResult(params: { experiment_id: string }) {
export function updateExperimentResult(data: { experiment_id: string; detail: string }) { export function updateExperimentResult(data: { experiment_id: string; detail: string }) {
return httpRequest.post('/api/lab/v1/student/experiment/result-save', data) return httpRequest.post('/api/lab/v1/student/experiment/result-save', data)
} }
// 获取实验报告模板
export function getExperimentReportTemplate(params: { experiment_id: string }) {
return httpRequest.get('/api/lab/v1/student/experiment/report-template', { params })
}
// 更新实验在线报告
export function updateExperimentReport(data: {
experiment_id: string
experiment_address: string
experiment_date: string
detail: string
}) {
return httpRequest.post('/api/lab/v1/student/experiment/upload-online-report', data)
}
// 缓存实验在线报告
export function cacheExperimentReport(data: {
experiment_id: string
experiment_address: string
experiment_date: string
detail: string
}) {
return httpRequest.post('/api/lab/v1/student/experiment/cache-online-report', data)
}
// 获取实验在线报告缓存
export function getExperimentReportCache(params: { experiment_id: string }) {
return httpRequest.get('/api/lab/v1/student/experiment/online-report-cached', { params })
}
// 获取实验在线报告详情
export function getExperimentReport(params: { experiment_id: string }) {
return httpRequest.get('/api/lab/v1/student/experiment/online-report-detail', { params })
}
<script setup>
import { getExperimentRecord } from '../api'
import { useNow, useDateFormat } from '@vueuse/core'
const props = defineProps({ experiment: Object, data: Object })
const emit = defineEmits(['update', 'update:modelValue'])
let pictures = $ref([])
const currentPictures = $computed(() => {
return pictures.map(item => {
const is_bind = !!props.data.files.find(file => file.url === item.url)
return { ...item, is_bind }
})
})
function fetchRecord() {
getExperimentRecord({ experiment_id: props.experiment.id }).then(res => {
pictures = res.data.data.pictures || []
})
}
onMounted(() => {
fetchRecord()
})
function handleBind(row) {
const files = props.data.files
const formatted = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss')
emit('update', [
...files,
{
id: Date.now().toString(),
url: row.url,
name: row.name,
type: '2',
file_type: 'png',
updated_time: formatted.value,
upload_time: row.upload_time
}
])
}
function handleRemove(row) {
const files = props.data.files
emit(
'update',
files.filter(file => file.url !== row.url)
)
}
</script>
<template>
<el-dialog append-to-body title="关联截图" width="800px" @update:modelValue="$emit('update:modelValue')">
<el-table :data="currentPictures" stripe>
<el-table-column prop="name"></el-table-column>
<el-table-column prop="upload_time"></el-table-column>
<el-table-column width="100">
<template #default="{ row }">
<el-button text type="danger" @click="handleRemove(row)" v-if="row.is_bind">取消关联</el-button>
<el-button text type="primary" @click="handleBind(row)" v-else>关联截图</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-row justify="center">
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
</el-row>
</template>
</el-dialog>
</template>
<script setup> <script setup>
import { getExperiment } from '../api' const props = defineProps({ data: Object })
const props = defineProps({ experiment_id: String })
let detail = $ref()
const teacherText = $computed(() => { const teacherText = $computed(() => {
if (!detail) return '' if (!props.data) return ''
return detail.teachers.map(item => item.name).join('、') return props.data.teachers.map(item => item.name).join('、')
})
function fetchInfo() {
if (!props.experiment_id) return
getExperiment({ experiment_id: props.experiment_id }).then(res => {
detail = res.data.detail
})
}
watchEffect(() => {
fetchInfo()
}) })
</script> </script>
<template> <template>
<template v-if="detail && experiment_id"> <template v-if="data">
<el-form label-suffix=":" label-width="120px" label-position="right"> <el-form label-suffix=":" label-width="120px" label-position="right">
<el-form-item label="实验名称">{{ detail.name }}</el-form-item> <el-form-item label="实验名称">{{ data.name }}</el-form-item>
<el-form-item label="实验课程名称">{{ detail.course.name }}</el-form-item> <el-form-item label="实验课程名称">{{ data.course.name }}</el-form-item>
<el-form-item label="所属机构/学校">{{ detail.organization.name }}</el-form-item> <el-form-item label="所属机构/学校">{{ data.organization.name }}</el-form-item>
<el-form-item label="实验类型">{{ detail.type_level }}</el-form-item> <el-form-item label="实验类型">{{ data.type_level }}</el-form-item>
<el-form-item label="指导教师">{{ teacherText }}</el-form-item> <el-form-item label="指导教师">{{ teacherText }}</el-form-item>
<el-form-item label="实验学时">{{ detail.length }}学时</el-form-item> <el-form-item label="实验学时">{{ data.length }}学时</el-form-item>
<el-form-item label="实验总成绩">{{ detail.score }}</el-form-item> <el-form-item label="实验总成绩">{{ data.score }}</el-form-item>
</el-form> </el-form>
<el-divider /> <el-divider />
<el-form label-suffix=":" label-position="top"> <el-form label-suffix=":" label-position="top">
<el-form-item label="实验目的">{{ detail.purpose }}</el-form-item> <el-form-item label="实验目的">{{ data.purpose }}</el-form-item>
<el-form-item label="实验要求">{{ detail.requirements }}</el-form-item> <el-form-item label="实验要求">{{ data.requirements }}</el-form-item>
<el-form-item label="实验内容及原理">{{ detail.content }}</el-form-item> <el-form-item label="实验内容及原理">{{ data.content }}</el-form-item>
<el-form-item label="实验步骤及过程">{{ detail.procedure }}</el-form-item> <el-form-item label="实验步骤及过程">{{ data.procedure }}</el-form-item>
</el-form> </el-form>
</template> </template>
<el-empty description="暂无数据" v-else /> <el-empty description="暂无数据" v-else />
......
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { ExperimentInfo } from '../types'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import AppEditor from '@/components/base/AppEditor.vue' import AppEditor from '@/components/base/AppEditor.vue'
import { getExperimentPrepare, updateExperimentPrepare } from '../api' import { getExperimentPrepare, updateExperimentPrepare } from '../api'
interface Props { interface Props {
experiment_id: string data: ExperimentInfo
} }
const props = defineProps<Props>() const props = defineProps<Props>()
...@@ -17,7 +18,7 @@ const emit = defineEmits<{ ...@@ -17,7 +18,7 @@ const emit = defineEmits<{
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive({ const form = reactive({
experiment_id: props.experiment_id, experiment_id: props.data.id,
detail: '' detail: ''
}) })
const rules = ref<FormRules>({ const rules = ref<FormRules>({
...@@ -25,7 +26,7 @@ const rules = ref<FormRules>({ ...@@ -25,7 +26,7 @@ const rules = ref<FormRules>({
}) })
function fetchInfo() { function fetchInfo() {
getExperimentPrepare({ experiment_id: props.experiment_id }).then(res => { getExperimentPrepare({ experiment_id: props.data.id }).then(res => {
Object.assign(form, res.data.detail) Object.assign(form, res.data.detail)
}) })
} }
...@@ -53,7 +54,8 @@ const update = () => { ...@@ -53,7 +54,8 @@ const update = () => {
:close-on-click-modal="false" :close-on-click-modal="false"
width="800px" width="800px"
@update:modelValue="$emit('update:modelValue')"> @update:modelValue="$emit('update:modelValue')">
<el-form ref="formRef" :model="form" :rules="rules"> <el-form ref="formRef" :model="form" :rules="rules" label-suffix=":">
<el-form-item label="实验名称">{{ data.name }} </el-form-item>
<el-form-item prop="detail"> <el-form-item prop="detail">
<AppEditor v-model="form.detail"></AppEditor> <AppEditor v-model="form.detail"></AppEditor>
</el-form-item> </el-form-item>
......
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { ExperimentRecord } from '../types' import type { ExperimentInfo, ExperimentRecord } from '../types'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { uploadExperimentReport } from '../api' import { uploadExperimentReport } from '../api'
interface Props { interface Props {
experiment_id: string data: ExperimentInfo
} }
const props = defineProps<Props>() const props = defineProps<Props>()
...@@ -34,7 +34,7 @@ function handleSubmit() { ...@@ -34,7 +34,7 @@ function handleSubmit() {
const update = () => { const update = () => {
const [file] = form.files const [file] = form.files
uploadExperimentReport({ uploadExperimentReport({
experiment_id: props.experiment_id, experiment_id: props.data.id,
file: JSON.stringify({ name: file.name, url: file.url, upload_time: dayjs().format('YYYY-MM-DD HH:mm:ss') }) file: JSON.stringify({ name: file.name, url: file.url, upload_time: dayjs().format('YYYY-MM-DD HH:mm:ss') })
}).then(() => { }).then(() => {
ElMessage({ message: '上传成功', type: 'success' }) ElMessage({ message: '上传成功', type: 'success' })
......
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { ExperimentInfo } from '../types'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import AppEditor from '@/components/base/AppEditor.vue' import AppEditor from '@/components/base/AppEditor.vue'
import { getExperimentResult, updateExperimentResult } from '../api' import { getExperimentResult, updateExperimentResult } from '../api'
interface Props { interface Props {
experiment_id: string data: ExperimentInfo
} }
const props = defineProps<Props>() const props = defineProps<Props>()
...@@ -17,7 +18,7 @@ const emit = defineEmits<{ ...@@ -17,7 +18,7 @@ const emit = defineEmits<{
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive({ const form = reactive({
experiment_id: props.experiment_id, experiment_id: props.data.id,
detail: '' detail: ''
}) })
const rules = ref<FormRules>({ const rules = ref<FormRules>({
...@@ -25,7 +26,7 @@ const rules = ref<FormRules>({ ...@@ -25,7 +26,7 @@ const rules = ref<FormRules>({
}) })
function fetchInfo() { function fetchInfo() {
getExperimentResult({ experiment_id: props.experiment_id }).then(res => { getExperimentResult({ experiment_id: props.data.id }).then(res => {
Object.assign(form, res.data.detail) Object.assign(form, res.data.detail)
}) })
} }
...@@ -53,7 +54,8 @@ const update = () => { ...@@ -53,7 +54,8 @@ const update = () => {
:close-on-click-modal="false" :close-on-click-modal="false"
width="800px" width="800px"
@update:modelValue="$emit('update:modelValue')"> @update:modelValue="$emit('update:modelValue')">
<el-form ref="formRef" :model="form" :rules="rules"> <el-form ref="formRef" :model="form" :rules="rules" label-suffix=":">
<el-form-item label="实验名称">{{ data.name }} </el-form-item>
<el-form-item prop="detail"> <el-form-item prop="detail">
<AppEditor v-model="form.detail"></AppEditor> <AppEditor v-model="form.detail"></AppEditor>
</el-form-item> </el-form-item>
......
...@@ -6,6 +6,9 @@ export const routes: Array<RouteRecordRaw> = [ ...@@ -6,6 +6,9 @@ export const routes: Array<RouteRecordRaw> = [
path: '/student/lab', path: '/student/lab',
component: AppLayout, component: AppLayout,
props: { sidebar: false }, props: { sidebar: false },
children: [{ path: '', component: () => import('./views/Index.vue') }] children: [
{ path: '', component: () => import('./views/Index.vue') },
{ path: 'report/:id', component: () => import('./views/Report.vue'), props: true }
]
} }
] ]
...@@ -103,7 +103,7 @@ export interface ExperimentRecord { ...@@ -103,7 +103,7 @@ export interface ExperimentRecord {
length: number length: number
} }
course: CourseType course: CourseType
student: ExperimentRecordStudent student: ExperimentStudent
} }
export interface ExperimentRecordFile { export interface ExperimentRecordFile {
url: string url: string
...@@ -111,18 +111,37 @@ export interface ExperimentRecordFile { ...@@ -111,18 +111,37 @@ export interface ExperimentRecordFile {
upload_time: string upload_time: string
} }
export interface ExperimentRecordStudent { export interface ExperimentStudent {
id: string id: string
name: string name: string
sno_number: string sno_number: string
specialty: { specialty: IdName
id: string classes: IdName[]
name: string }
}
classes: [ // 实验信息
{ export interface ExperimentInfo {
id: string id: string
name: string name: string
} length: number
] type: number
type_level: string
score: number
status: number
purpose: string
requirements: string
content: string
procedure: string
report_upload_way: 1 | 2
teachers: IdName[]
course: IdName
organization: IdName
student: ExperimentStudent
is_commit_report: boolean
is_commit: boolean
}
interface IdName {
id: string
name: string
} }
<script setup lang="ts"> <script setup lang="ts">
import type { CourseType, ExperimentRecord } from '../types' import type { CourseType, ExperimentInfo, ExperimentRecord } from '../types'
import { HomeFilled } from '@element-plus/icons-vue' import { HomeFilled } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import DragPanel from '@/components/DragPanel.vue' import DragPanel from '@/components/DragPanel.vue'
import { useGetCourseList } from '../composables/useGetCourseList' import { useGetCourseList } from '../composables/useGetCourseList'
import { upload } from '@/utils/upload' import { upload } from '@/utils/upload'
import { getExperimentRecord, uploadExperimentPicture, submitExperimentRecord } from '../api' import { getExperiment, getExperimentRecord, uploadExperimentPicture, submitExperimentRecord } from '../api'
import dayjs from 'dayjs' import dayjs from 'dayjs'
const Info = defineAsyncComponent(() => import('../components/Info.vue')) const Info = defineAsyncComponent(() => import('../components/Info.vue'))
...@@ -59,14 +59,25 @@ function handleExperimentChange(value: string) { ...@@ -59,14 +59,25 @@ function handleExperimentChange(value: string) {
let detail = $ref<ExperimentRecord>() let detail = $ref<ExperimentRecord>()
provide('detail', $$(detail)) provide('detail', $$(detail))
let experimentInfo = $ref<ExperimentInfo>()
provide('info', $$(experimentInfo))
function fetchInfo() { function fetchInfo() {
if (!form.experiment_id) return
getExperiment({ experiment_id: form.experiment_id }).then(res => {
experimentInfo = res.data.detail
})
}
function fetchExperimentRecord() {
if (!form.experiment_id) return if (!form.experiment_id) return
getExperimentRecord({ experiment_id: form.experiment_id }).then(res => { getExperimentRecord({ experiment_id: form.experiment_id }).then(res => {
detail = Array.isArray(res.data.data) ? undefined : res.data.data detail = Array.isArray(res.data.data) ? undefined : res.data.data
}) })
} }
watchEffect(() => { watchEffect(() => {
fetchInfo() fetchInfo()
fetchExperimentRecord()
}) })
// 右侧 // 右侧
...@@ -129,7 +140,7 @@ function uploadPicture(url: string) { ...@@ -129,7 +140,7 @@ function uploadPicture(url: string) {
const pictures = detail?.pictures || [] const pictures = detail?.pictures || []
pictures.unshift({ url, name: Date.now() + '.png', upload_time: dayjs().format('YYYY-MM-DD HH:mm:ss') }) pictures.unshift({ url, name: Date.now() + '.png', upload_time: dayjs().format('YYYY-MM-DD HH:mm:ss') })
uploadExperimentPicture({ experiment_id: form.experiment_id, pictures: JSON.stringify(pictures) }).then(() => { uploadExperimentPicture({ experiment_id: form.experiment_id, pictures: JSON.stringify(pictures) }).then(() => {
fetchInfo() fetchExperimentRecord()
screenshotLoading = false screenshotLoading = false
}) })
} }
...@@ -139,7 +150,7 @@ function handleSubmit() { ...@@ -139,7 +150,7 @@ function handleSubmit() {
() => { () => {
submitExperimentRecord({ experiment_id: form.experiment_id }).then(() => { submitExperimentRecord({ experiment_id: form.experiment_id }).then(() => {
ElMessage({ message: '提交成功', type: 'success' }) ElMessage({ message: '提交成功', type: 'success' })
fetchInfo() fetchExperimentRecord()
}) })
} }
) )
...@@ -173,7 +184,7 @@ const resultDialogVisible = $ref(false) ...@@ -173,7 +184,7 @@ const resultDialogVisible = $ref(false)
</el-form> </el-form>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane label="实验信息" lazy> <el-tab-pane label="实验信息" lazy>
<Info :experiment_id="form.experiment_id"></Info> <Info :data="experimentInfo"></Info>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="实训指导" lazy> <el-tab-pane label="实训指导" lazy>
<Book :course_id="form.course_id" :experiment_id="form.experiment_id" :key="resizeKey"></Book> <Book :course_id="form.course_id" :experiment_id="form.experiment_id" :key="resizeKey"></Book>
...@@ -185,7 +196,7 @@ const resultDialogVisible = $ref(false) ...@@ -185,7 +196,7 @@ const resultDialogVisible = $ref(false)
<Discuss :experiment_id="form.experiment_id"></Discuss> <Discuss :experiment_id="form.experiment_id"></Discuss>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="过程与结果" lazy> <el-tab-pane label="过程与结果" lazy>
<Result :experiment_id="form.experiment_id" @update="fetchInfo"></Result> <Result :experiment_id="form.experiment_id" @update="fetchExperimentRecord"></Result>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
...@@ -205,10 +216,30 @@ const resultDialogVisible = $ref(false) ...@@ -205,10 +216,30 @@ const resultDialogVisible = $ref(false)
> >
<el-button type="primary" :disabled="disabled" @click="prepareDialogVisible = true">实验准备</el-button> <el-button type="primary" :disabled="disabled" @click="prepareDialogVisible = true">实验准备</el-button>
<el-button type="primary" :disabled="disabled" @click="resultDialogVisible = true">实验结果</el-button> <el-button type="primary" :disabled="disabled" @click="resultDialogVisible = true">实验结果</el-button>
<el-button type="primary" :disabled="disabled" @click="reportDialogVisible = true">在线实验报告</el-button> <el-button type="primary" :disabled="disabled" v-if="experimentInfo?.report_upload_way === 2">
<el-button type="primary" :disabled="disabled" @click="reportDialogVisible = true">上传实验报告</el-button> <router-link :to="`/student/lab/report/${form.experiment_id}`" target="_blank">在线实验报告</router-link>
<el-button type="primary" :disabled="disabled" @click="reportDialogVisible = true">查看实验报告</el-button> </el-button>
<el-button type="primary" :disabled="disabled" @click="reportDialogVisible = true">导出实验报告</el-button> <el-button
type="primary"
:disabled="disabled"
@click="reportDialogVisible = true"
v-if="experimentInfo?.report_upload_way === 1"
>上传实验报告</el-button
>
<el-button
type="primary"
:disabled="disabled"
@click="reportDialogVisible = true"
v-if="experimentInfo?.is_commit_report"
>查看实验报告</el-button
>
<el-button
type="primary"
:disabled="disabled"
@click="reportDialogVisible = true"
v-if="experimentInfo?.is_commit"
>导出实验报告</el-button
>
</div> </div>
</el-row> </el-row>
</AppCard> </AppCard>
...@@ -222,21 +253,21 @@ const resultDialogVisible = $ref(false) ...@@ -222,21 +253,21 @@ const resultDialogVisible = $ref(false)
<!-- 上传报告 --> <!-- 上传报告 -->
<ReportDialog <ReportDialog
v-model="reportDialogVisible" v-model="reportDialogVisible"
:experiment_id="form.experiment_id" :data="experimentInfo"
@update="fetchInfo" @update="fetchExperimentRecord"
v-if="reportDialogVisible && form.experiment_id"></ReportDialog> v-if="reportDialogVisible && experimentInfo"></ReportDialog>
<!-- 实验准备 --> <!-- 实验准备 -->
<PrepareDialog <PrepareDialog
v-model="prepareDialogVisible" v-model="prepareDialogVisible"
:experiment_id="form.experiment_id" :data="experimentInfo"
v-if="prepareDialogVisible && form.experiment_id"></PrepareDialog> v-if="prepareDialogVisible && experimentInfo"></PrepareDialog>
<!-- 实验结果 --> <!-- 实验结果 -->
<ResultDialog <ResultDialog
v-model="resultDialogVisible" v-model="resultDialogVisible"
:experiment_id="form.experiment_id" :data="experimentInfo"
v-if="resultDialogVisible && form.experiment_id"></ResultDialog> v-if="resultDialogVisible && experimentInfo"></ResultDialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
......
<script setup>
import AppEditor from '@/components/base/AppEditor.vue'
import { useMapStore } from '@/stores/map'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useFileDialog } from '@vueuse/core'
import { upload } from '@/utils/upload'
import { useNow, useDateFormat } from '@vueuse/core'
import {
getExperimentReport,
getExperimentReportTemplate,
getExperimentReportCache,
cacheExperimentReport,
updateExperimentReport
} from '../api'
import BindCaptureDialog from '../components/BindCaptureDialog.vue'
const props = defineProps({ id: String })
const experimentAddress = useMapStore().getMapValuesByKey('experiment_address')
let experiment = $ref()
let report = $ref()
const disabled = $computed(() => {
return experiment?.is_commit_report
})
const teacherText = $computed(() => {
if (!experiment) return ''
return experiment.teachers.map(item => item.name).join('、')
})
const classText = $computed(() => {
if (!experiment) return ''
return experiment.student.classes.map(item => item.name).join('、')
})
const formRef = $ref()
const form = reactive({
experiment_id: props.id,
experiment_address: '',
experiment_date: useDateFormat(useNow(), 'YYYY-MM-DD').value,
detail: []
})
function fetchInfo() {
getExperimentReport({ experiment_id: props.id }).then(res => {
experiment = res.data.experiment
report = res.data.report
if (experiment.is_commit_report) {
let detail = []
try {
detail = JSON.parse(report.detail)
} catch (error) {
console.log(error)
}
Object.assign(form, report, { detail })
} else {
fetchCached()
}
})
}
function fetchTemplate() {
getExperimentReportTemplate({ experiment_id: props.id }).then(res => {
form.detail = res.data.template
})
}
function fetchCached() {
getExperimentReportCache({ experiment_id: props.id }).then(res => {
const report = res.data.report
if (!report.experiment_id) {
fetchTemplate()
return
}
let detail = []
try {
detail = JSON.parse(report.detail)
} catch (error) {
console.log(error)
}
Object.assign(form, report, { detail })
})
}
onMounted(() => {
fetchInfo()
})
// 关闭
function handleClose() {
ElMessageBox.confirm('此操作将不做任何修改,确认关闭该页面?', '提示').then(() => {
window.close()
})
}
// 暂存
function handleCache() {
const params = { ...form, detail: JSON.stringify(form.detail) }
cacheExperimentReport(params).then(() => {
ElMessage.success('暂存成功')
})
}
// 提交
function handleSubmit() {
formRef.validate().then(() => {
const params = { ...form, detail: JSON.stringify(form.detail) }
ElMessageBox.confirm('提交报告之后,您将不能进行修改报告,确认提交实验报告?', '提示').then(() => {
updateExperimentReport(params).then(() => {
ElMessage.success('提交成功')
fetchInfo()
})
})
})
}
// 附件
let currentRaw = $ref(null)
// 本地上传
const { files, open, reset } = useFileDialog()
function handleUpload(data) {
currentRaw = data
open({ multiple: false })
}
watchEffect(() => {
if (!files.value?.length) return
const [file] = files.value
upload(file).then(url => {
const formatted = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss')
currentRaw.files.push({
id: Date.now().toString(),
url,
name: file.name,
type: '1',
file_type: file.type,
updated_time: formatted.value,
upload_time: formatted.value
})
reset()
})
})
// 关联截图
let bindCaptureVisible = $ref(false)
function handleBindCapture(data) {
currentRaw = data
bindCaptureVisible = true
}
// 删除文件
function handleRemoveFile(data, index) {
data.files.splice(index, 1)
}
function handleUpdateBindCapture(files) {
currentRaw.files = files
}
</script>
<template>
<AppCard title="在线填写实验报告">
<h1 class="report-title">在线填写实验报告</h1>
<el-form
ref="formRef"
:model="form"
:disabled="disabled"
label-suffix=":"
hide-required-asterisk
v-if="experiment">
<el-row>
<el-col :span="12">
<el-form-item label="课程名称">{{ experiment.course.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实验名称">{{ experiment.name }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="实验地点">
<el-select v-model="form.experiment_address">
<el-option v-for="item in experimentAddress" v-bind="item" :key="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实验日期">
<el-date-picker v-model="form.experiment_date" value-format="YYYY-MM-DD"></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="实验类型">{{ experiment.type_level }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="指导教师">{{ teacherText }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="专业">{{ experiment.student.specialty.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班级">{{ classText }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="姓名">{{ experiment.student.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学号">{{ experiment.student.sno_number }}</el-form-item>
</el-col>
</el-row>
<el-divider />
<el-form-item :label="item.name" v-for="item in form.detail" :key="item.id" class="report-form-item">
<!-- 内容 -->
<template v-if="item.type === 1">
{{ item.notice_message }}
<AppEditor v-model="item.content" :disabled="disabled" :height="200"></AppEditor>
</template>
<!-- 附件 -->
<template v-if="item.type === 2">
<el-button type="primary" @click="handleUpload(item)" v-if="item.categories.includes(2)">上传附件</el-button>
<el-button type="primary" @click="handleBindCapture(item)" v-if="item.categories.includes(1)"
>关联截图</el-button
>
<el-table :data="item.files" stripe :header-cell-style="{ background: '#ededed' }" style="margin-top: 20px">
<el-table-column label="序号" type="index" width="80" align="center"></el-table-column>
<el-table-column label="附件类型" prop="type" align="center">
<template #default="{ row }">
{{ row.type === '1' ? '本地上传' : '实验截图' }}
</template>
</el-table-column>
<el-table-column label="附件名称" prop="name" align="center"></el-table-column>
<el-table-column label="更新时间" prop="updated_time" align="center"></el-table-column>
<el-table-column label="操作" width="200" align="center">
<template #default="{ row, $index }">
<el-button text type="primary"><a :href="row.url" target="_blank">查看</a></el-button>
<el-button text type="danger" @click="handleRemoveFile(item, $index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<!-- 思考题 -->
<template v-if="item.type === 3">
{{ item.question_stem }}
<AppEditor v-model="item.content" :disabled="disabled" :height="200"></AppEditor>
</template>
</el-form-item>
<el-row justify="center">
<el-button type="primary" auto-insert-space @click="handleClose">关闭</el-button>
<el-button type="primary" auto-insert-space @click="handleCache">暂存</el-button>
<el-button type="primary" auto-insert-space @click="handleSubmit">提交报告</el-button>
</el-row>
</el-form>
<!-- 关联截图 -->
<BindCaptureDialog
v-model="bindCaptureVisible"
:experiment="detail"
:data="currentRaw"
@update="handleUpdateBindCapture"
v-if="bindCaptureVisible && currentRaw"></BindCaptureDialog>
</AppCard>
</template>
<style lang="scss">
.report-title {
padding: 20px;
font-size: 20px;
text-align: center;
}
.report-form-item {
flex-direction: column;
.el-form-item__label {
font-weight: bold;
text-align: left;
justify-content: flex-start;
}
}
</style>
<script setup>
import AppEditor from '@/components/base/AppEditor.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useFileDialog } from '@vueuse/core'
import { upload } from '@/utils/upload'
import { useNow, useDateFormat } from '@vueuse/core'
import {
getExperimentReport,
getExperimentReportTemplate,
getExperimentReportCache,
cacheExperimentReport,
updateExperimentReport
} from '../api'
import BindCaptureDialog from '../components/BindCaptureDialog.vue'
const props = defineProps({ id: String })
let experiment = $ref()
let report = $ref()
const disabled = $computed(() => {
return experiment?.is_commit_report
})
const teacherText = $computed(() => {
if (!experiment) return ''
return experiment.teachers.map(item => item.name).join('、')
})
const classText = $computed(() => {
if (!experiment) return ''
return experiment.student.classes.map(item => item.name).join('、')
})
const formRef = $ref()
const form = reactive({
experiment_id: props.id,
experiment_address: '',
experiment_date: useDateFormat(useNow(), 'YYYY-MM-DD').value,
detail: []
})
function fetchInfo() {
getExperimentReport({ experiment_id: props.id }).then(res => {
experiment = res.data.experiment
report = res.data.report
if (experiment.is_commit_report) {
let detail = []
try {
detail = JSON.parse(report.detail)
} catch (error) {
console.log(error)
}
Object.assign(form, report, { detail })
} else {
fetchCached()
}
})
}
function fetchTemplate() {
getExperimentReportTemplate({ experiment_id: props.id }).then(res => {
form.detail = res.data.template
})
}
function fetchCached() {
getExperimentReportCache({ experiment_id: props.id }).then(res => {
const report = res.data.report
if (!report.experiment_id) {
fetchTemplate()
return
}
let detail = []
try {
detail = JSON.parse(report.detail)
} catch (error) {
console.log(error)
}
Object.assign(form, report, { detail })
})
}
onMounted(() => {
fetchInfo()
})
// 关闭
function handleClose() {
ElMessageBox.confirm('此操作将不做任何修改,确认关闭该页面?', '提示').then(() => {
window.close()
})
}
// 暂存
function handleCache() {
const params = { ...form, detail: JSON.stringify(form.detail) }
cacheExperimentReport(params).then(() => {
ElMessage.success('暂存成功')
})
}
// 提交
function handleSubmit() {
formRef.validate().then(() => {
const params = { ...form, detail: JSON.stringify(form.detail) }
ElMessageBox.confirm('提交报告之后,您将不能进行修改报告,确认提交实验报告?', '提示').then(() => {
updateExperimentReport(params).then(() => {
ElMessage.success('提交成功')
fetchInfo()
})
})
})
}
// 附件
let currentRaw = $ref(null)
// 本地上传
const { files, open, reset } = useFileDialog()
function handleUpload(data) {
currentRaw = data
open({ multiple: false })
}
watchEffect(() => {
if (!files.value?.length) return
const [file] = files.value
upload(file).then(url => {
const formatted = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss')
currentRaw.files.push({
id: Date.now().toString(),
url,
name: file.name,
type: '1',
file_type: file.type,
updated_time: formatted.value,
upload_time: formatted.value
})
reset()
})
})
// 关联截图
let bindCaptureVisible = $ref(false)
function handleBindCapture(data) {
currentRaw = data
bindCaptureVisible = true
}
// 删除文件
function handleRemoveFile(data, index) {
data.files.splice(index, 1)
}
function handleUpdateBindCapture(files) {
currentRaw.files = files
}
</script>
<template>
<AppCard title="查看实验报告">
<h1 class="report-title">查看实验报告</h1>
<el-form ref="formRef" :model="form" label-suffix=":" hide-required-asterisk v-if="experiment">
<el-row>
<el-col :span="12">
<el-form-item label="课程名称">{{ experiment.course.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实验名称">{{ experiment.name }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="实验地点">{{ report.experiment_address }} </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实验日期"> {{ report.experiment_date }} </el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="实验类型">{{ experiment.type_level }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="指导教师">{{ teacherText }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="专业">{{ experiment.student.specialty.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班级">{{ classText }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="姓名">{{ experiment.student.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学号">{{ experiment.student.sno_number }}</el-form-item>
</el-col>
</el-row>
<el-divider />
<el-form-item :label="item.name" v-for="item in form.detail" :key="item.id" class="report-form-item">
<!-- 内容 -->
<template v-if="item.type === 1">
{{ item.notice_message }}
<AppEditor v-model="item.content" :disabled="disabled" :height="200"></AppEditor>
</template>
<!-- 附件 -->
<template v-if="item.type === 2">
<el-button type="primary" @click="handleUpload(item)" v-if="item.categories.includes(2)">上传附件</el-button>
<el-button type="primary" @click="handleBindCapture(item)" v-if="item.categories.includes(1)"
>关联截图</el-button
>
<el-table :data="item.files" stripe :header-cell-style="{ background: '#ededed' }" style="margin-top: 20px">
<el-table-column label="序号" type="index" width="80" align="center"></el-table-column>
<el-table-column label="附件类型" prop="type" align="center">
<template #default="{ row }">
{{ row.type === '1' ? '本地上传' : '实验截图' }}
</template>
</el-table-column>
<el-table-column label="附件名称" prop="name" align="center"></el-table-column>
<el-table-column label="更新时间" prop="updated_time" align="center"></el-table-column>
<el-table-column label="操作" width="200" align="center">
<template #default="{ row, $index }">
<el-button text type="primary"><a :href="row.url" target="_blank">查看</a></el-button>
<el-button text type="danger" @click="handleRemoveFile(item, $index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<!-- 思考题 -->
<template v-if="item.type === 3">
{{ item.question_stem }}
<AppEditor v-model="item.content" :disabled="disabled" :height="200"></AppEditor>
</template>
</el-form-item>
<el-row justify="center">
<el-button type="primary" auto-insert-space @click="handleClose">关闭</el-button>
<el-button type="primary" auto-insert-space @click="handleCache">暂存</el-button>
<el-button type="primary" auto-insert-space @click="handleSubmit">提交报告</el-button>
</el-row>
</el-form>
<!-- 关联截图 -->
<BindCaptureDialog
v-model="bindCaptureVisible"
:experiment="detail"
:data="currentRaw"
@update="handleUpdateBindCapture"
v-if="bindCaptureVisible && currentRaw"></BindCaptureDialog>
</AppCard>
</template>
<style lang="scss">
.report-title {
padding: 20px;
font-size: 20px;
text-align: center;
}
.report-form-item {
flex-direction: column;
.el-form-item__label {
font-weight: bold;
text-align: left;
justify-content: flex-start;
}
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论