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

feat: 添加删除功能,支持删除实验指导书、案例原文和操作视频

上级 00476186
......@@ -27,3 +27,8 @@ export function createBook(data: BookCreateItem) {
export function updateBook(data: BookCreateItem) {
return httpRequest.post('/api/lab/v1/teacher/book/update', data)
}
// 删除指导书
export function deleteBook(data: { id: string }) {
return httpRequest.post('/api/lab/v1/teacher/book/delete', data)
}
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { BookItem, BookCreateItem } from '../types'
import type { BookFormData, BookItem, BookCreateItem } from '../types'
import { ElMessageBox, ElMessage } from 'element-plus'
import AppUpload from '@/components/base/AppUpload.vue'
import { createBook, updateBook } from '../api'
import { useGetCourseList } from '../composables/useGetCourseList'
import { useGetExperimentList } from '../composables/useGetExperimentList'
import { useMapStore } from '@/stores/map'
......@@ -19,32 +18,29 @@ const emit = defineEmits<{
(e: 'update:modelValue', visible: boolean): void
}>()
// 课程列表
const { courses } = useGetCourseList()
// 数据状态
const status = useMapStore().getMapValuesByKey('system_status')
// 实验列表
const { experiments, updateExperiments } = useGetExperimentList()
const formRef = $ref<FormInstance>()
const form = reactive<BookCreateItem>({
const form = reactive<BookFormData>({
name: '',
course_id: '',
experiment_id: '',
status: '1',
url: '',
type: '',
size: '',
files: [],
protocol: false
protocol: true
})
watchEffect(() => {
if (!props.data) return
form.files = [{ name: props.data.name, url: props.data.url, type: props.data.type }]
Object.assign(form, { protocol: true }, props.data)
})
watchEffect(() => {
updateExperiments(form.course_id)
onMounted(() => {
updateExperiments()
})
const checkProtocol = (rule: any, value: any, callback: any) => {
if (!value) {
......@@ -56,7 +52,6 @@ const checkProtocol = (rule: any, value: any, callback: any) => {
const rules = ref<FormRules>({
files: [{ type: 'array', required: true, message: '请上传实验指导书' }],
name: [{ required: true, message: '请输入实验指导书名称', trigger: 'blur' }],
course_id: [{ required: true, message: '请选择关联实验课程', trigger: 'change' }],
experiment_id: [{ required: true, message: '请选择关联实验', trigger: 'change' }],
protocol: [{ validator: checkProtocol, message: '请阅读并同意', trigger: 'change' }]
})
......@@ -121,11 +116,6 @@ function handleUpdate(params: BookCreateItem) {
<el-input v-model="form.name"></el-input>
<p class="form-tips">实验指导书名称自动取值于文件名称,可以进行二次修改。</p>
</el-form-item>
<el-form-item label="关联实验课程" prop="course_id">
<el-select v-model="form.course_id" filterable style="width: 100%" @change="form.experiment_id = ''">
<el-option v-for="item in courses" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="关联实验" prop="experiment_id">
<el-select v-model="form.experiment_id" filterable style="width: 100%">
<el-option v-for="item in experiments" :key="item.id" :label="item.name" :value="item.id"></el-option>
......
......@@ -24,12 +24,14 @@ export interface BookItem {
export interface BookCreateItem {
id?: string
experiment_id: string
course_id: string
status: string
name: string
type: string
url: string
size: string
}
export interface BookFormData extends BookCreateItem {
protocol: boolean
files: FileItem[]
}
......
......@@ -2,9 +2,10 @@
import type { BookItem } from '../types'
import { CirclePlus } from '@element-plus/icons-vue'
import { useLocalStorage } from '@vueuse/core'
import { ElMessage, ElMessageBox } from 'element-plus'
import AppList from '@/components/base/AppList.vue'
import ListItem from '../components/ListItem.vue'
import { getBookList } from '../api'
import { deleteBook, getBookList } from '../api'
import { useGetExperimentList } from '../composables/useGetExperimentList'
import { useMapStore } from '@/stores/map'
......@@ -63,7 +64,7 @@ const listOptions = $computed(() => {
{ label: '创建人', prop: 'created_operator_name', width: 120 },
{ label: '创建时间', prop: 'created_time', width: 180 },
{ label: '更新时间', prop: 'updated_time', width: 180 },
{ label: '操作', slots: 'table-x', width: 160 },
{ label: '操作', slots: 'table-x', width: 260 },
],
}
})
......@@ -81,6 +82,14 @@ function handleUpdate(row: BookItem) {
dialogVisible = true
}
async function handleDelete(row: BookItem) {
ElMessageBox.confirm(`确定要删除实验指导书“${row.name}”吗?`, '提示').then(async () => {
await deleteBook({ id: row.id })
ElMessage.success('删除成功')
appList?.refetch()
})
}
function onUpdateSuccess() {
appList?.refetch()
}
......@@ -118,7 +127,12 @@ function onUpdateSuccess() {
</template>
<template #body="{ data }" v-if="viewMode === 'card'">
<div class="list-card" v-if="data.length">
<ListItem v-for="item in data" :data="item" :key="item.id" @clickEdit="handleUpdate(item)"></ListItem>
<ListItem
v-for="item in data"
:data="item"
:key="item.id"
@clickEdit="handleUpdate(item)"
@clickDelete="handleDelete(item)"></ListItem>
</div>
<el-empty description="暂无数据" v-else />
</template>
......@@ -129,6 +143,7 @@ function onUpdateSuccess() {
<el-button type="primary" round @click="handleUpdate(row)" v-permission="'v1-teacher-book-update'"
>编辑</el-button
>
<el-button type="danger" round @click="handleDelete(row)" v-permission="'v1-teacher-book-delete'">删除</el-button>
</template>
<template #table-status="{ row }: { row: BookItem }">
<span :class="isActiveStatus(row.status) ? 'status-active' : 'status-inactive'">{{ row.status_name }}</span>
......
......@@ -27,3 +27,8 @@ export function createCase(data: CaseCreateItem) {
export function updateCase(data: CaseCreateItem) {
return httpRequest.post('/api/lab/v1/teacher/experiment-cases/update', data)
}
// 删除案例原文
export function deleteCase(data: { id: string }) {
return httpRequest.post('/api/lab/v1/teacher/experiment-cases/delete', data)
}
......@@ -5,7 +5,6 @@ import { ElMessageBox, ElMessage } from 'element-plus'
import AppUpload from '@/components/base/AppUpload.vue'
import { createCase, updateCase } from '../api'
import { useGetCourseList } from '../composables/useGetCourseList'
import { useGetExperimentList } from '../composables/useGetExperimentList'
import { useMapStore } from '@/stores/map'
......@@ -19,8 +18,6 @@ const emit = defineEmits<{
(e: 'update:modelValue', visible: boolean): void
}>()
// 课程列表
const { courses } = useGetCourseList()
// 数据状态
const status = useMapStore().getMapValuesByKey('system_status')
// 实验列表
......@@ -29,22 +26,21 @@ const { experiments, updateExperiments } = useGetExperimentList()
const formRef = $ref<FormInstance>()
const form = reactive<CaseFormData>({
name: '',
course_id: '',
experiment_id: '',
status: '1',
url: '',
type: '',
size: '',
files: [],
protocol: false
protocol: true
})
watchEffect(() => {
if (!props.data) return
form.files = [{ name: props.data.name, url: props.data.url, type: props.data.type }]
Object.assign(form, { protocol: true, course_id: props.data.course.id }, props.data)
Object.assign(form, { protocol: true }, props.data)
})
watchEffect(() => {
updateExperiments(form.course_id)
onMounted(() => {
updateExperiments()
})
const checkProtocol = (rule: any, value: any, callback: any) => {
if (!value) {
......@@ -56,7 +52,6 @@ const checkProtocol = (rule: any, value: any, callback: any) => {
const rules = ref<FormRules>({
files: [{ type: 'array', required: true, message: '请上传案例原文' }],
name: [{ required: true, message: '请输入案例原文名称', trigger: 'blur' }],
course_id: [{ required: true, message: '请选择关联实验课程', trigger: 'change' }],
experiment_id: [{ required: true, message: '请选择关联实验', trigger: 'change' }],
protocol: [{ validator: checkProtocol, message: '请阅读并同意', trigger: 'change' }]
})
......@@ -66,13 +61,6 @@ const isUpdate = $computed(() => {
const title = $computed(() => {
return isUpdate ? '编辑案例原文' : '新增案例原文'
})
// 实验列表
const experimentList = $computed(() => {
if (!props.data) return experiments.value
return isUpdate && props.data.course.id === form.course_id
? [{ id: props.data.experiment_id, name: props.data.experiment.name }, ...experiments.value]
: experiments.value
})
function handleBeforeUpload() {
if (form.files.length) {
......@@ -128,14 +116,9 @@ function handleUpdate(params: CaseUpdateItem) {
<el-input v-model="form.name"></el-input>
<p class="form-tips">案例原文名称自动取值于文件名称,可以进行二次修改。</p>
</el-form-item>
<el-form-item label="关联实验课程" prop="course_id">
<el-select v-model="form.course_id" filterable style="width: 100%" @change="form.experiment_id = ''">
<el-option v-for="item in courses" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="关联实验" prop="experiment_id">
<el-select v-model="form.experiment_id" filterable style="width: 100%">
<el-option v-for="item in experimentList" :key="item.id" :label="item.name" :value="item.id"></el-option>
<el-option v-for="item in experiments" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="有效状态" prop="status">
......
......@@ -33,7 +33,6 @@ export interface CaseOperator {
export interface CaseFormData {
id?: string
experiment_id: string
course_id: string
status: string
name: string
type: string
......
......@@ -2,9 +2,10 @@
import type { CaseItem } from '../types'
import { CirclePlus } from '@element-plus/icons-vue'
import { useLocalStorage } from '@vueuse/core'
import { ElMessage, ElMessageBox } from 'element-plus'
import AppList from '@/components/base/AppList.vue'
import ListItem from '../components/ListItem.vue'
import { getCaseList } from '../api'
import { deleteCase, getCaseList } from '../api'
import { useGetExperimentList } from '../composables/useGetExperimentList'
import { useMapStore } from '@/stores/map'
......@@ -95,7 +96,7 @@ const listOptions = $computed(() => {
{ label: '创建人', prop: 'created_operator_name', width: 120 },
{ label: '创建时间', prop: 'created_time', width: 180 },
{ label: '更新时间', prop: 'updated_time', width: 180 },
{ label: '操作', slots: 'table-x', width: 160 },
{ label: '操作', slots: 'table-x', width: 260 },
],
}
})
......@@ -113,6 +114,14 @@ function handleUpdate(row: CaseItem) {
dialogVisible = true
}
async function handleDelete(row: CaseItem) {
ElMessageBox.confirm(`确定要删除案例原文“${row.name}”吗?`, '提示').then(async () => {
await deleteCase({ id: row.id })
ElMessage.success('删除成功')
appList?.refetch()
})
}
function onUpdateSuccess() {
appList?.refetch()
}
......@@ -150,7 +159,12 @@ function onUpdateSuccess() {
</template>
<template #body="{ data }: { data: CaseListRow[] }" v-if="viewMode === 'card'">
<div class="list-card" v-if="viewMode === 'card' && data.length">
<ListItem v-for="item in data" :data="item" :key="item.id" @clickEdit="handleUpdate(item)"></ListItem>
<ListItem
v-for="item in data"
:data="item"
:key="item.id"
@clickEdit="handleUpdate(item)"
@clickDelete="handleDelete(item)"></ListItem>
</div>
<el-empty description="暂无数据" v-else />
</template>
......@@ -161,6 +175,9 @@ function onUpdateSuccess() {
<el-button type="primary" round @click="handleUpdate(row)" v-permission="'teacher-experiment-cases-update'"
>编辑</el-button
>
<el-button type="danger" round @click="handleDelete(row)" v-permission="'teacher-experiment-cases-delete'"
>删除</el-button
>
</template>
<template #table-status="{ row }: { row: CaseListRow }">
<span :class="isActiveStatus(row.status) ? 'status-active' : 'status-inactive'">{{ row.status_name }}</span>
......
......@@ -27,3 +27,8 @@ export function createVideo(data: VideoCreateItem) {
export function updateVideo(data: VideoCreateItem) {
return httpRequest.post('/api/lab/v1/teacher/video/update', data)
}
// 删除操作视频
export function deleteVideo(data: { id: string }) {
return httpRequest.post('/api/lab/v1/teacher/video/delete', data)
}
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { VideoItem, VideoCreateItem } from '../types'
import type { VideoFormData, VideoItem, VideoCreateItem } from '../types'
import { ElMessageBox, ElMessage } from 'element-plus'
import UploadVideo from '@/components/UploadVideo.vue'
import { createVideo, updateVideo } from '../api'
import { useGetCourseList } from '../composables/useGetCourseList'
import { useGetExperimentList } from '../composables/useGetExperimentList'
import { useMapStore } from '@/stores/map'
......@@ -19,28 +18,25 @@ const emit = defineEmits<{
(e: 'update:modelValue', visible: boolean): void
}>()
// 课程列表
const { courses } = useGetCourseList()
// 数据状态
const status = useMapStore().getMapValuesByKey('system_status')
// 实验列表
const { experiments, updateExperiments } = useGetExperimentList()
const formRef = $ref<FormInstance>()
const form = reactive<VideoCreateItem>({
const form = reactive<VideoFormData>({
name: '',
course_id: '',
experiment_id: '',
status: '1',
source_id: '',
protocol: false
protocol: true
})
watchEffect(() => {
if (!props.data) return
Object.assign(form, { protocol: true }, props.data)
})
watchEffect(() => {
updateExperiments(form.course_id)
onMounted(() => {
updateExperiments()
})
const checkProtocol = (rule: any, value: any, callback: any) => {
if (!value) {
......@@ -52,7 +48,6 @@ const checkProtocol = (rule: any, value: any, callback: any) => {
const rules = ref<FormRules>({
source_id: [{ required: true, message: '请上传实验操作视频' }],
name: [{ required: true, message: '请输入实验操作视频名称', trigger: 'blur' }],
course_id: [{ required: true, message: '请选择关联实验课程', trigger: 'change' }],
experiment_id: [{ required: true, message: '请选择关联实验', trigger: 'change' }],
protocol: [{ validator: checkProtocol, message: '请阅读并同意', trigger: 'change' }]
})
......@@ -110,11 +105,6 @@ function handleUpdate(params: VideoCreateItem) {
<el-input v-model="form.name"></el-input>
<p class="form-tips">操作视频名称自动取值于文件名称,可以进行二次修改。</p>
</el-form-item>
<el-form-item label="关联实验课程" prop="course_id">
<el-select v-model="form.course_id" filterable style="width: 100%" @change="form.experiment_id = ''">
<el-option v-for="item in courses" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="关联实验" prop="experiment_id">
<el-select v-model="form.experiment_id" filterable style="width: 100%">
<el-option v-for="item in experiments" :key="item.id" :label="item.name" :value="item.id"></el-option>
......
......@@ -24,9 +24,11 @@ export interface VideoItem {
export interface VideoCreateItem {
id?: string
experiment_id: string
course_id: string
status: string
name: string
source_id: string
}
export interface VideoFormData extends VideoCreateItem {
protocol: boolean
}
......@@ -2,9 +2,10 @@
import type { VideoItem } from '../types'
import { CirclePlus } from '@element-plus/icons-vue'
import { useLocalStorage } from '@vueuse/core'
import { ElMessage, ElMessageBox } from 'element-plus'
import AppList from '@/components/base/AppList.vue'
import ListItem from '../components/ListItem.vue'
import { getVideoList } from '../api'
import { deleteVideo, getVideoList } from '../api'
import { useGetExperimentList } from '../composables/useGetExperimentList'
import { useMapStore } from '@/stores/map'
......@@ -63,7 +64,7 @@ const listOptions = $computed(() => {
{ label: '创建人', prop: 'created_operator_name', width: 120 },
{ label: '创建时间', prop: 'created_time', width: 180 },
{ label: '更新时间', prop: 'updated_time', width: 180 },
{ label: '操作', slots: 'table-x', width: 160 },
{ label: '操作', slots: 'table-x', width: 260 },
],
}
})
......@@ -81,6 +82,14 @@ function handleUpdate(row: VideoItem) {
dialogVisible = true
}
async function handleDelete(row: VideoItem) {
ElMessageBox.confirm(`确定要删除实验操作视频“${row.name}”吗?`, '提示').then(async () => {
await deleteVideo({ id: row.id })
ElMessage.success('删除成功')
appList?.refetch()
})
}
function onUpdateSuccess() {
appList?.refetch()
}
......@@ -118,7 +127,12 @@ function onUpdateSuccess() {
</template>
<template #body="{ data }" v-if="viewMode === 'card'">
<div class="list-card" v-if="data.length">
<ListItem v-for="item in data" :data="item" :key="item.id" @clickEdit="handleUpdate(item)"></ListItem>
<ListItem
v-for="item in data"
:data="item"
:key="item.id"
@clickEdit="handleUpdate(item)"
@clickDelete="handleDelete(item)"></ListItem>
</div>
<el-empty description="暂无数据" v-else />
</template>
......@@ -129,6 +143,9 @@ function onUpdateSuccess() {
<el-button type="primary" round @click="handleUpdate(row)" v-permission="'v1-teacher-video-update'"
>编辑</el-button
>
<el-button type="danger" round @click="handleDelete(row)" v-permission="'v1-teacher-video-delete'"
>删除</el-button
>
</template>
<template #table-status="{ row }: { row: VideoItem }">
<span :class="isActiveStatus(row.status) ? 'status-active' : 'status-inactive'">{{ row.status_name }}</span>
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论