diff --git a/src/api/base/jycgApi.ts b/src/api/base/jycgApi.ts
new file mode 100644
index 0000000..d348562
--- /dev/null
+++ b/src/api/base/jycgApi.ts
@@ -0,0 +1,45 @@
+import { get, post } from "@/utils/request";
+
+/**
+ * 获取教研成果列表
+ */
+export function jycgFindPageApi(params: any) {
+ return get('/api/jycg/findPage', params);
+}
+
+/**
+ * 获取教研成果详情
+ */
+export function jycgFindByIdApi(params: any) {
+ return get('/api/jycg/findById', params);
+}
+
+/**
+ * 保存教研成果(新增/修改)
+ */
+export function jycgSaveApi(params: any) {
+ return post('/api/jycg/save', params);
+}
+
+/**
+ * 删除教研成果
+ */
+export function jycgDeleteApi(params: any) {
+ return post('/api/jycg/delete', params);
+}
+
+/**
+ * 批量删除教研成果
+ */
+export function jycgBatchDeleteApi(params: any) {
+ return post('/api/jycg/batchDelete', params);
+}
+
+/**
+ * 上传文件
+ */
+export function jycgUploadFileApi(file: File) {
+ const formData = new FormData();
+ formData.append('file', file);
+ return post('/api/jycg/upload', formData);
+}
diff --git a/src/components/ImageVideoUpload/ImageVideoUpload.vue b/src/components/ImageVideoUpload/ImageVideoUpload.vue
index fe38088..0c593a7 100644
--- a/src/components/ImageVideoUpload/ImageVideoUpload.vue
+++ b/src/components/ImageVideoUpload/ImageVideoUpload.vue
@@ -72,7 +72,7 @@
- {{ video.name }}
+ {{ video.originalName || video.name }}
{{ formatFileSize(video.size) }}
@@ -103,10 +103,14 @@
>
-
+
- {{ file.name }}
+ {{ file.originalName || file.name }}
{{ formatFileSize(file.size) }}
{{ file.extension?.toUpperCase() || 'FILE' }}
@@ -160,6 +164,7 @@ interface FileItem {
tempPath?: string
url?: string
name?: string
+ originalName?: string
type?: string
size?: number
extension?: string
@@ -433,40 +438,43 @@ const checkVideoSize = async (filePath: string): Promise => {
// 选择图片
const chooseImage = () => {
+ // 使用 chooseImage 支持拍照和相册选择
uni.chooseImage({
count: props.maxImageCount - imageList.value.length,
- sizeType: ['original'],
- sourceType: ['album', 'camera'],
+ sourceType: ['camera', 'album'], // 支持拍照和相册
+ sizeType: ['original', 'compressed'], // 可以选择原图或压缩图
success: async (res) => {
- const tempFilePaths = res.tempFilePaths as string[]
-
- showLoading('压缩图片中...')
-
- try {
- const compressedImages = []
+ const tempFilePaths = res.tempFilePaths
+ if (Array.isArray(tempFilePaths) && tempFilePaths.length > 0) {
+ showLoading('压缩图片中...')
- // 并行压缩所有图片
- const compressPromises = tempFilePaths.map(async (path, index) => {
- try {
- showLoading(`压缩图片中... (${index + 1}/${tempFilePaths.length})`)
-
- const compressedPath = await smartCompressImage(path)
-
- return {
- tempPath: compressedPath,
- name: path.split('/').pop() || 'image.jpg',
- originalPath: path,
- isCompressed: true
+ try {
+ const compressedImages = []
+
+ // 并行压缩所有图片
+ const compressPromises = tempFilePaths.map(async (filePath: string, index) => {
+ try {
+ showLoading(`压缩图片中... (${index + 1}/${tempFilePaths.length})`)
+
+ const compressedPath = await smartCompressImage(filePath)
+
+ return {
+ tempPath: compressedPath,
+ name: filePath.split('/').pop() || 'image.jpg',
+ originalName: filePath.split('/').pop() || 'image.jpg',
+ originalPath: filePath,
+ isCompressed: true
+ }
+ } catch (error) {
+ console.error(`图片 ${filePath} 压缩失败:`, error)
+ return {
+ tempPath: filePath,
+ name: filePath.split('/').pop() || 'image.jpg',
+ originalName: filePath.split('/').pop() || 'image.jpg',
+ isCompressed: false
+ }
}
- } catch (error) {
- console.error(`图片 ${path} 压缩失败:`, error)
- return {
- tempPath: path,
- name: path.split('/').pop() || 'image.jpg',
- isCompressed: false
- }
- }
- })
+ })
const results = await Promise.all(compressPromises)
compressedImages.push(...results)
@@ -496,8 +504,9 @@ const chooseImage = () => {
showToast({ title: '图片处理失败', icon: 'none' })
console.error('图片处理失败:', error)
}
+ }
},
- fail: (error) => {
+ fail: (error: any) => {
console.error('选择图片失败:', error)
showToast({ title: '选择图片失败', icon: 'none' })
}
@@ -534,6 +543,7 @@ const chooseVideo = () => {
const newVideo = {
tempPath: tempFilePath,
name: tempFilePath.split('/').pop() || 'video.mp4',
+ originalName: res.name || 'video.mp4', // 保存原始文件名
duration: res.duration,
size: res.size
}
@@ -584,18 +594,29 @@ const chooseFile = () => {
// 确定文件类型
let fileType = 'document'
- if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+ if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'tiff', 'ico'].includes(fileExtension)) {
fileType = 'image'
- } else if (['mp4', 'mov', 'avi', 'wmv', 'flv'].includes(fileExtension)) {
+ } else if (['mp4', 'mov', 'avi', 'wmv', 'flv', 'mkv', 'webm', '3gp', 'm4v'].includes(fileExtension)) {
fileType = 'video'
- } else if (['mp3', 'wav', 'aac', 'ogg'].includes(fileExtension)) {
+ } else if (['mp3', 'wav', 'aac', 'ogg', 'flac', 'm4a', 'wma'].includes(fileExtension)) {
fileType = 'audio'
+ } else if (['pdf', 'doc', 'docx', 'txt', 'rtf', 'wps'].includes(fileExtension)) {
+ fileType = 'document'
+ } else if (['xls', 'xlsx', 'csv', 'et'].includes(fileExtension)) {
+ fileType = 'spreadsheet'
+ } else if (['ppt', 'pptx', 'dps'].includes(fileExtension)) {
+ fileType = 'presentation'
+ } else if (['zip', 'rar', '7z', 'tar', 'gz'].includes(fileExtension)) {
+ fileType = 'archive'
+ } else if (['html', 'htm', 'css', 'js', 'json', 'xml'].includes(fileExtension)) {
+ fileType = 'code'
}
// 创建文件项
const fileItem: FileItem = {
tempPath: fileInfo.path,
name: fileName,
+ originalName: fileName, // 保存原始文件名
type: fileType,
size: fileInfo.size,
extension: fileExtension,
@@ -634,15 +655,29 @@ const uploadFile = async (fileItem: FileItem, index: number) => {
if (!props.uploadApi || !fileItem.tempPath) return
try {
+ // 触发上传开始事件
+ emit('upload-progress', 'file', 1, 1)
+
const result = await props.uploadApi(fileItem.tempPath)
if (result && result.resultCode === 1 && result.result && result.result.length > 0) {
const uploadedFile = result.result[0]
- // 更新文件项
- fileItem.url = imagUrl(uploadedFile.filePath)
+ // 更新文件项 - 直接使用相对路径,不添加域名前缀
+ fileItem.url = uploadedFile.filePath
+ // 如果服务器返回了文件名,更新name字段,但保留originalName
+ if (uploadedFile.fileName) {
+ fileItem.name = uploadedFile.fileName
+ }
fileItem.tempPath = undefined // 清除临时路径
+ // 同步更新 fileList 中的对应项
+ if (fileList.value[index]) {
+ fileList.value[index].url = fileItem.url
+ fileList.value[index].name = fileItem.name
+ fileList.value[index].tempPath = undefined
+ }
+
// 触发成功事件
emit('file-upload-success', fileItem, index)
@@ -703,32 +738,92 @@ const removeFile = (index: number) => {
// 获取文件图标
const getFileIcon = (extension: string): string => {
- const iconMap: { [key: string]: string } = {
- // 文档
- 'pdf': 'book',
- 'doc': 'book',
- 'docx': 'book',
- 'txt': 'book',
- // 表格
- 'xls': 'table',
- 'xlsx': 'table',
- // 演示文稿
- 'ppt': 'slideshow',
- 'pptx': 'slideshow',
- // 音频
- 'mp3': 'mic',
- 'wav': 'mic',
- 'aac': 'mic',
- 'ogg': 'mic',
+ const type = extension.toLowerCase();
+ switch (type) {
+ // PDF文档
+ case 'pdf':
+ return '/static/base/view/pdf.png';
+
+ // Word文档
+ case 'doc':
+ case 'docx':
+ case 'rtf':
+ case 'wps': // WPS文字
+ return '/static/base/view/word.png';
+
+ // Excel表格
+ case 'xls':
+ case 'xlsx':
+ case 'csv':
+ case 'et': // WPS表格
+ return '/static/base/view/excel.png';
+
+ // PowerPoint演示
+ case 'ppt':
+ case 'pptx':
+ case 'dps': // WPS演示
+ return '/static/base/view/ppt.png';
+
// 压缩文件
- 'zip': 'folder',
- 'rar': 'folder',
- '7z': 'folder',
- // 其他
- 'default': 'paperclip'
+ case 'zip':
+ case 'rar':
+ case '7z':
+ case 'tar':
+ case 'gz':
+ return '/static/base/view/zip.png';
+
+ // 图片文件
+ case 'jpg':
+ case 'jpeg':
+ case 'png':
+ case 'gif':
+ case 'bmp':
+ case 'webp':
+ case 'svg':
+ case 'tiff':
+ case 'ico':
+ return '/static/base/view/image.png';
+
+ // 视频文件
+ case 'mp4':
+ case 'avi':
+ case 'mov':
+ case 'wmv':
+ case 'flv':
+ case 'mkv':
+ case 'webm':
+ case '3gp':
+ case 'm4v':
+ return '/static/base/view/video.png';
+
+ // 音频文件
+ case 'mp3':
+ case 'wav':
+ case 'aac':
+ case 'ogg':
+ case 'flac':
+ case 'm4a':
+ case 'wma':
+ return '/static/base/view/audio.png';
+
+ // 文本文件
+ case 'txt':
+ case 'md':
+ return '/static/base/view/text.png';
+
+ // 代码文件
+ case 'html':
+ case 'htm':
+ case 'css':
+ case 'js':
+ case 'json':
+ case 'xml':
+ return '/static/base/view/code.png';
+
+ // 默认文件
+ default:
+ return '/static/base/view/more.png';
}
-
- return iconMap[extension.toLowerCase()] || iconMap['default']
}
// 上传图片
@@ -753,10 +848,14 @@ const uploadImages = async (images: ImageItem[]) => {
if (uploadResult && uploadResult.resultCode === 1 && uploadResult.result && uploadResult.result.length > 0) {
const serverPath = uploadResult.result[0].filePath
- // 更新图片对象
+ // 更新图片对象 - 直接使用相对路径,不添加域名前缀
const index = imageList.value.findIndex(img => img.tempPath === image.tempPath)
if (index !== -1) {
- imageList.value[index].url = imagUrl(serverPath)
+ imageList.value[index].url = serverPath
+ // 如果服务器返回了文件名,更新name字段,但保留originalName
+ if (uploadResult.result[0].fileName) {
+ imageList.value[index].name = uploadResult.result[0].fileName
+ }
delete imageList.value[index].tempPath
delete imageList.value[index].originalPath
}
@@ -821,10 +920,14 @@ const uploadVideos = async (videos: VideoItem[]) => {
if (uploadResult && uploadResult.resultCode === 1 && uploadResult.result && uploadResult.result.length > 0) {
const serverPath = uploadResult.result[0].filePath
- // 更新视频对象
+ // 更新视频对象 - 直接使用相对路径,不添加域名前缀
const index = videoList.value.findIndex(v => v.tempPath === video.tempPath)
if (index !== -1) {
- videoList.value[index].url = imagUrl(serverPath)
+ videoList.value[index].url = serverPath
+ // 如果服务器返回了文件名,更新name字段,但保留originalName
+ if (uploadResult.result[0].fileName) {
+ videoList.value[index].name = uploadResult.result[0].fileName
+ }
delete videoList.value[index].tempPath
}
@@ -941,7 +1044,7 @@ defineExpose({
})
-
diff --git a/src/pages/view/routine/jiaoyan/cg/achievementList.vue b/src/pages/view/routine/jiaoyan/cg/achievementList.vue
new file mode 100644
index 0000000..de97f0d
--- /dev/null
+++ b/src/pages/view/routine/jiaoyan/cg/achievementList.vue
@@ -0,0 +1,832 @@
+
+
+
+
+
+
+
+
+ 教研成果
+ 记录和展示您的教研成果
+
+
+
+ {{ achievementList.length }}
+ 个成果
+
+
+
+
+
+
+
+
+ 所有成果
+ {{ achievementList.length }}个
+
+
+
+
+
+ 👆
+
+
+
+
+
+
+
+
+
+ ⏳
+ 加载中...
+
+
+
+
+ 教研成果
+
+
+
+
+
+
+
+ 👨🏫
+ 创建教师:
+ {{ achievement.jsxm }}
+
+
+ 📅
+ 创建时间:
+ {{ formatTime(achievement.createdTime) }}
+
+
+ 📎
+ 附件:
+ {{ achievement.fileName }}
+
+
+
+
+
+
+
+ 暂无教研成果
+ 当前没有符合条件的教研成果
+
+
+
+
+ ⏳
+ 加载中...
+
+
+
+
+ ✓
+ 已加载全部成果
+
+
+
+
+
+
+
+ +
+ 新增成果
+
+
+
+
+
+
+
+
diff --git a/src/pages/view/routine/jiaoyan/detail.vue b/src/pages/view/routine/jiaoyan/detail.vue
index 2813adc..cfe329c 100644
--- a/src/pages/view/routine/jiaoyan/detail.vue
+++ b/src/pages/view/routine/jiaoyan/detail.vue
@@ -655,7 +655,7 @@ const deleteMember = (member: MemberItem) => {
};
-