zhangsq vor 8 Monaten
Ursprung
Commit
382df8a679

+ 2 - 1
.env.development

@@ -5,7 +5,8 @@ NODE_ENV = development
 VITE_TITLE = Snowy
 
 # 接口地址
-VITE_API_BASEURL = http://192.168.31.14:9003
+VITE_API_BASEURL = http://192.168.31.81:9003
+VITE_FILEURL = http://192.168.1.245:10005/education/
 # VITE_API_BASEURL = http://192.168.31.80:9003
 # VITE_API_BASEURL = http://192.168.31.6:9003
 

+ 17 - 13
src/api/resourceAudit.js

@@ -1,58 +1,62 @@
 import { baseRequest } from '@/utils/newRequest'
 
-const request = (url, ...arg) => baseRequest(`/api/webapp/disk/` + url, ...arg)
+const request = (url, ...arg) => baseRequest(`/api/webapp/` + url, ...arg)
 
 export default {
 	// 获取资管理审核括列表
 	page(data) {
-		return request('courseauditrecord/page', data, 'get')
+		return request('disk/courseauditrecord/page', data, 'get')
 	},
 	//资源管理添加
 	add(data = {}) {
-		return request('courseauditrecord/add', data, 'post')
+		return request('disk/courseauditrecord/add', data, 'post')
 	},
 	//发布
 	release(data = {}) {
-		return request('courseinfo/add', data, 'post')
+		return request('disk/courseinfo/add', data, 'post')
 	},
 	//更新状态(审核/删除/恢复)
 	updateStatus(data = {}) {
-		return request('courseauditrecord/updateStatus', data, 'post')
+		return request('disk/courseauditrecord/updateStatus', data, 'post')
 	},
 	//编辑
 	edit(data = {}) {
-		return request('courseauditrecord/edit', data, 'post')
+		return request('disk/courseauditrecord/edit', data, 'post')
 	},
 	//编辑
 	detail(data = {}) {
-		return request('courseauditrecord/detail', data, 'get')
+		return request('disk/courseauditrecord/detail', data, 'get')
 	},
 	//院校下拉接口
 	orgTreeSelector(data = {}) {
-		return request('college/orgTreeSelector', data, 'get')
+		return request('disk/college/orgTreeSelector', data, 'get')
 	},
 	//根据院校id获取专业下拉接口
 	zyselect(data = {}) {
-		return request('major/select', data, 'get')
+		return request('disk/major/select', data, 'get')
 	},
 	//获取热门关键词下拉接口
 	HotKeywords(data = {}) {
-		return request('word/select', data, 'get')
+		return request('disk/word/select', data, 'get')
 	},
 	//添加热门关键词
 	addHotKeywords(data = {}) {
-		return request('word/add', data, 'post')
+		return request('disk/word/add', data, 'post')
 	},
 	//获取课程下拉
 	courseAllList(data = {}) {
-		return request('courseinfo/allList', data, 'get')
+		return request('disk/courseinfo/allList', data, 'get')
 	},
 	//查询资源表单最后一次提交信息
 	recentlyRecord(data = {}) {
-		return request('courseauditrecord/recentlyRecord', data, 'get')
+		return request('disk/courseauditrecord/recentlyRecord', data, 'get')
 	},
 	//资源上传删除
 	deletefile(data = {}) {
 		return request('resourceFile/deletefile', data, 'post')
+	},
+	//文件下载资源上传删除
+	downloadfile(data = {}) {
+		return request('resourceFile/downloadfile', data, 'get', { responseType: 'blob' })
 	}
 }

+ 3 - 0
src/config/index.js

@@ -15,6 +15,9 @@ const DEFAULT_CONFIG = {
 	// 接口地址
 	API_URL: import.meta.env.VITE_API_BASEURL,
 
+	// 文件访问地址
+	FILE_URL: import.meta.env.VITE_FILEURL,
+
 	// 请求超时
 	TIMEOUT: 60000,
 

+ 3 - 1
src/libs/globalFunction/file.js

@@ -84,7 +84,9 @@ const fileFunction = {
 		}&extractionCode=${row.extractionCode == null ? '' : row.extractionCode}&admin=true`
 	},
 	getDownloadFilePath3(row) {
-		return `${config.baseContext}/resourceFile/downloadfile?userFileIds=${row.fileId}`
+		return `${config.baseContext}/resourceFile/downloadfile?userFileId=${row.fileId}&shareBatchNum=${
+			row.shareBatchNum == null ? '' : row.shareBatchNum
+		}&extractionCode=${row.extractionCode == null ? '' : row.extractionCode}&admin=true`
 	},
 	/**
 	 * 获取 Onlyoffice 文件创建路径

+ 1 - 0
src/utils/newRequest.js

@@ -78,6 +78,7 @@ const error = () => {
 // HTTP response 拦截器
 service.interceptors.response.use(
 	(response) => {
+		console.log(response, '文件')
 		// 配置了blob,不处理直接返回文件流
 		if (response.config.responseType === 'blob') {
 			if (response.status === 200) {

+ 107 - 0
src/views/myResources/VideoPlayer.vue

@@ -0,0 +1,107 @@
+<template>
+	<video ref="videoPlayer" class="video-js"></video>
+</template>
+
+<script setup>
+	import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
+	import videojs from 'video.js'
+	import 'video.js/dist/video-js.css'
+
+	const props = defineProps({
+		source: {
+			type: Object,
+			default: () => ({})
+		}
+	})
+
+	const videoPlayer = ref(null)
+	let player = null
+
+	// 播放器配置
+	const options = {
+		playbackRates: [0.5, 1.0, 1.5, 2.0],
+		autoplay: false,
+		muted: false,
+		loop: false,
+		preload: 'auto',
+		language: 'zh-CN',
+		aspectRatio: '16:9',
+		fluid: true,
+		sources: [props.source],
+		notSupportedMessage: '此视频暂无法播放,请稍后再试',
+		controls: true,
+		controlBar: {
+			timeDivider: true,
+			durationDisplay: true,
+			remainingTimeDisplay: false,
+			fullscreenToggle: true
+		}
+	}
+
+	watch(
+		() => props.source,
+		(newSource) => {
+			if (player) {
+				player.pause()
+				player.currentTime(0)
+				player.src(newSource)
+				player.play()
+			}
+		}
+	)
+
+	onMounted(() => {
+		player = videojs(videoPlayer.value, options)
+		window.videojs = videojs
+		// 使用 require 加载中文语言包
+		import('video.js/dist/lang/zh-CN.js')
+	})
+
+	onBeforeUnmount(() => {
+		if (player) {
+			player.dispose()
+			player = null
+		}
+	})
+</script>
+
+<style lang="less" scoped>
+	@import '@/style/myResource/varibles.less';
+
+	.video-js {
+		width: 100%;
+		height: 100%;
+		padding: 0;
+		color: @primary-color;
+
+		:deep(.vjs-big-play-button) {
+			border-radius: 50%;
+			border: 6px solid @primary-color;
+			left: calc(50% - 1em);
+			top: calc(50% - 1em);
+			width: 2.5em;
+			height: 2.5em;
+			line-height: 2.5em;
+			background: transparent;
+			box-sizing: content-box;
+
+			.vjs-icon-placeholder:before {
+				font-size: 48px;
+			}
+
+			&:hover {
+				opacity: 0.6;
+			}
+		}
+
+		:deep(.vjs-volume-level),
+		:deep(.vjs-play-progress),
+		:deep(.vjs-slider-bar) {
+			background: @primary-color;
+		}
+
+		:deep(.vjs-control-bar) {
+			font-size: 14px;
+		}
+	}
+</style>

+ 43 - 14
src/views/myResources/auditModal.vue

@@ -3,18 +3,25 @@
 		<div class="audit-container">
 			<!-- 左侧 - 文件展示区域 -->
 			<div class="file-preview">
-				<video-player v-if="recordData.suffix === 'mp4'" :options="playerOptions" @ready="playerReadied"></video-player>
-				<div v-else-if="recordData.suffix === 'ppt'" class="preview-placeholder">
-					<file-ppt-filled style="font-size: 48px; color: #d24638" />
-					<p>PPT文件预览</p>
+				<!-- <img src="/src/assets/images/flw/REVOKE.png" /> -->
+				<video-player
+					v-if="recordData.suffix === 'mp4'"
+					:source="activeVideoSource"
+					@ready="playerReadied"
+				></video-player>
+				<div v-else-if="['pdf', 'word', 'ppt', 'doc'].includes(recordData.suffix.toLowerCase())" class="preview-iframe">
+					<iframe
+						:src="`https://docs.google.com/gview?url=${sysConfig.FILE_URL + recordData.fileUrl}&embedded=true`"
+						frameborder="0"
+					></iframe>
 				</div>
-				<div v-else-if="recordData.suffix === 'word'" class="preview-placeholder">
-					<file-word-filled style="font-size: 48px; color: #2b579a" />
-					<p>Word文件预览</p>
-				</div>
-				<div v-else-if="recordData.suffix === 'pdf'" class="preview-placeholder">
-					<file-pdf-filled style="font-size: 48px; color: #f40f02" />
-					<p>PDF文件预览</p>
+				<!-- 图片预览 -->
+				<div v-else-if="['jpg', 'jpeg', 'png', 'gif'].includes(recordData.suffix.toLowerCase())" class="image-viewer">
+					<img
+						:src="sysConfig.FILE_URL + recordData.fileUrl"
+						:alt="recordData.fileName"
+						style="max-width: 100%; max-height: 100%; object-fit: contain"
+					/>
 				</div>
 				<div v-else class="preview-placeholder">
 					<file-unknown-filled style="font-size: 48px; color: #999" />
@@ -28,7 +35,7 @@
 					<p><strong>上传人:</strong>{{ detailData.resourceCreaterUserName || '--' }}</p>
 					<p><strong>所属院系:</strong>{{ detailData?.collegeAllIdName || '--' }}</p>
 					<p><strong>所属专业:</strong>{{ detailData?.majorIdName || '--' }}</p>
-					<p><strong>资源类型:</strong>{{ detailData?.courseTypeName || '--' }}</p>
+					<p><strong>资源类型:</strong>{{ detailData?.resourceTypeName || '--' }}</p>
 					<p><strong>资源格式:</strong>{{ detailData?.suffix || '--' }}</p>
 					<p><strong>视频时长:</strong>{{ detailData?.duration || '--' }}</p>
 					<p><strong>视频大小:</strong>{{ detailData?.FILESIZE || '--' }}<span v-if="detailData?.FILESIZE">b</span></p>
@@ -47,6 +54,8 @@
 <script setup>
 	import { ref, defineProps, defineEmits, computed } from 'vue'
 	import resourceAuditApi from '@/api/resourceAudit.js'
+	import VideoPlayer from './VideoPlayer.vue'
+	import sysConfig from '@/config/index'
 	// import videoPlayer from 'vue-video-player'
 	const props = defineProps({
 		recordData: {
@@ -69,13 +78,23 @@
 	const visibles = ref(true)
 
 	const playerOptions = computed(() => ({
+		autoplay: false, // 禁止自动播放
+		controls: true, // 显示控制条
+		fluid: true, // 流体布局
+		preload: 'auto', // 预加载
 		sources: [
 			{
 				type: 'video/mp4',
-				src: props.recordData.filePath // 视频文件路径
+				src: sysConfig.FILE_URL + props.recordData.fileUrl
 			}
 		],
-		poster: props.recordData.posterPath // 封面图片路径
+		techOrder: ['html5'], // 优先使用html5播放
+		// poster: sysConfig.FILE_URL + props.recordData.posterPath
+		poster: 'http://192.168.1.245:10005/education/upload/20250702/21d8bc591e499136c393c13cf5343f6c.jpeg'
+	}))
+	const activeVideoSource = computed(() => ({
+		type: `video/mp4`,
+		src: sysConfig.FILE_URL + props.recordData.fileUrl
 	}))
 	const handleCancel = () => {
 		emit('close')
@@ -166,4 +185,14 @@
 	.ant-modal-footer {
 		display: none !important; /* 检查是否被覆盖 */
 	}
+	.preview-iframe {
+		width: 100%;
+		height: 100%;
+		min-height: 500px;
+	}
+	.preview-iframe iframe {
+		width: 100%;
+		height: 100%;
+		border: none;
+	}
 </style>

+ 25 - 1
src/views/myResources/myResources.vue

@@ -124,7 +124,7 @@
 										<a href="javascript:;" @click="handleView(record)">播放</a>
 									</a-menu-item>
 									<a-menu-item>
-										<!-- <a href="javascript:;">下载</a> -->
+										<!-- <a href="javascript:;" @click="handleDownload(record)">下载</a> -->
 										<a
 											target="_blank"
 											style="display: block; color: inherit"
@@ -588,6 +588,30 @@
 		auditState.value = false
 		auditModalVisible.value = true
 	}
+	const handleDownload = (record) => {
+		resourceAuditApi
+			.downloadfile({
+				userFileId: record.fileId,
+				shareBatchNum: record.shareBatchNum == null ? '' : record.shareBatchNum,
+				extractionCode: record.extractionCode == null ? '' : record.extractionCode,
+				admin: true
+			})
+			.then((res) => {
+				console.log('下载成功:', res)
+				// 创建Blob对象
+				const url = window.URL.createObjectURL(new Blob([res]))
+				const link = document.createElement('a')
+				link.href = url
+				link.download = record.fileName || `file_${record.id}.${record.suffix}`
+				document.body.appendChild(link)
+				link.click()
+				window.URL.revokeObjectURL(url)
+				document.body.removeChild(link)
+			})
+			.catch((err) => {
+				console.error(err)
+			})
+	}
 
 	const handlePermission = (record) => {
 		console.log('Permission:', record)

+ 24 - 10
src/views/myResources/resourceUpload.vue

@@ -48,8 +48,8 @@
 			<a-form-item
 				label="关键词(需添加2-5个关键词)"
 				name="keywordValue"
-				:label-col="{ span: 8 }"
-				:wrapper-col="{ span: 10 }"
+				:label-col="{ span: 10 }"
+				:wrapper-col="{ span: 18 }"
 			>
 				<div v-if="!formState.keywordValue.length" style="color: #ccc">请选择下方热门关键词</div>
 				<div v-if="formState.keywordValue.length">
@@ -57,7 +57,7 @@
 						v-for="(keyword, index) in formState.keywordValue"
 						:key="index"
 						closable
-						@close="handleRemoveKeyword(index)"
+						@close="handleRemoveKeyword(keyword, index)"
 					>
 						{{ keyword }}
 					</a-tag>
@@ -240,8 +240,15 @@
 		// }
 	}
 
-	const handleRemoveKeyword = (index) => {
-		formState.keywordValue.splice(index, 1)
+	const handleRemoveKeyword = (keywordName, index) => {
+		console.log(keywordName, index)
+		// 1. 从显示列表中删除
+		formState.keywordValue = formState.keywordValue.filter((name) => name !== keywordName)
+		console.log(formState.keywordValue, 'formState.keywordValue')
+		// 2. 更新checkbox的绑定值
+		formState.keyword = HotKeywordsOptions.value
+			.filter((option) => formState.keywordValue.includes(option.label))
+			.map((item) => item.value)
 	}
 	const getHotKeywords = () => {
 		resourceAuditApi
@@ -250,7 +257,7 @@
 				console.log(res.data, '获取热门关键词')
 				HotKeywordsOptions.value = res.data.map((it) => {
 					return {
-						value: it.wordName,
+						value: it.id,
 						label: it.wordName
 					}
 				})
@@ -259,9 +266,12 @@
 				console.log(err)
 			})
 	}
-	const handleChangeKeyword = (e) => {
-		console.log(e)
-		formState.keywordValue = e
+	const handleChangeKeyword = (checkedValues) => {
+		formState.keyword = checkedValues
+		formState.keywordValue = HotKeywordsOptions.value
+			.filter((option) => checkedValues.includes(option.value))
+			.map((item) => item.label)
+		console.log(formState.keywordValue, '选中数据')
 	}
 	const setPublicStatus = (status) => {
 		formState.publicStatus = status
@@ -382,9 +392,11 @@
 			getCollegeMajor(majorIdName.value[majorIdName.value.length - 1])
 			formState.resourceDesc = res.data.resourceDesc
 			formState.majorId = res.data.majorId
+			formState.keywordValue = res.data.keywordValue.split(',')
+			formState.keyword = res.data.keyword.split(',')
 		})
 	}
-	// 获取资源详情
+	// 获取历史添加表单
 	const getformState = () => {
 		resourceAuditApi.recentlyRecord().then((res) => {
 			console.log(res.data, '历史表单数据')
@@ -396,6 +408,8 @@
 			getCollegeMajor(majorIdName.value[majorIdName.value.length - 1])
 			formState.resourceDesc = res.data.resourceDesc
 			formState.majorId = res.data.majorId
+			formState.keywordValue = res.data.keywordValue.split(',')
+			formState.keyword = res.data.keyword.split(',')
 		})
 	}
 	// 上传前的钩子函数

+ 1 - 1
vite.config.js

@@ -52,7 +52,7 @@ export default defineConfig(({ command, mode }) => {
 			port: envConfig.VITE_PORT,
 			proxy: {
 				'/api': {
-					target: 'http://192.168.31.14:9003',
+					target: 'http://192.168.31.81:9003',
 					ws: false,
 					changeOrigin: true
 					// rewrite: (path) => path.replace(/^\/api/, '')