diff --git a/src/api/base/server.ts b/src/api/base/server.ts
index a23d7d0..1bc70fc 100644
--- a/src/api/base/server.ts
+++ b/src/api/base/server.ts
@@ -118,3 +118,37 @@ export const jzXsQjActivitiHistoryApi = async (params: any) => {
export const getUserLatestInfoApi = async () => {
return await get("/open/login/getLatestInfo");
};
+
+/**
+ * 根据课程ID查询作品执行数据(家长端)
+ */
+export const zpzxFindByKcParamsApi = async (params: {
+ kcId?: string;
+ njId?: string;
+ njmcId?: string;
+ bjId?: string;
+ xsId?: string;
+}) => {
+ return await get("/api/zpzx/findByKcParams", params);
+};
+
+/**
+ * 根据ID获取作品任务完整详情(包含任务信息、任务类型列表、评价人列表)
+ */
+export const zpFindDetailByIdApi = async (params: { id: string }) => {
+ return await get("/api/zp/findDetailById", params);
+};
+
+/**
+ * 新增/修改学生作品执行记录
+ */
+export const zpzxSaveApi = async (params: any) => {
+ return await post("/api/zpzx/save", params);
+};
+
+/**
+ * 根据作品执行ID查询作品清单
+ */
+export const zpqdFindByZpzxIdApi = async (params: { zpzxId: string }) => {
+ return await get("/api/zpqd/findPage", { zpzxId: params.zpzxId, page: 1, rows: 100 });
+};
\ No newline at end of file
diff --git a/src/components/BasicFile/preview.vue b/src/components/BasicFile/preview.vue
new file mode 100644
index 0000000..db89145
--- /dev/null
+++ b/src/components/BasicFile/preview.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+ 附件:
+ {{ getFileName(file) }}
+
+
+
+
+
+
+
+
diff --git a/src/components/BasicForm/components/BasicEditor.vue b/src/components/BasicForm/components/BasicEditor.vue
new file mode 100644
index 0000000..d542d43
--- /dev/null
+++ b/src/components/BasicForm/components/BasicEditor.vue
@@ -0,0 +1,517 @@
+
+
+
+
+
+
+ 📷
+ 插入图片
+
+
+
+
+
+
+
+ 当前平台不支持富文本编辑器,请使用文本输入
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/BasicForm/components/BasicPicker.vue b/src/components/BasicForm/components/BasicPicker.vue
index a293804..12c1422 100644
--- a/src/components/BasicForm/components/BasicPicker.vue
+++ b/src/components/BasicForm/components/BasicPicker.vue
@@ -14,7 +14,7 @@
+ @change="change" @popupChange="handlePopupChange"/>
@@ -115,6 +115,13 @@ function change(e: any) {
}
}
+// 处理弹窗状态变化
+function handlePopupChange(e: any) {
+ if (attrs.componentProps.onPopupChange && typeof attrs.componentProps.onPopupChange === 'function') {
+ attrs.componentProps.onPopupChange(e)
+ }
+}
+
const pickerValue = ref('')
watchEffect(() => {
diff --git a/src/components/BasicForm/src/BasicComponent.vue b/src/components/BasicForm/src/BasicComponent.vue
index 30dfa2c..43c09e0 100644
--- a/src/components/BasicForm/src/BasicComponent.vue
+++ b/src/components/BasicForm/src/BasicComponent.vue
@@ -15,11 +15,29 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/components/ImageVideoUpload/ImageVideoUpload.vue b/src/components/ImageVideoUpload/ImageVideoUpload.vue
index 4ca4d14..cdd22d6 100644
--- a/src/components/ImageVideoUpload/ImageVideoUpload.vue
+++ b/src/components/ImageVideoUpload/ImageVideoUpload.vue
@@ -2,7 +2,7 @@
-
+
图片
({{ imageList.length }}/{{ maxImageCount }})
@@ -14,14 +14,14 @@
:key="index"
>
-
+
@@ -34,7 +34,7 @@
v-if="imageList.length < maxImageCount"
@click="chooseImage"
>
-
+
添加图片
@@ -42,7 +42,7 @@
-
+
视频
({{ videoList.length }}/{{ maxVideoCount }})
@@ -60,7 +60,7 @@
mode="aspectFill"
/>
-
+
{{ formatDuration(video.duration) }}
@@ -68,7 +68,7 @@
-
+
@@ -82,7 +82,7 @@
v-if="videoList.length < maxVideoCount"
@click="chooseVideo"
>
-
+
添加视频
@@ -90,7 +90,7 @@
-
+
文件
({{ fileList.length }}/{{ maxFileCount }})
@@ -117,7 +117,7 @@
-
+
@@ -127,7 +127,7 @@
v-if="fileList.length < maxFileCount"
@click="chooseFile"
>
-
+
添加文件
@@ -139,7 +139,8 @@
import { ref, computed, watch } from 'vue'
import { imagUrl } from '@/utils'
import {
- previewFile as previewFileUtil
+ previewFile as previewFileUtil,
+ previewVideo as previewVideoUtil
} from '@/utils/filePreview'
// 接口定义
@@ -208,6 +209,9 @@ interface Props {
// 上传配置
autoUpload?: boolean
uploadApi?: (file: any) => Promise
+
+ // 是否显示区域标题
+ showSectionTitle?: boolean
}
const props = withDefaults(defineProps(), {
@@ -240,7 +244,9 @@ const props = withDefaults(defineProps(), {
}),
autoUpload: true,
- uploadApi: undefined
+ uploadApi: undefined,
+
+ showSectionTitle: true
})
// Emits
@@ -969,25 +975,61 @@ const uploadVideos = async (videos: VideoItem[]) => {
}
}
+// 获取图片显示路径(避免重复拼接)
+const getImageSrc = (image: ImageItem): string => {
+ if (!image) return '';
+ // 如果 url 存在,检查是否已经是完整 URL
+ if (image.url) {
+ // 如果已经是完整 URL(http/https/blob),直接返回
+ if (/^(https?|blob):/i.test(image.url)) {
+ return image.url;
+ }
+ // 否则使用 imagUrl 拼接
+ return imagUrl(image.url);
+ }
+ // 如果只有 tempPath,直接返回(tempPath 通常是本地路径或完整 URL)
+ return image.tempPath || '';
+}
+
// 预览图片
const previewImage = (index: number) => {
- const urls = imageList.value.map(img => img.url || img.tempPath).filter(Boolean)
+ const urls = imageList.value.map(img => getImageSrc(img)).filter(Boolean)
uni.previewImage({
urls: urls,
current: index
})
}
+// 获取视频显示路径(避免重复拼接)
+const getVideoSrc = (video: VideoItem): string => {
+ if (!video) return '';
+ // 如果 url 存在,检查是否已经是完整 URL
+ if (video.url) {
+ // 如果已经是完整 URL(http/https/blob),直接返回
+ if (/^(https?|blob):/i.test(video.url)) {
+ return video.url;
+ }
+ // 否则使用 imagUrl 拼接
+ return imagUrl(video.url);
+ }
+ // 如果只有 tempPath,直接返回(tempPath 通常是本地路径或完整 URL)
+ return video.tempPath || '';
+}
+
// 预览视频
const previewVideo = (index: number) => {
const video = videoList.value[index]
- if (video.url || video.tempPath) {
- uni.previewVideo({
- sources: [{
- src: video.url || video.tempPath,
- type: 'mp4'
- }]
- })
+ const videoSrc = getVideoSrc(video);
+ if (videoSrc) {
+ const videoName = video.originalName || video.name || '视频';
+ previewVideoUtil(videoSrc, videoName)
+ .catch((error: any) => {
+ console.error('视频预览失败:', error);
+ uni.showToast({
+ title: '视频预览失败',
+ icon: 'error'
+ });
+ });
}
}
@@ -1282,4 +1324,3 @@ defineExpose({
justify-content: center;
}
-
diff --git a/src/components/ImageVideoUpload/README.md b/src/components/ImageVideoUpload/README.md
new file mode 100644
index 0000000..0dd099e
--- /dev/null
+++ b/src/components/ImageVideoUpload/README.md
@@ -0,0 +1,223 @@
+# ImageVideoUpload 图片视频上传组件
+
+一个功能完整的图片和视频上传组件,支持压缩、预览、删除等功能。
+
+## 功能特性
+
+- ✅ 图片和视频上传
+- ✅ 智能图片压缩(支持H5和APP环境)
+- ✅ 文件大小和时长限制
+- ✅ 预览功能
+- ✅ 删除功能
+- ✅ 上传进度显示
+- ✅ 自定义压缩配置
+- ✅ 自动上传或手动上传
+- ✅ 完整的事件回调
+
+## 基本使用
+
+```vue
+
+
+
+
+
+
+
+```
+
+## Props 属性
+
+| 属性名 | 类型 | 默认值 | 说明 |
+|--------|------|--------|------|
+| enableImage | boolean | true | 是否启用图片上传 |
+| enableVideo | boolean | true | 是否启用视频上传 |
+| maxImageCount | number | 5 | 最大图片数量 |
+| maxVideoCount | number | 3 | 最大视频数量 |
+| imageList | ImageItem[] | [] | 图片列表 |
+| videoList | VideoItem[] | [] | 视频列表 |
+| compressConfig | CompressConfig | 默认配置 | 压缩配置 |
+| autoUpload | boolean | true | 是否自动上传 |
+| uploadApi | Function | - | 上传API函数 |
+
+## Events 事件
+
+| 事件名 | 参数 | 说明 |
+|--------|------|------|
+| update:imageList | images: ImageItem[] | 图片列表更新 |
+| update:videoList | videos: VideoItem[] | 视频列表更新 |
+| image-upload-success | image: ImageItem, index: number | 图片上传成功 |
+| image-upload-error | error: any, index: number | 图片上传失败 |
+| video-upload-success | video: VideoItem, index: number | 视频上传成功 |
+| video-upload-error | error: any, index: number | 视频上传失败 |
+| upload-progress | type: 'image' \| 'video', current: number, total: number | 上传进度 |
+
+## 压缩配置
+
+### 使用预设配置
+
+```javascript
+import { COMPRESS_PRESETS } from '@/components/ImageVideoUpload'
+
+// 高质量配置
+const highQualityConfig = COMPRESS_PRESETS.high
+
+// 平衡配置(默认)
+const mediumConfig = COMPRESS_PRESETS.medium
+
+// 高压缩配置
+const lowQualityConfig = COMPRESS_PRESETS.low
+```
+
+### 自定义配置
+
+```javascript
+const customConfig = {
+ image: {
+ quality: 70, // 压缩质量 (1-100)
+ maxWidth: 1600, // 最大宽度
+ maxHeight: 900, // 最大高度
+ maxSize: 300 * 1024, // 最大文件大小 300KB
+ minQuality: 25 // 最低压缩质量
+ },
+ video: {
+ maxDuration: 45, // 最大时长45秒
+ maxSize: 8 * 1024 * 1024, // 最大文件大小 8MB
+ quality: 'medium' // 视频质量
+ }
+}
+```
+
+## 高级用法
+
+### 手动上传
+
+```vue
+
+
+
+
+
+
+```
+
+### 监听上传进度
+
+```vue
+
+
+
+ 上传进度: {{ currentProgress }}/{{ totalProgress }}
+
+
+
+
+```
+
+## 样式自定义
+
+组件使用 scoped 样式,如需自定义样式,可以通过以下方式:
+
+```vue
+
+```
+
+## 注意事项
+
+1. **H5环境**:使用Canvas进行图片压缩
+2. **APP环境**:使用uni.compressImage进行压缩
+3. **文件大小**:建议根据实际需求调整压缩配置
+4. **上传API**:需要返回标准的响应格式
+5. **内存管理**:上传成功后会自动清理临时文件
+
+## 响应格式要求
+
+上传API需要返回以下格式的响应:
+
+```javascript
+{
+ resultCode: 1, // 1表示成功
+ result: [
+ {
+ filePath: "服务器文件路径"
+ }
+ ]
+}
+```
diff --git a/src/components/ImageVideoUpload/example.vue b/src/components/ImageVideoUpload/example.vue
new file mode 100644
index 0000000..d913310
--- /dev/null
+++ b/src/components/ImageVideoUpload/example.vue
@@ -0,0 +1,65 @@
+
+
+ 图片视频上传组件示例
+
+
+
+
+
+
+
+
diff --git a/src/components/ImageVideoUpload/index.ts b/src/components/ImageVideoUpload/index.ts
index fcf56e1..2409d19 100644
--- a/src/components/ImageVideoUpload/index.ts
+++ b/src/components/ImageVideoUpload/index.ts
@@ -4,4 +4,3 @@ export * from './types'
// 默认导出
export { default } from './ImageVideoUpload.vue'
-
diff --git a/src/components/ImageVideoUpload/types.ts b/src/components/ImageVideoUpload/types.ts
index 1ef4420..c63dee1 100644
--- a/src/components/ImageVideoUpload/types.ts
+++ b/src/components/ImageVideoUpload/types.ts
@@ -153,4 +153,3 @@ export const COMPRESS_PRESETS = {
}
}
}
-
diff --git a/src/components/ImageVideoUpload/使用说明.md b/src/components/ImageVideoUpload/使用说明.md
new file mode 100644
index 0000000..cc1b59e
--- /dev/null
+++ b/src/components/ImageVideoUpload/使用说明.md
@@ -0,0 +1,204 @@
+# ImageVideoUpload 图片视频上传组件
+
+## 组件位置
+`D:\code\zhxy-jsd\src\components\ImageVideoUpload\`
+
+## 文件结构
+```
+ImageVideoUpload/
+├── ImageVideoUpload.vue # 主组件文件
+├── types.ts # 类型定义
+├── index.ts # 导出文件
+├── example.vue # 使用示例
+├── README.md # 详细文档
+└── 使用说明.md # 中文说明
+```
+
+## 快速使用
+
+### 1. 基本用法
+```vue
+
+
+
+
+
+```
+
+### 2. 完整配置
+```vue
+
+
+
+
+
+```
+
+## 主要功能
+
+### ✅ 图片功能
+- 拍照/相册选择
+- 智能压缩(H5/APP自适应)
+- 预览功能
+- 删除功能
+- 压缩状态显示
+
+### ✅ 视频功能
+- 拍摄/相册选择
+- 文件大小检查
+- 时长限制
+- 预览播放
+- 删除功能
+
+### ✅ 压缩功能
+- 尺寸压缩(降低分辨率)
+- 质量压缩(调整JPEG质量)
+- 智能压缩(根据文件大小自动调整)
+- 多级压缩(确保达到目标大小)
+
+## 压缩配置
+
+### 预设配置
+```javascript
+import { COMPRESS_PRESETS } from '@/components/ImageVideoUpload'
+
+// 高质量(文件较大)
+const highConfig = COMPRESS_PRESETS.high
+
+// 平衡(推荐)
+const mediumConfig = COMPRESS_PRESETS.medium
+
+// 高压缩(文件很小)
+const lowConfig = COMPRESS_PRESETS.low
+```
+
+### 自定义配置
+```javascript
+const customConfig = {
+ image: {
+ quality: 70, // 压缩质量 1-100
+ maxWidth: 1600, // 最大宽度
+ maxHeight: 900, // 最大高度
+ maxSize: 300 * 1024, // 最大文件大小(字节)
+ minQuality: 25 // 最低压缩质量
+ },
+ video: {
+ maxDuration: 45, // 最大时长(秒)
+ maxSize: 8 * 1024 * 1024, // 最大文件大小(字节)
+ quality: 'medium' // 视频质量
+ }
+}
+```
+
+## 事件回调
+
+```javascript
+// 图片上传成功
+@image-upload-success="(image, index) => {}"
+
+// 图片上传失败
+@image-upload-error="(error, index) => {}"
+
+// 视频上传成功
+@video-upload-success="(video, index) => {}"
+
+// 视频上传失败
+@video-upload-error="(error, index) => {}"
+
+// 上传进度
+@upload-progress="(type, current, total) => {}"
+```
+
+## 在 xcXkkcDetail.vue 中的使用
+
+原来的代码已经替换为:
+
+```vue
+
+```
+
+## 注意事项
+
+1. **环境兼容**:自动检测H5/APP环境,使用不同的压缩方案
+2. **文件大小**:建议根据实际需求调整压缩配置
+3. **上传API**:需要返回标准格式的响应
+4. **内存管理**:上传成功后自动清理临时文件
+5. **错误处理**:完善的错误处理和用户提示
+
+## 响应格式要求
+
+上传API需要返回:
+```javascript
+{
+ resultCode: 1, // 1表示成功
+ result: [
+ {
+ filePath: "服务器文件路径"
+ }
+ ]
+}
+```
+
+## 样式自定义
+
+组件使用scoped样式,如需自定义:
+
+```css
+/* 全局样式覆盖 */
+.image-video-upload .add-btn {
+ border-color: #007aff;
+}
+```
+
+## 测试
+
+可以运行 `example.vue` 来测试组件功能。
diff --git a/src/config.ts b/src/config.ts
index a9754fd..b7a1482 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -17,6 +17,8 @@ export const BASE_WS_URL: string =
//图片地址
// export const BASE_IMAGE_URL: string = process.env.NODE_ENV == "development" ? `https://${ip}` : `http://${fwqip}`;
export const BASE_IMAGE_URL: string = `http://${fwqip}`;
+// kkFileView预览服务地址
+export const KK_FILE_VIEW_URL: string = `https://${fwqip}/kkpro`;
//存token的key
export const AUTH_KEY: string = "satoken";
//token过期返回状态码
diff --git a/src/pages.json b/src/pages.json
index 72b58a2..28ec3b5 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -76,6 +76,17 @@
"backgroundColor": "#ffffff"
}
},
+ {
+ "path": "pages/system/video-player/index",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "视频播放",
+ "enablePullDownRefresh": false,
+ "navigationBarBackgroundColor": "#000000",
+ "navigationBarTextStyle": "white",
+ "backgroundColor": "#000000"
+ }
+ },
{
"path": "pages/system/updatePopup/updatePopup",
"style": {
@@ -143,6 +154,27 @@
"enablePullDownRefresh": false
}
},
+ {
+ "path": "pages/base/xszp/index",
+ "style": {
+ "navigationBarTitleText": "作品任务",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/base/xszp/submit",
+ "style": {
+ "navigationBarTitleText": "作品提交",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/base/xszp/detail",
+ "style": {
+ "navigationBarTitleText": "任务详情",
+ "enablePullDownRefresh": false
+ }
+ },
{
"path": "pages/base/jl/detailwb",
"style": {
diff --git a/src/pages/base/home/index.vue b/src/pages/base/home/index.vue
index fe61d17..ab868aa 100644
--- a/src/pages/base/home/index.vue
+++ b/src/pages/base/home/index.vue
@@ -28,7 +28,7 @@
class="grid-item" @click="handleMenuClick(item)">
-
+
{{ item.title }}
@@ -204,7 +204,7 @@ const menuItems = ref([
},
{
title: "就餐详情",
- icon: "/static/base/home/contacts-book-3-line.png",
+ icon: "/static/base/home/jcxq.png",
path: "/pages/base/jc/index",
permissionKey: "school-jcxq",
},
@@ -226,7 +226,7 @@ const menuItems = ref([
},
{
title: "就餐报名",
- icon: "/static/base/home/contacts-book-3-line.png",
+ icon: "/static/base/home/jcxq.png",
path: "/pages/base/gzs/index",
permissionKey: "school-jcjf",
action: 'jf',
@@ -248,6 +248,12 @@ const menuItems = ref([
action: "tf",
lxId: "816059832",
},
+ {
+ title: "新苗成长",
+ icon: "/static/base/home/xszp.png",
+ path: "/pages/base/xszp/index",
+ permissionKey: "school-xszp",
+ },
]);
// 通知公告数据
@@ -287,6 +293,15 @@ function switchXs(xs: any) {
getArticleList();
}
+// 处理图片加载失败
+function handleImageError(e: any) {
+ // 图片加载失败时,使用默认占位图标
+ const target = e.target || e.currentTarget;
+ if (target) {
+ target.src = '/static/base/home/file-text-line.png'; // 默认图标
+ }
+}
+
// 跳转到详情页面
function goToDetail(notice: any) {
setData(notice)
diff --git a/src/pages/base/xszp/detail.vue b/src/pages/base/xszp/detail.vue
new file mode 100644
index 0000000..45febd1
--- /dev/null
+++ b/src/pages/base/xszp/detail.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+ 任务要求
+
+
+
+ 任务名称:
+ {{ taskInfo.zpmc || '作品任务' }}
+
+
+
+
+ 任务描述:
+ {{ taskInfo.zpms }}
+
+
+
+
+ 任务时间:
+ {{ formatTimeRange(taskInfo.zpkstime, taskInfo.zpjstime) }}
+
+
+
+
+
+ 附件:
+ {{ taskInfo.fileName }}
+
+
+
+
+
+
+ 任务项
+
+
+
+
+
+
+
+ 类型:
+ {{ getTaskTypeText(item.zpfl) }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/base/xszp/index.vue b/src/pages/base/xszp/index.vue
new file mode 100644
index 0000000..12da445
--- /dev/null
+++ b/src/pages/base/xszp/index.vue
@@ -0,0 +1,662 @@
+
+
+
+
+
+
+
+ 正在认证中...
+
+
+
+
+
+
+
+
+ 📝
+
+ 作品任务
+ 独立项目选择 · 学习成长
+
+
+
+ {{ taskList.length }}
+ 个任务
+
+
+
+
+
+
+
+ 独立项目选择
+ 请从下方{{ taskList.length }}个任务中选择1个完成,可自主挑战更高层级
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+ {{ task.zpms }}
+
+
+
+
+ 课程:
+ {{ task.kcmc }}
+
+
+ 提交时间:
+ {{ formatTime(task.zptjsj) }}
+
+
+
+
+
+
+
+
+
+ 📭
+ 暂无作品任务
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/base/xszp/submit.vue b/src/pages/base/xszp/submit.vue
new file mode 100644
index 0000000..29a53ec
--- /dev/null
+++ b/src/pages/base/xszp/submit.vue
@@ -0,0 +1,1114 @@
+
+
+
+
+
+
+
+ 提交中...
+
+
+
+ 加载中...
+
+
+
+
+ 任务要求
+
+
+
+ 任务名称:
+ {{ zp.zpmc || '作品任务' }}
+
+
+
+
+ 任务描述:
+ {{ zp.zpms }}
+
+
+
+
+ 任务时间:
+ {{ formatTimeRange(zp.zpkstime, zp.zpjstime) }}
+
+
+
+
+
+
+
+
+
+
+ 作品提交
+
+
+
+
+ {{ category.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/system/video-player/index.vue b/src/pages/system/video-player/index.vue
new file mode 100644
index 0000000..6a61e76
--- /dev/null
+++ b/src/pages/system/video-player/index.vue
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+ {{ videoTitle }}
+ {{ videoDesc }}
+
+
+
+
+
+
+
diff --git a/src/static/base/home/book-read-line.png b/src/static/base/home/book-read-line.png
index b6ba2a7..e0d4db7 100644
Binary files a/src/static/base/home/book-read-line.png and b/src/static/base/home/book-read-line.png differ
diff --git a/src/static/base/home/contacts-book-3-line.png b/src/static/base/home/contacts-book-3-line.png
index 1ad9331..fb817db 100644
Binary files a/src/static/base/home/contacts-book-3-line.png and b/src/static/base/home/contacts-book-3-line.png differ
diff --git a/src/static/base/home/draft-line.png b/src/static/base/home/draft-line.png
index 4e13c8a..04156ca 100644
Binary files a/src/static/base/home/draft-line.png and b/src/static/base/home/draft-line.png differ
diff --git a/src/static/base/home/file-search-line.png b/src/static/base/home/file-search-line.png
index 47b81a2..f686f52 100644
Binary files a/src/static/base/home/file-search-line.png and b/src/static/base/home/file-search-line.png differ
diff --git a/src/static/base/home/file-text-line.png b/src/static/base/home/file-text-line.png
index 0cb5053..428d4dc 100644
Binary files a/src/static/base/home/file-text-line.png and b/src/static/base/home/file-text-line.png differ
diff --git a/src/static/base/home/file-transfer-line.png b/src/static/base/home/file-transfer-line.png
index 6ea391f..f044cf5 100644
Binary files a/src/static/base/home/file-transfer-line.png and b/src/static/base/home/file-transfer-line.png differ
diff --git a/src/static/base/home/jcxq.png b/src/static/base/home/jcxq.png
new file mode 100644
index 0000000..65d114e
Binary files /dev/null and b/src/static/base/home/jcxq.png differ
diff --git a/src/static/base/home/xszp.png b/src/static/base/home/xszp.png
new file mode 100644
index 0000000..3d9afe8
Binary files /dev/null and b/src/static/base/home/xszp.png differ
diff --git a/src/static/base/view/excel.png b/src/static/base/view/excel.png
new file mode 100644
index 0000000..697849a
Binary files /dev/null and b/src/static/base/view/excel.png differ
diff --git a/src/static/base/view/fire-black.png b/src/static/base/view/fire-black.png
new file mode 100644
index 0000000..d6eff97
Binary files /dev/null and b/src/static/base/view/fire-black.png differ
diff --git a/src/static/base/view/fire-white.png b/src/static/base/view/fire-white.png
new file mode 100644
index 0000000..13dfebf
Binary files /dev/null and b/src/static/base/view/fire-white.png differ
diff --git a/src/static/base/view/fire.png b/src/static/base/view/fire.png
new file mode 100644
index 0000000..1c8f494
Binary files /dev/null and b/src/static/base/view/fire.png differ
diff --git a/src/static/base/view/image.png b/src/static/base/view/image.png
new file mode 100644
index 0000000..e81038f
Binary files /dev/null and b/src/static/base/view/image.png differ
diff --git a/src/static/base/view/more.png b/src/static/base/view/more.png
new file mode 100644
index 0000000..66ddf7c
Binary files /dev/null and b/src/static/base/view/more.png differ
diff --git a/src/static/base/view/pdf.png b/src/static/base/view/pdf.png
new file mode 100644
index 0000000..3254950
Binary files /dev/null and b/src/static/base/view/pdf.png differ
diff --git a/src/static/base/view/ppt.png b/src/static/base/view/ppt.png
new file mode 100644
index 0000000..7e9147b
Binary files /dev/null and b/src/static/base/view/ppt.png differ
diff --git a/src/static/base/view/qdself.png b/src/static/base/view/qdself.png
new file mode 100644
index 0000000..d28bc8d
Binary files /dev/null and b/src/static/base/view/qdself.png differ
diff --git a/src/static/base/view/rgzn.png b/src/static/base/view/rgzn.png
new file mode 100644
index 0000000..8f537de
Binary files /dev/null and b/src/static/base/view/rgzn.png differ
diff --git a/src/static/base/view/sptg.png b/src/static/base/view/sptg.png
new file mode 100644
index 0000000..f2d27dc
Binary files /dev/null and b/src/static/base/view/sptg.png differ
diff --git a/src/static/base/view/word.png b/src/static/base/view/word.png
new file mode 100644
index 0000000..e0b4494
Binary files /dev/null and b/src/static/base/view/word.png differ
diff --git a/src/static/base/view/zip.png b/src/static/base/view/zip.png
new file mode 100644
index 0000000..7a4892e
Binary files /dev/null and b/src/static/base/view/zip.png differ
diff --git a/src/static/base/view/zyyl.png b/src/static/base/view/zyyl.png
new file mode 100644
index 0000000..6d9e129
Binary files /dev/null and b/src/static/base/view/zyyl.png differ
diff --git a/src/utils/filePreview.ts b/src/utils/filePreview.ts
index 904981e..4bc13b6 100644
--- a/src/utils/filePreview.ts
+++ b/src/utils/filePreview.ts
@@ -1,24 +1,132 @@
+/**
+ * 文件预览工具函数
+ * 提供跨平台的文件预览功能
+ */
+
+import { KK_FILE_VIEW_URL } from '@/config';
+
+// 检查是否是压缩包文件
+const isCompressedFile = (fileName: string): boolean => {
+ const compressedExtensions = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'];
+ const extension = fileName.split('.').pop()?.toLowerCase();
+ return compressedExtensions.includes(extension || '');
+};
+
+// 检查文件是否可以预览
+const canPreview = (fileName: string): boolean => {
+ const previewableExtensions = [
+ 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
+ 'txt', 'rtf', 'odt', 'ods', 'odp',
+ 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+ 'mp4', 'avi', 'mov', 'wmv', 'flv', 'webm',
+ 'mp3', 'wav', 'ogg', 'aac', 'm4a'
+ ];
+ const extension = fileName.split('.').pop()?.toLowerCase();
+ return previewableExtensions.includes(extension || '');
+};
+
// 文件预览工具函数
export const previewFile = (fileUrl: string, fileName: string, fileType: string) => {
return new Promise((resolve, reject) => {
const type = fileType.toLowerCase();
+ console.log('=== 文件预览调试信息 ===');
+ console.log('原始文件URL:', fileUrl);
+ console.log('文件名:', fileName);
+ console.log('文件类型:', fileType);
+
// 检查是否是压缩包文件,如果是则直接下载
- if (['zip', 'rar', '7z', 'tar', 'gz'].includes(type)) {
+ if (isCompressedFile(fileName)) {
+ console.log('=== 检测到压缩包文件,直接下载 ===');
uni.showToast({ title: '压缩包文件不支持预览,将为您下载', icon: 'none' });
downloadFile(fileUrl, fileName).then(resolve).catch(resolve);
return;
}
- // 使用 kkview 预览
- const previewUrl = fileUrl;
- const needLandscape = ['ppt', 'pptx'].includes(type);
+ // 检查是否支持预览的文件格式
+ const canPreviewType = canPreview(fileName);
+
+ if (!canPreviewType) {
+ // 不支持预览的文件格式,直接下载
+ console.log('不支持预览的文件格式,执行下载');
+ uni.showToast({ title: '该文件格式暂不支持预览,将为您下载', icon: 'none' });
+ downloadFile(fileUrl, fileName).then(resolve).catch(resolve);
+ return;
+ }
+
+ // 检查URL是否已经是kkFileView生成的压缩包内文件URL
+ const isCompressedFileUrl = fileUrl.includes('kkCompressfileKey') && fileUrl.includes('kkCompressfilepath');
+
+ console.log('=== 压缩包内文件检测 ===');
+ console.log('URL包含kkCompressfileKey:', fileUrl.includes('kkCompressfileKey'));
+ console.log('URL包含kkCompressfilepath:', fileUrl.includes('kkCompressfilepath'));
+ console.log('是否为压缩包内文件URL:', isCompressedFileUrl);
+
+ if (isCompressedFileUrl) {
+ console.log('=== 压缩包内文件处理 ===');
+ console.log('检测到压缩包内文件URL,直接使用');
+ console.log('原始压缩包内文件URL:', fileUrl);
+
+ const previewUrl = fileUrl; // 直接使用这个URL,不重新编码
+ console.log('最终预览URL (压缩包内文件):', previewUrl);
+
+ const needLandscape = ['ppt', 'pptx'].includes(type);
+ console.log('是否需要横屏显示:', needLandscape);
+
+ const targetPageUrl = `/pages/system/webView/webView?url=${encodeURIComponent(previewUrl)}`;
+ console.log('跳转目标页面URL:', targetPageUrl);
+
+ uni.navigateTo({
+ url: targetPageUrl,
+ success: () => {
+ console.log('跳转到压缩包内文件预览页面成功');
+ resolve(true);
+ },
+ fail: (err) => {
+ console.error('跳转到压缩包内文件预览页面失败:', err);
+ console.log('错误详情:', JSON.stringify(err));
+ uni.showToast({ title: '预览加载失败,尝试下载', icon: 'none' });
+ setTimeout(() => {
+ downloadFile(fileUrl, fileName).then(resolve).catch(resolve);
+ }, 1000);
+ }
+ });
+ return; // 退出函数
+ }
+
+ console.log('=== 普通文件处理 ===');
+
+ // 处理普通文件预览
+ const finalFileUrl = fileUrl;
+ console.log('DEBUG: 最终用于编码的URL (finalFileUrl):', finalFileUrl);
+
+ // 使用kkFileView进行预览
+ const encodedUrl = btoa(finalFileUrl);
+ console.log('使用kkFileView预览,Base64编码后的URL:', encodedUrl);
+
+ const previewUrl = `${KK_FILE_VIEW_URL}/onlinePreview?url=${encodeURIComponent(encodedUrl)}`;
+ console.log('最终预览URL (普通文件):', previewUrl);
+
+ const needLandscape = ['ppt', 'pptx'].includes(type);
+ console.log('是否需要横屏显示:', needLandscape);
+
+ const targetPageUrl = `/pages/system/webView/webView?url=${encodeURIComponent(previewUrl)}`;
+ console.log('跳转目标页面URL:', targetPageUrl);
- // 打开预览页面
uni.navigateTo({
- url: `/pages/base/view/index?url=${encodeURIComponent(previewUrl)}&name=${encodeURIComponent(fileName)}&landscape=${needLandscape}`,
- success: resolve,
- fail: reject
+ url: targetPageUrl,
+ success: () => {
+ console.log('跳转到预览页面成功');
+ resolve(true);
+ },
+ fail: (err) => {
+ console.error('跳转到预览页面失败:', err);
+ console.log('错误详情:', JSON.stringify(err));
+ uni.showToast({ title: '预览加载失败,尝试下载', icon: 'none' });
+ setTimeout(() => {
+ downloadFile(fileUrl, fileName).then(resolve).catch(resolve);
+ }, 1000);
+ }
});
});
};
@@ -47,3 +155,38 @@ const downloadFile = (fileUrl: string, fileName: string) => {
});
};
+// 视频预览
+export const previewVideo = (videoUrl: string, videoTitle: string) => {
+ console.log('=== 视频预览调试信息 ===');
+ console.log('视频URL:', videoUrl);
+ console.log('视频标题:', videoTitle);
+
+ return new Promise((resolve) => {
+ const targetUrl = `/pages/system/video-player/index?url=${encodeURIComponent(videoUrl)}&title=${encodeURIComponent(videoTitle)}`;
+ console.log('跳转目标URL:', targetUrl);
+
+ uni.navigateTo({
+ url: targetUrl,
+ success: () => {
+ console.log('跳转到视频播放页面成功');
+ resolve(true);
+ },
+ fail: (err) => {
+ console.error('跳转到视频播放页面失败:', err);
+ console.log('错误详情:', JSON.stringify(err));
+
+ // 跳转失败时尝试使用系统播放器
+ uni.showToast({
+ title: '跳转失败,尝试使用系统播放器',
+ icon: 'none',
+ duration: 2000
+ });
+
+ // 延迟后尝试下载视频
+ setTimeout(() => {
+ downloadFile(videoUrl, videoTitle + '.mp4').then(resolve).catch(resolve);
+ }, 2000);
+ }
+ });
+ });
+};