|
|
<template> <div class="app-container"><!-- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">--><!-- <el-form-item>--><!-- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>--><!-- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>--><!-- </el-form-item>--><!-- </el-form>-->
<el-row :gutter="10" class="mb8"> <el-col :span="1.5"> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['vet:training:add']" >新增</el-button> </el-col> <el-col :span="1.5"> <el-button type="info" plain icon="el-icon-s-promotion" size="mini" :disabled="single" @click="handleSubmitAudit" v-hasPermi="['vet:training:submit']" >提交审核</el-button> </el-col> <el-col :span="1.5"> <el-button type="primary" plain icon="el-icon-finished" size="mini" :disabled="single" @click="handleAuditDialog" v-hasPermi="['vet:training:audit']" >审核</el-button> </el-col> <el-col :span="1.5"> <el-button type="success" plain icon="el-icon-check" size="mini" :disabled="single" @click="handlePublish" v-hasPermi="['vet:training:publish']" >上架视频</el-button> </el-col> <el-col :span="1.5"> <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['vet:training:remove']" >删除</el-button> </el-col> <el-col :span="1.5"> <el-button type="warning" plain icon="el-icon-download" size="mini" :disabled="single" @click="handleOffline" v-hasPermi="['vet:training:offline']" >下架视频</el-button> </el-col> <el-col :span="1.5"> <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['vet:training:export']" >导出</el-button> </el-col> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> </el-row>
<el-table v-loading="loading" :data="trainingList" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55" align="center" /> <el-table-column label="发布者" align="center" prop="publisherName" width="120"> <template slot-scope="scope"> <span>{{ scope.row.publisherName || '-' }}</span> </template> </el-table-column> <el-table-column label="视频标题" align="center" prop="title" show-overflow-tooltip/> <el-table-column label="视频描述" align="center" prop="description" show-overflow-tooltip/> <el-table-column label="视频地址" align="center" prop="videoUrl" width="180" /> <el-table-column label="封面图片" align="center" prop="coverImage" width="100"> <template slot-scope="scope"> <image-preview :src="scope.row.coverImage" :width="50" :height="50"/> </template> </el-table-column> <el-table-column label="分类" align="center" prop="category"> <template slot-scope="scope"> <dict-tag :options="dict.type.video_category" :value="scope.row.category" /> </template> </el-table-column> <el-table-column label="观看次数" align="center" prop="viewCount" /> <el-table-column label="发布时间" align="center" prop="publishTime" min-width="200" show-overflow-tooltip />
<!-- 状态列 --> <el-table-column label="上架状态" align="center" prop="status" width="100"> <template slot-scope="scope"> <el-tag :type="getStatusType(scope.row.status)" size="small"> {{ getStatusText(scope.row.status) }} </el-tag> </template> </el-table-column>
<!-- 审核状态列 --> <el-table-column label="审核状态" align="center" prop="auditStatus" width="100"> <template slot-scope="scope"> <el-tag :type="getAuditStatusType(scope.row.auditStatus)" size="small"> {{ getAuditStatusText(scope.row.auditStatus) }} </el-tag> </template> </el-table-column>
<el-table-column label="审核意见" align="center" prop="auditOpinion" width="150" show-overflow-tooltip> <template slot-scope="scope"> <span v-if="scope.row.auditOpinion">{{ truncateText(scope.row.auditOpinion, 15) }}</span> <span v-else>-</span> </template> </el-table-column>
<!-- 操作列 --> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="300"> <template slot-scope="scope"> <!-- 修改按钮 --> <el-button size="mini" type="text" icon="el-icon-edit" style="color: #42B983" @click="handleUpdate(scope.row)" v-hasPermi="['vet:training:edit']" v-if="scope.row.status === '0' && (scope.row.auditStatus === '3' || scope.row.auditStatus === '0')" class="info-btn alter-btn" >修改</el-button>
<!-- 提交审核按钮:审核拒绝或无需审核状态 --> <el-button size="mini" type="text" icon="el-icon-s-promotion" style="color: #dab708" @click="handleSubmitAudit(scope.row.id)" v-hasPermi="['vet:training:submit']" v-if="scope.row.status === '0' && scope.row.auditStatus === '0'" class="info-btn submit-btn" >提交审核</el-button>
<!-- 审核按钮:待审核状态(管理员) --> <el-button size="mini" type="text" icon="el-icon-finished" @click="handleAuditDialog(scope.row.id)" style="color: #072eed" v-hasPermi="['vet:training:audit']" v-if="scope.row.auditStatus === '0' && isAdmin" class="info-btn audit-btn" >审核</el-button>
<!-- 上架按钮:审核通过且未上架 --> <el-button size="mini" type="text" icon="el-icon-top" @click="handlePublish(scope.row.id)" style="color: #f46a0c" v-hasPermi="['vet:training:publish']" v-if="scope.row.auditStatus === '2' && scope.row.status === '0'" class="info-btn publish-btn" >上架</el-button>
<!-- 下架按钮:已上架状态 --> <el-button size="mini" type="text" icon="el-icon-bottom" style="color: #636361" @click="handleOffline(scope.row.id)" v-hasPermi="['vet:training:offline']" v-if="scope.row.status === '1'" class="info-btn offline-btn" >下架</el-button>
<!-- 取消审核按钮 --><!-- <el-button--><!-- size="mini"--><!-- type="text"--><!-- icon="el-icon-close"--><!-- style="color: #5607b3"--><!-- @click="handleCancelAudit(scope.row.id)"--><!-- v-hasPermi="['vet:training:edit']"--><!-- v-if="scope.row.auditStatus === '1' && !isAdmin"--><!-- class="info-btn cancel-btn"--><!-- >取消审核</el-button>--> <el-button size="mini" type="text" icon="el-icon-close" style="color: #5607b3" @click="handleCancelAudit(scope.row.id)" v-hasPermi="['vet:training:edit']" v-if="scope.row.auditStatus === '1'" class="info-btn cancel-btn" >取消审核</el-button>
<el-button size="mini" type="text" icon="el-icon-s-promotion" style="color: #c108af" @click="handleResubmitAudit(scope.row)" class="info-btn resubmit-btn" v-hasPermi="['vet:training:submit']" v-if="scope.row.status === '0' && scope.row.auditStatus === '3'" > 重新提交 </el-button>
<!-- 删除按钮 --> <el-button size="mini" type="text" icon="el-icon-delete" style="color: #f56c6c" @click="handleDelete(scope.row)" v-hasPermi="['vet:training:remove']" class="info-btn delete-btn" >删除</el-button> </template> </el-table-column> </el-table>
<div class="pagestyle"> <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> </div>
<!-- 添加或修改兽医培训视频对话框 --> <el-dialog :title="title" :visible.sync="open" width="80%" append-to-body> <el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form-item label="视频标题" prop="title"> <el-input v-model="form.title" placeholder="请输入视频标题" /> </el-form-item> <el-form-item label="视频描述" prop="description"> <el-input v-model="form.description" type="textarea" placeholder="请输入内容" /> </el-form-item> <el-form-item label="发布时间" prop="publishTime"> <el-date-picker v-model="form.publishTime" type="date" value-format="yyyy-MM-dd" placeholder="请选择时间" style="width: 100%;" /> </el-form-item> <el-form-item label="视频" required> <div style="display: flex; flex-direction: column; gap: 12px;"> <!-- 简单的文件选择方式 --> <div v-if="!form.videoUrl"> <input type="file" ref="videoInput" accept=".mp4,.avi,.mov,.wmv,.flv,.mkv" @change="handleFileSelect" style="display: none" /> <el-button type="primary" @click="$refs.videoInput.click()" :loading="uploading" > <el-icon><Upload /></el-icon> {{ uploading ? '上传中...' : '点击上传视频' }} </el-button> <div class="el-upload__tip" style="margin-top: 7px; color: #909399; font-size: 12px;"> 支持 MP4、AVI、MOV、WMV、FLV、MKV 格式,大小不超过200MB </div> </div>
<!-- 预览区域(上传后显示) --> <div v-if="form.videoUrl" class="video-preview"> <div style="display: flex; align-items: flex-start; gap: 10px;"> <video :src="getVideoUrl(form.videoUrl)" controls style="max-width: 300px; max-height: 150px; border-radius: 4px; background: #000;" ></video> <div style="display: flex; flex-direction: column; gap: 5px;"> <el-button type="danger" size="small" @click="removeVideo" circle > <el-icon><Delete /></el-icon> </el-button> <el-button type="primary" size="small" @click="previewVideo" > 预览 </el-button> </div> </div> </div>
<!-- 地址输入框(可编辑) --> <el-form-item prop="videoUrl" style="margin-bottom: 0;"> <el-input v-model="form.videoUrl" type="textarea" :rows="2" placeholder="请上传视频或直接输入视频地址" clearable /> </el-form-item> </div> </el-form-item> <el-form-item label="封面图片" prop="coverImage"> <image-upload v-model="form.coverImage"/> </el-form-item> <el-form-item label="分类" prop="category"> <el-select v-model="form.category" placeholder="请选择分类" clearable> <el-option v-for="dict in dict.type.video_category" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitForm">确 定</el-button> <el-button @click="cancel">取 消</el-button> </div> </el-dialog>
<!-- ================= 审核对话框 ================= --> <el-dialog title="视频审核" :visible.sync="auditOpen" width="80%" append-to-body > <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="80px"> <el-form-item label="审核结果" prop="auditStatus" required> <el-radio-group v-model="auditForm.auditStatus"> <el-radio v-for="item in auditStatusOptions.filter(item => ['1', '2'].includes(item.dictValue))" :key="item.dictValue" :label="item.dictValue" > {{ item.dictLabel }} </el-radio> </el-radio-group> </el-form-item> <el-form-item label="审核意见" prop="auditOpinion"> <el-input v-model="auditForm.auditOpinion" type="textarea" :rows="4" placeholder="请输入审核意见(审核拒绝时必须填写)" maxlength="500" show-word-limit /> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitAudit">确 定</el-button> <el-button @click="cancelAudit">取 消</el-button> </div> </el-dialog> </div></template>
<script>import { listTraining, getTraining, delTraining, addTraining, updateTraining, uploadVideo, resubmitAudit} from "@/api/vet/training"import { submitForAudit, cancelAudit, auditVideo, publishVideo, offlineVideo, batchSubmitAudit, batchAuditVideo, batchPublishVideo, batchOfflineVideo} from "@/api/vet/training"import { getToken } from "@/utils/auth"
export default { name: "Training", dicts: ['video_category'], data() { return { // 遮罩层
loading: true, // 选中数组
ids: [], // 非单个禁用
single: true, // 非多个禁用
multiple: true, // 显示搜索条件
showSearch: true, // 总条数
total: 0, // 兽医培训视频表格数据
trainingList: [], // 弹出层标题
title: "", // 是否显示弹出层
open: false, // 上传相关变量
uploading: false,
// 是否为管理员
isAdmin: false,
// 字典数据
statusOptions: [ { dictValue: '0', dictLabel: '未上架', listClass: 'info' }, { dictValue: '1', dictLabel: '已上架', listClass: 'success' } ], auditStatusOptions: [ { dictValue: '0', dictLabel: '待审核', listClass: 'info' }, { dictValue: '1', dictLabel: '审核中', listClass: 'warning' }, { dictValue: '2', dictLabel: '审核通过', listClass: 'success' }, { dictValue: '3', dictLabel: '审核驳回', listClass: 'danger' } ],
// 查询参数
queryParams: { pageNum: 1, pageSize: 10, title: null, description: null, videoUrl: null, coverImage: null, category: null, tags: null, duration: null, fileSize: null, viewCount: null, status: null, auditStatus: null, auditOpinion: null, auditUserId: null, auditTime: null },
// 表单参数
form: { id: undefined, userId: undefined, title: "", description: "", videoUrl: "", coverImage: "", category: "", tags: "", duration: undefined, fileSize: undefined, viewCount: undefined, status: "0", createTime: undefined, updateTime: undefined, delFlag: undefined, auditStatus: "0", auditOpinion: "", auditUserId: undefined, auditTime: undefined },
// 表单校验
rules: { title: [ { required: true, message: "视频标题不能为空", trigger: "blur" } ], videoUrl: [ { required: true, message: "视频地址不能为空", trigger: "blur" } ], category: [ { required: true, message: "分类不能为空", trigger: "blur" } ] },
// ========== 审核相关 ==========
auditOpen: false, auditForm: { id: null, auditStatus: '1', auditOpinion: '' }, auditRules: { auditOpinion: [ { validator: (rule, value, callback) => { if (this.auditForm.auditStatus === '2' && (!value || value.trim() === '')) { callback(new Error('审核拒绝时必须填写审核意见')) } else { callback() } }, trigger: 'blur' } ] } } }, created() { this.getList() this.checkAdminRole() }, methods: { /** 检查是否是管理员 */ checkAdminRole() { const userInfo = this.$store.getters.userInfo || {} this.isAdmin = userInfo.roles && userInfo.roles.includes('admin') },
/** 查询兽医培训视频列表 */ getList() { this.loading = true listTraining(this.queryParams).then(response => { this.trainingList = response.rows this.total = response.total this.loading = false }).catch(() => { this.loading = false }) },
/** ============ 字典工具方法 ============ */ /** 通过字典值获取标签 */ getDictLabel(options, value) { if (!options || !value) return '' const item = options.find(item => item.dictValue === String(value)) return item ? item.dictLabel : String(value) },
/** 通过字典值获取样式类型 */ getDictType(options, value) { if (!options || !value) return 'info' const item = options.find(item => item.dictValue === String(value)) const type = item ? (item.listClass || 'info') : 'info'
const tagTypeMap = { 'info': 'info', 'warning': 'warning', 'success': 'success', 'danger': 'danger', // 'primary': 'primary',
} return tagTypeMap[type] || 'info' },
/** 获取上架状态文本 */ getStatusText(status) { return this.getDictLabel(this.statusOptions, status) },
/** 获取上架状态类型 */ getStatusType(status) { return this.getDictType(this.statusOptions, status) },
/** 获取审核状态文本 */ getAuditStatusText(auditStatus) { return this.getDictLabel(this.auditStatusOptions, auditStatus) },
/** 获取审核状态类型 */ getAuditStatusType(auditStatus) { return this.getDictType(this.auditStatusOptions, auditStatus) },
/** 截断文本 */ truncateText(text, maxLength) { if (!text) return '' if (text.length <= maxLength) return text return text.substring(0, maxLength) + '...' },
/** ============ 视频URL处理相关方法 ============ */ // 截短URL显示
truncateUrl(url) { if (!url) return '' if (url.includes('/')) { const parts = url.split('/') const filename = parts[parts.length - 1] if (filename.length > 15) { return filename.substring(0, 12) + '...' } return filename } if (url.length > 15) { return url.substring(0, 12) + '...' } return url },
// 表格中的视频预览
previewTableVideo(url) { if (!url) { this.$modal.msgWarning("视频地址为空") return }
const fullUrl = this.getVideoUrl(url) const htmlContent = `
<div style="text-align: center; padding: 20px;"> <iframe src="${fullUrl}" style="width: 100%; height: 400px; border: none; border-radius: 4px; background: #000;" frameborder="0" allowfullscreen allow="autoplay; encrypted-media" > </iframe> <div style="margin-top: 10px; color: #666; font-size: 12px; word-break: break-all;"> 视频地址: ${url} </div></div> `
this.$modal.alert({ title: '视频预览', message: htmlContent, dangerouslyUseHTMLString: true, customClass: 'video-preview-modal', width: '600px', showConfirmButton: false, showCancelButton: true, cancelButtonText: '关闭' }) },
// 取消按钮
cancel() { this.open = false this.reset() },
// 表单重置
reset() { this.form = { id: undefined, userId: undefined, title: "", description: "", videoUrl: "", coverImage: "", category: "", tags: "", duration: undefined, fileSize: undefined, viewCount: undefined, status: "0", createTime: undefined, updateTime: undefined, delFlag: undefined, auditStatus: "0", auditOpinion: "", auditUserId: undefined, auditTime: undefined }
if (this.$refs.form) { this.$nextTick(() => { this.$refs.form.clearValidate() }) }
this.uploading = false },
/** ============ 视频上传相关方法 ============ */ // 处理文件选择
handleFileSelect(event) { const file = event.target.files[0] if (file) { this.uploadFile(file) } event.target.value = '' },
// 上传文件
async uploadFile(file) { const fileName = file.name.toLowerCase() const validExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv'] const hasValidExtension = validExtensions.some(ext => fileName.endsWith(ext))
if (!hasValidExtension) { this.$modal.msgError('请上传 MP4、AVI、MOV、WMV、FLV、MKV 格式的视频文件') return false }
const maxSize = 200 * 1024 * 1024 if (file.size > maxSize) { this.$modal.msgError('视频大小不能超过 200MB') return false }
this.uploading = true
try { const formData = new FormData() formData.append('file', file)
const response = await uploadVideo(formData)
if (response.code === 200) { this.form.videoUrl = response.data this.$modal.msgSuccess("视频上传成功") return true } else { this.$modal.msgError(response.msg || '上传失败') return false } } catch (error) { console.error('上传失败:', error) this.$modal.msgError('上传失败,请重试') return false } finally { this.uploading = false } },
// 移除视频
removeVideo() { this.form.videoUrl = '' this.$modal.msgSuccess("已移除视频") },
// 预览视频
previewVideo() { if (this.form.videoUrl) { let url = this.form.videoUrl if (url && url.startsWith('/')) { url = process.env.VUE_APP_BASE_API + url } if (url) { window.open(url, '_blank') } } else { this.$modal.msgWarning("请先上传或输入视频地址") } },
// 获取完整的视频URL
getVideoUrl(url) { if (!url) return '' if (url.startsWith('/')) { return process.env.VUE_APP_BASE_API + url } return url },
/** ============ 审核相关方法 ============ */ /** 提交审核(批量或单个) */ async handleSubmitAudit(videoId) { let id
if (videoId && typeof videoId !== 'object' && videoId !== '') { id = videoId } else if (this.ids.length === 1) { id = this.ids[0] } else if (typeof videoId === 'object') { if (this.ids.length === 1) { id = this.ids[0] } else { this.$message.warning('请先选择一个视频') return } } else { this.$message.warning('请选择需要提交审核的视频') return }
if (!id) { this.$message.warning('请选择需要提交审核的视频') return }
try { await this.$confirm('是否确认提交审核?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
await submitForAudit(id) this.$message.success('提交审核成功') this.getList() } catch (error) { if (error !== 'cancel') { console.error('提交审核失败:', error) this.$message.error(error.message || '提交审核失败') } } },
/** 取消审核 */ async handleCancelAudit(videoId) { const id = videoId || this.ids[0] if (!id) { this.$message.warning('请选择需要取消审核的视频') return }
try { await this.$confirm('确定要取消审核吗?取消后可以重新提交审核', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
await cancelAudit(id) this.$message.success('取消审核成功') this.getList() } catch (error) { if (error !== 'cancel') { console.error('取消审核失败:', error) this.$message.error(error.message || '取消审核失败') } } },
/** 审核(批量或单个) */ handleAuditDialog(videoId) { let id
if (videoId && typeof videoId !== 'object' && videoId !== '') { id = videoId } else if (this.ids.length === 1) { id = this.ids[0] } else if (typeof videoId === 'object') { if (this.ids.length === 1) { id = this.ids[0] } else { this.$message.warning('请先选择一个视频') return } } else { this.$message.warning('请选择需要审核的视频') return }
if (!id) { this.$message.warning('请选择需要审核的视频') return }
this.auditForm.id = id this.auditForm.auditStatus = '1' this.auditForm.auditOpinion = '' this.auditOpen = true },
/** 取消审核对话框 */ cancelAudit() { this.auditOpen = false this.resetAuditForm() },
/** 重置审核表单 */ resetAuditForm() { this.auditForm = { id: null, auditStatus: '1', auditOpinion: '' } if (this.$refs.auditFormRef) { this.$refs.auditFormRef.resetFields() } },
/** 提交审核(管理员审核) */ async submitAudit() { try { const valid = await this.$refs.auditFormRef.validate() if (!valid) return
const message = this.auditForm.auditStatus === '1' ? '是否确认审核通过?' : '是否确认审核拒绝?'
await this.$confirm(message, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
// 方式1:传递对象参数
const response = await auditVideo({ id: this.auditForm.id, auditStatus: this.auditForm.auditStatus, auditOpinion: this.auditForm.auditOpinion || '' })
// 或者方式2:如果不想改API函数,可以直接调用request
// const response = await request({
// url: `/vet/training/audit/${this.auditForm.id}`,
// method: 'post',
// data: {
// auditStatus: this.auditForm.auditStatus,
// auditOpinion: this.auditForm.auditOpinion || ''
// }
// })
if (response.code === 200) { this.$message.success('审核成功') this.auditOpen = false this.getList() this.resetAuditForm() } else { this.$message.error(response.msg || '审核失败') }
} catch (error) { if (error === 'cancel') return console.error('审核错误:', error) this.$message.error('审核失败,请检查参数') } },
/** ============ 上架/下架相关方法 ============ */ /** 上架视频(批量或单个) */ async handlePublish(videoId) { let id
if (videoId && typeof videoId !== 'object' && videoId !== '') { id = videoId } else if (this.ids.length === 1) { id = this.ids[0] } else if (typeof videoId === 'object') { if (this.ids.length === 1) { id = this.ids[0] } else { this.$message.warning('请先选择一个视频') return } } else { this.$message.warning('请选择需要上架的视频') return }
try { await this.$confirm('是否确认上架视频?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
await publishVideo(id) this.$message.success('上架成功') this.getList() } catch (error) { if (error !== 'cancel') { console.error('上架失败:', error) this.$message.error(error.message || '上架失败') } } },
/** 下架视频(批量或单个) */ async handleOffline(videoId) { let id
if (videoId && typeof videoId !== 'object' && videoId !== '') { id = videoId } else if (this.ids.length === 1) { id = this.ids[0] } else if (typeof videoId === 'object') { if (this.ids.length === 1) { id = this.ids[0] } else { this.$message.warning('请先选择一个视频') return } } else { this.$message.warning('请选择需要下架的视频') return }
try { await this.$confirm('是否确认下架视频?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
await offlineVideo(id) this.$message.success('下架成功') this.getList() } catch (error) { if (error !== 'cancel') { console.error('下架失败:', error) this.$message.error(error.message || '下架失败') } } },
// handleResubmitAudit重新提交审核
handleResubmitAudit(row) { const id = row.id || this.ids[0]; if (!id) { this.$modal.msgWarning('请选择需要重新提交审核的视频'); return; } this.$confirm('是否确认重新提交审核?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { try { const response = await resubmitAudit(id); if (response.code === 200) { this.$modal.msgSuccess("重新提交审核成功"); this.getList(); } else { this.$modal.msgError(response.msg || "重新提交审核失败"); } } catch (error) { console.error('重新提交审核失败:', error); this.$modal.msgError('重新提交审核失败:' + (error.message || '网络异常')); } }).catch(() => { }); },
/** ============ 其他方法 ============ */ /** 搜索按钮操作 */ handleQuery() { this.queryParams.pageNum = 1 this.getList() },
/** 重置按钮操作 */ resetQuery() { this.resetForm("queryForm") this.handleQuery() },
// 多选框选中数据
handleSelectionChange(selection) { this.ids = selection.map(item => item.id) this.single = selection.length !== 1 this.multiple = !selection.length },
/** 新增按钮操作 */ handleAdd() { this.reset() this.open = true this.title = "添加兽医培训视频" },
/** 修改按钮操作 */ handleUpdate(row) { this.reset() const id = row.id || this.ids getTraining(id).then(response => { const data = response.data || {} this.form = { id: data.id || undefined, userId: data.userId || undefined, title: data.title || "", description: data.description || "", videoUrl: data.videoUrl || "", coverImage: data.coverImage || "", category: data.category || "", tags: data.tags || "", duration: data.duration || undefined, fileSize: data.fileSize || undefined, viewCount: data.viewCount || undefined, status: data.status || "0", createTime: data.createTime || undefined, updateTime: data.updateTime || undefined, delFlag: data.delFlag || undefined, auditStatus: data.auditStatus || "0", auditOpinion: data.auditOpinion || "", auditUserId: data.auditUserId || undefined, auditTime: data.auditTime || undefined } this.open = true this.title = "修改兽医培训视频" }).catch(() => { this.$modal.msgError("获取数据失败") }) },
/** 提交按钮 */ submitForm() { this.$refs["form"].validate(valid => { if (valid) { const submitData = { ...this.form, title: (this.form.title || "").trim(), category: (this.form.category || "").trim(), videoUrl: this.form.videoUrl || "", description: this.form.description || "", status: this.form.status || "0", auditStatus: this.form.auditStatus || "0" }
if (submitData.id) { updateTraining(submitData).then(response => { this.$modal.msgSuccess("修改成功") this.open = false this.getList() }).catch((error) => { console.error('修改失败:', error) this.$modal.msgError("修改失败: " + (error.message || "未知错误")) }) } else { addTraining(submitData).then(response => { this.$modal.msgSuccess("新增成功") this.open = false this.getList() }).catch((error) => { console.error('新增失败:', error) this.$modal.msgError("新增失败: " + (error.message || "未知错误")) }) } } else { return false } }) },
/** 删除按钮操作 */ handleDelete(row) { const ids = row.id || this.ids this.$modal.confirm('是否确认删除兽医培训视频编号为"' + ids + '"的数据项?').then(() => { return delTraining(ids) }).then(() => { this.getList() this.$modal.msgSuccess("删除成功") }).catch(() => {}) },
/** 导出按钮操作 */ handleExport() { this.download('vet/training/export', { ...this.queryParams }, `training_${new Date().getTime()}.xlsx`) } }}</script>
<style scoped>::v-deep .pagestyle .el-input{ width: auto !important;}</style>
<style lang="scss" scoped>.video-url-cell { display: flex; align-items: center; justify-content: center;}
.url-text { max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
// 操作按钮样式
.info-btn { padding: 6px 10px; border-radius: 4px; margin: 0 10px; transition: all 0.3s ease;}
.view-btn:hover { background-color: rgb(216, 238, 248); transform: translateY(-1px);}
.alter-btn:hover{ background-color: rgb(230, 255, 238); transform: translateY(-1px);}
.delete-btn:hover { background-color: rgba(245, 108, 108, 0.1); transform: translateY(-1px);}
.submit-btn:hover { background-color: rgb(253, 250, 232); transform: translateY(-1px);}
.publish-btn:hover { background-color: rgb(253, 238, 228); transform: translateY(-1px);}
.offline-btn:hover { background-color: rgb(237, 237, 235); transform: translateY(-1px);}
.cancel-btn:hover { background-color: rgb(244, 237, 251); transform: translateY(-1px);}
.audit-btn:hover { background-color: rgb(215, 223, 246); transform: translateY(-1px);}
.resubmit-btn:hover { background-color: rgb(248, 232, 250); transform: translateY(-1px);}
// 新增/修改的弹窗
::v-deep .el-dialog { border-radius: 12px; overflow: hidden; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12); animation: dialogFadeIn 0.3s ease;}
::v-deep .el-dialog__header { background: linear-gradient(135deg, #42b983 0%, #83df92 100%); padding: 18px 24px; border-bottom: none; position: relative;}
::v-deep .el-dialog__title { font-size: 17px; font-weight: 600; color: white; letter-spacing: 0.5px;}
::v-deep .el-dialog__headerbtn:hover .el-dialog__close { color: #ffd04b; transform: rotate(90deg);}
::v-deep .el-dialog__body { padding: 28px 24px 20px; background-color: #f8fafc; max-height: 70vh; overflow-y: auto;}
::v-deep .el-form-item { margin-bottom: 20px; transition: all 0.3s;}
::v-deep .el-form-item__label { font-weight: 500; color: #2d3748; font-size: 14px; transition: color 0.3s;}
::v-deep .el-input,::v-deep .el-textarea,::v-deep .el-select { width: 100%;}
::v-deep .el-input__inner,::v-deep .el-textarea__inner { border-radius: 8px; border: 1px solid #dcdfe6; font-size: 14px; transition: all 0.3s; background-color: #fcfdfe;}
::v-deep .el-input__inner:focus,::v-deep .el-textarea__inner:focus { border-color: #42B983; box-shadow: 0 0 0 3px rgb(230, 255, 238); background-color: white;}
::v-deep .el-select .el-input__inner { padding-right: 35px;}
::v-deep .el-dialog__footer { padding: 20px 24px; background-color: #f8fafc; border-top: 1px solid #eef2f7; border-radius: 0 0 12px 12px;}</style>
|