选课调整
This commit is contained in:
parent
80f126c25a
commit
e72543cb2b
@ -155,3 +155,5 @@ const setDefaultValue = () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
<template v-for="(item,index) in head" :key="index">
|
<template v-for="(item,index) in head" :key="index">
|
||||||
<view class="font-w-500 px-5 flex-row justify-between items-center" style="width: 115px" v-if="index==0"
|
<view class="font-w-500 px-5 flex-row justify-between items-center" style="width: 115px" v-if="index==0"
|
||||||
:style="{ position: 'sticky', left: '0', backgroundColor: '#aacbfb', zIndex: 10 }">
|
:style="{ position: 'sticky', left: '0', backgroundColor: '#aacbfb', zIndex: 10 }">
|
||||||
<view v-for="(zitem,xindex) in item['name'].split(',')" :key="'z_'+xindex">
|
<view v-for="(zitem,xindex) in (item['name'] || '').split(',')" :key="'z_'+xindex">
|
||||||
{{ zitem }}
|
{{ zitem }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<view class="font-13 flex-row justify-between items-center px-5" style="width: 115px" v-if="dindex==0"
|
<view class="font-13 flex-row justify-between items-center px-5" style="width: 115px" v-if="dindex==0"
|
||||||
:style="{ position: 'sticky', left: '0', backgroundColor: '#f8f8f8', zIndex: 10 }">
|
:style="{ position: 'sticky', left: '0', backgroundColor: '#f8f8f8', zIndex: 10 }">
|
||||||
<view> {{ bitem['gradeFullName'] }}</view>
|
<view> {{ bitem['gradeFullName'] }}</view>
|
||||||
<view>{{ 100 + parseFloat(bitem['totalScore']) }}</view>
|
<view>{{ calculateTotalScore(bitem) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- <view class="font-13 flex-col-center" v-else-if="dindex==1"-->
|
<!-- <view class="font-13 flex-col-center" v-else-if="dindex==1"-->
|
||||||
<!-- :style="{ position: 'sticky', left: '0', backgroundColor: '#f8f8f8', zIndex: 10 }">-->
|
<!-- :style="{ position: 'sticky', left: '0', backgroundColor: '#f8f8f8', zIndex: 10 }">-->
|
||||||
@ -35,10 +35,10 @@
|
|||||||
<!-- </view>-->
|
<!-- </view>-->
|
||||||
<view class="font-13 flex-col-center" v-else>
|
<view class="font-13 flex-col-center" v-else>
|
||||||
<view v-if="bitem['itemScoreMap'][ ditem['id']]">
|
<view v-if="bitem['itemScoreMap'][ ditem['id']]">
|
||||||
{{ bitem['itemScoreMap'][ditem['id']] }}
|
{{ calculateItemScore(bitem, ditem) }}
|
||||||
</view>
|
</view>
|
||||||
<view v-else>
|
<view v-else>
|
||||||
<image src="/static/base/tb.jpg" class="wi-50 he-50"></image>
|
{{ getBaseScore(ditem) }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@ -65,9 +65,56 @@ onMounted(() => {
|
|||||||
height.value = getWindowHeight()
|
height.value = getWindowHeight()
|
||||||
})
|
})
|
||||||
|
|
||||||
const head = ref([])
|
const head = ref<any[]>([])
|
||||||
const dataLiat = ref<any>([])
|
const dataLiat = ref<any>([])
|
||||||
|
|
||||||
|
// 获取检查项基础分:baseScore * 5
|
||||||
|
function getBaseScore(ditem: any) {
|
||||||
|
const inspectItem = head.value.find(item => item.id === ditem.id);
|
||||||
|
if (inspectItem && inspectItem.baseScore) {
|
||||||
|
return inspectItem.baseScore * 5;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算单个检查项得分:baseScore * 5 - 扣分项
|
||||||
|
function calculateItemScore(bitem: any, ditem: any) {
|
||||||
|
if (bitem.itemScoreMap && bitem.itemScoreMap[ditem.id]) {
|
||||||
|
// 找到对应的检查项获取baseScore
|
||||||
|
const inspectItem = head.value.find(item => item.id === ditem.id);
|
||||||
|
if (inspectItem && inspectItem.baseScore) {
|
||||||
|
const baseScore = inspectItem.baseScore * 5; // 基础分
|
||||||
|
const deduction = bitem.itemScoreMap[ditem.id]; // 扣分项(负数)
|
||||||
|
// 得分 = baseScore * 5 - 扣分项
|
||||||
|
return baseScore + deduction; // deduction是负数,所以用加法
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算总分:所有检查项汇总
|
||||||
|
function calculateTotalScore(bitem: any) {
|
||||||
|
let totalScore = 0;
|
||||||
|
|
||||||
|
// 遍历所有检查项(从head中获取)
|
||||||
|
head.value.forEach(item => {
|
||||||
|
if (item.id && item.baseScore) {
|
||||||
|
const baseScore = item.baseScore * 5; // 基础分
|
||||||
|
let deduction = 0; // 扣分项
|
||||||
|
|
||||||
|
// 如果有扣分记录,获取扣分
|
||||||
|
if (bitem.itemScoreMap && bitem.itemScoreMap[item.id]) {
|
||||||
|
deduction = bitem.itemScoreMap[item.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得分 = baseScore * 5 - 扣分项
|
||||||
|
totalScore += baseScore + deduction; // deduction是负数,所以用加法
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return totalScore;
|
||||||
|
}
|
||||||
|
|
||||||
async function getWeekData() {
|
async function getWeekData() {
|
||||||
let res = await inspectItemFindAllApi();
|
let res = await inspectItemFindAllApi();
|
||||||
let arr: any = [{name: "班级,得分"}];
|
let arr: any = [{name: "班级,得分"}];
|
||||||
@ -79,8 +126,25 @@ async function getWeekData() {
|
|||||||
// arr.push();
|
// arr.push();
|
||||||
head.value = arr
|
head.value = arr
|
||||||
let res1 = await evaluationGetWeekReportApi();
|
let res1 = await evaluationGetWeekReportApi();
|
||||||
const grouped = groupBy(res1.result, 'gradeNum');
|
|
||||||
dataLiat.value = values(grouped);
|
// 按年级分组,但保持排序
|
||||||
|
// 提取年级名称进行分组
|
||||||
|
const grouped = groupBy(res1.result, (item) => {
|
||||||
|
// 从"一年级1班"中提取"一年级"
|
||||||
|
const match = item.gradeFullName.match(/^(.+?)(\d+班)$/);
|
||||||
|
return match ? match[1] : item.gradeFullName;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取所有年级并排序(按年级名称排序)
|
||||||
|
const gradeNames = Object.keys(grouped).sort((a, b) => {
|
||||||
|
// 提取年级数字进行排序
|
||||||
|
const numA = parseInt(a.replace(/[^\d]/g, '')) || 0;
|
||||||
|
const numB = parseInt(b.replace(/[^\d]/g, '')) || 0;
|
||||||
|
return numA - numB;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 按排序后的年级顺序重新组织数据
|
||||||
|
dataLiat.value = gradeNames.map(gradeName => grouped[gradeName]);
|
||||||
// forEach(result, (data) => {
|
// forEach(result, (data) => {
|
||||||
// let rowDatas: any = [];
|
// let rowDatas: any = [];
|
||||||
// if (data && data.length > 0) {
|
// if (data && data.length > 0) {
|
||||||
|
|||||||
@ -30,70 +30,21 @@
|
|||||||
<view class="file-section">
|
<view class="file-section">
|
||||||
<view class="section-title">附件</view>
|
<view class="section-title">附件</view>
|
||||||
<view class="file-list" v-if="hasAttachments">
|
<view class="file-list" v-if="hasAttachments">
|
||||||
<!-- 处理单个附件(从gwInfo直接获取) -->
|
<!-- 显示所有解析后的附件 -->
|
||||||
<view
|
<view
|
||||||
v-if="gwInfo.fileUrl"
|
v-for="(file, index) in parsedAttachments"
|
||||||
|
:key="(file as any).id || index"
|
||||||
class="file-item"
|
class="file-item"
|
||||||
@click="previewSingleFile"
|
|
||||||
>
|
>
|
||||||
<view class="file-icon">
|
<view class="file-icon">
|
||||||
<text v-if="isImage(gwInfo.fileFormat || '')">🖼️</text>
|
<image
|
||||||
<text v-else-if="isVideo(gwInfo.fileFormat || '')">🎥</text>
|
:src="getFileIcon(getFileSuffix(file))"
|
||||||
<text v-else-if="canPreview(gwInfo.fileFormat || '')">📄</text>
|
class="icon-image"
|
||||||
<text v-else>📎</text>
|
mode="aspectFit"
|
||||||
</view>
|
|
||||||
<view class="file-info">
|
|
||||||
<text class="file-name">{{ gwInfo.fileName || '未知文件' }}</text>
|
|
||||||
<text class="file-type">{{ (gwInfo.fileFormat || 'unknown').toUpperCase() }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="file-actions">
|
|
||||||
<u-button
|
|
||||||
v-if="canPreview(gwInfo.fileFormat || '') && !isVideo(gwInfo.fileFormat || '')"
|
|
||||||
text="预览"
|
|
||||||
size="mini"
|
|
||||||
type="primary"
|
|
||||||
@click.stop="previewSingleFile"
|
|
||||||
/>
|
/>
|
||||||
<u-button
|
|
||||||
v-if="isVideo(gwInfo.fileFormat || '')"
|
|
||||||
text="播放"
|
|
||||||
size="mini"
|
|
||||||
type="success"
|
|
||||||
@click.stop="previewSingleFile"
|
|
||||||
/>
|
|
||||||
<u-button
|
|
||||||
v-if="isImage(gwInfo.fileFormat || '')"
|
|
||||||
text="查看"
|
|
||||||
size="mini"
|
|
||||||
type="warning"
|
|
||||||
@click.stop="previewSingleFile"
|
|
||||||
/>
|
|
||||||
<u-button
|
|
||||||
text="下载"
|
|
||||||
size="mini"
|
|
||||||
type="info"
|
|
||||||
@click.stop="downloadSingleFile"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 处理多个附件(从files数组获取) -->
|
|
||||||
<view
|
|
||||||
v-for="(file, index) in gwInfo.files"
|
|
||||||
:key="index"
|
|
||||||
class="file-item"
|
|
||||||
@click="previewFile(file)"
|
|
||||||
>
|
|
||||||
<view class="file-icon">
|
|
||||||
<text v-if="isImage(getFileSuffix(file))">🖼️</text>
|
|
||||||
<text v-else-if="isVideo(getFileSuffix(file))">🎥</text>
|
|
||||||
<text v-else-if="canPreview(getFileSuffix(file))">📄</text>
|
|
||||||
<text v-else>📎</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="file-info">
|
<view class="file-info">
|
||||||
<text class="file-name">{{ getFileName(file) }}</text>
|
<text class="file-name">{{ getFileName(file) }}</text>
|
||||||
<text class="file-size">{{ formatFileSize(file.size) }}</text>
|
|
||||||
<text class="file-type">{{ getFileSuffix(file).toUpperCase() }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="file-actions">
|
<view class="file-actions">
|
||||||
<u-button
|
<u-button
|
||||||
@ -101,27 +52,27 @@
|
|||||||
text="预览"
|
text="预览"
|
||||||
size="mini"
|
size="mini"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click.stop="previewFile(file)"
|
@click="previewFile(file)"
|
||||||
/>
|
/>
|
||||||
<u-button
|
<u-button
|
||||||
v-if="isVideo(getFileSuffix(file))"
|
v-if="isVideo(getFileSuffix(file))"
|
||||||
text="播放"
|
text="播放"
|
||||||
size="mini"
|
size="mini"
|
||||||
type="success"
|
type="success"
|
||||||
@click.stop="previewFile(file)"
|
@click="previewFile(file)"
|
||||||
/>
|
/>
|
||||||
<u-button
|
<u-button
|
||||||
v-if="isImage(getFileSuffix(file))"
|
v-if="isImage(getFileSuffix(file))"
|
||||||
text="查看"
|
text="查看"
|
||||||
size="mini"
|
size="mini"
|
||||||
type="warning"
|
type="warning"
|
||||||
@click.stop="previewFile(file)"
|
@click="previewFile(file)"
|
||||||
/>
|
/>
|
||||||
<u-button
|
<u-button
|
||||||
text="下载"
|
text="下载"
|
||||||
size="mini"
|
size="mini"
|
||||||
type="info"
|
type="info"
|
||||||
@click.stop="downloadFile(file)"
|
@click="downloadFileAction(file)"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -208,7 +159,6 @@
|
|||||||
<text class="time">{{ formatTime(log.operationTime) }}</text>
|
<text class="time">{{ formatTime(log.operationTime) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="log-content">
|
<view class="log-content">
|
||||||
<text class="type">{{ log.operationType }}</text>
|
|
||||||
<text class="content">{{ log.operationContent }}</text>
|
<text class="content">{{ log.operationContent }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="log-detail" v-if="log.beforeChange || log.afterChange">
|
<view class="log-detail" v-if="log.beforeChange || log.afterChange">
|
||||||
@ -265,7 +215,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- 操作记录详情弹窗 -->
|
<!-- 操作记录详情弹窗 -->
|
||||||
<u-popup v-model="showLogDetailModal" mode="center">
|
<u-popup :show="showLogDetailModal" @close="showLogDetailModal = false" mode="center">
|
||||||
<view class="detail-modal">
|
<view class="detail-modal">
|
||||||
<view class="detail-header">
|
<view class="detail-header">
|
||||||
<text class="detail-title">操作详情</text>
|
<text class="detail-title">操作详情</text>
|
||||||
@ -287,6 +237,48 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</u-popup>
|
</u-popup>
|
||||||
|
|
||||||
|
<!-- 下载路径选择弹窗 -->
|
||||||
|
<u-popup :show="showDownloadModal" @close="showDownloadModal = false" mode="center">
|
||||||
|
<view class="download-modal">
|
||||||
|
<view class="download-header">
|
||||||
|
<text class="download-title">文件下载</text>
|
||||||
|
</view>
|
||||||
|
<view class="download-content">
|
||||||
|
<view class="file-info-section">
|
||||||
|
<text class="file-label">文件名:</text>
|
||||||
|
<text class="file-name">{{ downloadFileName }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="path-info-section">
|
||||||
|
<text class="path-label">下载路径:</text>
|
||||||
|
<text class="path-text">将下载到默认下载目录</text>
|
||||||
|
</view>
|
||||||
|
<view class="download-tips">
|
||||||
|
<text class="tips-text">点击确认后将开始下载文件</text>
|
||||||
|
</view>
|
||||||
|
<!-- 下载中状态 -->
|
||||||
|
<view class="download-progress" v-if="isDownloading">
|
||||||
|
<view class="progress-spinner"></view>
|
||||||
|
<text class="progress-text">正在下载文件,请稍候...</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="download-actions" v-if="!isDownloading">
|
||||||
|
<u-button
|
||||||
|
text="取消"
|
||||||
|
type="default"
|
||||||
|
size="large"
|
||||||
|
@click="cancelDownload"
|
||||||
|
style="margin-right: 10px;"
|
||||||
|
/>
|
||||||
|
<u-button
|
||||||
|
text="确认下载"
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="confirmDownload"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
</BasicLayout>
|
</BasicLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -305,7 +297,8 @@ import {
|
|||||||
canPreview,
|
canPreview,
|
||||||
previewFile as previewFileUtil,
|
previewFile as previewFileUtil,
|
||||||
previewVideo as previewVideoUtil,
|
previewVideo as previewVideoUtil,
|
||||||
previewImage as previewImageUtil
|
previewImage as previewImageUtil,
|
||||||
|
downloadFile
|
||||||
} from "@/utils/filePreview";
|
} from "@/utils/filePreview";
|
||||||
|
|
||||||
// 类型定义
|
// 类型定义
|
||||||
@ -332,6 +325,7 @@ interface GwInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface FileInfo {
|
interface FileInfo {
|
||||||
|
id?: string; // 文件ID
|
||||||
name: string;
|
name: string;
|
||||||
size: number;
|
size: number;
|
||||||
url: string;
|
url: string;
|
||||||
@ -379,6 +373,10 @@ const gwId = ref("");
|
|||||||
|
|
||||||
// 弹窗控制
|
// 弹窗控制
|
||||||
const showLogDetailModal = ref(false);
|
const showLogDetailModal = ref(false);
|
||||||
|
const showDownloadModal = ref(false);
|
||||||
|
const downloadUrl = ref('');
|
||||||
|
const downloadFileName = ref('');
|
||||||
|
const isDownloading = ref(false);
|
||||||
|
|
||||||
// 用户store
|
// 用户store
|
||||||
const { getUser, getJs } = useUserStore();
|
const { getUser, getJs } = useUserStore();
|
||||||
@ -396,9 +394,54 @@ const ccExpanded = ref(false);
|
|||||||
// 操作记录展开状态
|
// 操作记录展开状态
|
||||||
const logExpanded = ref(false);
|
const logExpanded = ref(false);
|
||||||
|
|
||||||
|
// 计算属性:解析后的附件列表
|
||||||
|
const parsedAttachments = computed(() => {
|
||||||
|
const attachments = [];
|
||||||
|
|
||||||
|
// 处理files数组
|
||||||
|
if (gwInfo.value.files && gwInfo.value.files.length > 0) {
|
||||||
|
attachments.push(...gwInfo.value.files);
|
||||||
|
}
|
||||||
|
// 处理逗号分隔的fileUrl字符串
|
||||||
|
else if (gwInfo.value.fileUrl) {
|
||||||
|
const fileUrls = gwInfo.value.fileUrl.split(',').map(url => url.trim()).filter(url => url);
|
||||||
|
|
||||||
|
// 解析fileName字符串(如果存在)
|
||||||
|
let fileNames: string[] = [];
|
||||||
|
if (gwInfo.value.fileName) {
|
||||||
|
fileNames = gwInfo.value.fileName.split(',').map(name => name.trim()).filter(name => name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将URL字符串转换为文件对象
|
||||||
|
fileUrls.forEach((url, index) => {
|
||||||
|
// 优先使用解析出的文件名,如果没有则从URL提取
|
||||||
|
let displayName = fileNames[index] || url.split('/').pop() || `文件${index + 1}`;
|
||||||
|
const fileFormat = url.split('.').pop() || 'unknown';
|
||||||
|
|
||||||
|
// 如果文件名包含扩展名,去掉扩展名(保持resourName不包含扩展名)
|
||||||
|
let resourName = displayName;
|
||||||
|
if (displayName.includes('.' + fileFormat)) {
|
||||||
|
resourName = displayName.replace('.' + fileFormat, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments.push({
|
||||||
|
id: `file_${index}`,
|
||||||
|
name: displayName, // 保持原始文件名(可能包含扩展名)
|
||||||
|
url: url,
|
||||||
|
resourUrl: url,
|
||||||
|
resourName: resourName, // 不包含扩展名的文件名
|
||||||
|
resSuf: fileFormat,
|
||||||
|
size: 0 // 无法从URL获取大小
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachments;
|
||||||
|
});
|
||||||
|
|
||||||
// 计算属性:是否有附件
|
// 计算属性:是否有附件
|
||||||
const hasAttachments = computed(() => {
|
const hasAttachments = computed(() => {
|
||||||
return gwInfo.value.fileUrl || (gwInfo.value.files && gwInfo.value.files.length > 0);
|
return parsedAttachments.value.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 计算属性:显示的抄送人列表
|
// 计算属性:显示的抄送人列表
|
||||||
@ -683,7 +726,13 @@ const getCurrentUserApproverId = (currentUserId: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 预览单个附件(从gwInfo直接获取)
|
// 预览单个附件(从gwInfo直接获取)
|
||||||
const previewSingleFile = () => {
|
const previewSingleFile = (event?: Event) => {
|
||||||
|
// 手动阻止事件冒泡
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
if (!gwInfo.value.fileUrl) {
|
if (!gwInfo.value.fileUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -706,69 +755,34 @@ const previewSingleFile = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 下载单个附件
|
// 下载单个附件
|
||||||
const downloadSingleFile = () => {
|
const downloadSingleFile = (event?: Event) => {
|
||||||
|
// 手动阻止事件冒泡
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
if (!gwInfo.value.fileUrl) {
|
if (!gwInfo.value.fileUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileUrl = imagUrl(gwInfo.value.fileUrl);
|
const finalUrl = imagUrl(gwInfo.value.fileUrl);
|
||||||
const fileName = gwInfo.value.fileName || '未知文件';
|
const fileName = gwInfo.value.fileName || '未知文件';
|
||||||
const fileFormat = gwInfo.value.fileFormat || '';
|
const fileFormat = gwInfo.value.fileFormat || '';
|
||||||
const fullFileName = fileFormat ? `${fileName}.${fileFormat}` : fileName;
|
const fullFileName = fileFormat ? `${fileName}.${fileFormat}` : fileName;
|
||||||
|
|
||||||
// 方法1: 使用 fetch 和 blob 方式强制下载
|
// 显示下载路径选择弹窗
|
||||||
fetch(fileUrl)
|
showDownloadPathModal(finalUrl, fullFileName);
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('网络请求失败');
|
|
||||||
}
|
|
||||||
return response.blob();
|
|
||||||
})
|
|
||||||
.then(blob => {
|
|
||||||
const downloadUrl = window.URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = downloadUrl;
|
|
||||||
link.download = fullFileName; // 使用 download 属性强制下载
|
|
||||||
link.style.display = 'none';
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
window.URL.revokeObjectURL(downloadUrl);
|
|
||||||
|
|
||||||
uni.showToast({
|
|
||||||
title: '开始下载',
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('fetch下载失败:', error);
|
|
||||||
// 方法2: 如果fetch失败,尝试直接打开链接
|
|
||||||
try {
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = fileUrl;
|
|
||||||
link.download = fullFileName;
|
|
||||||
link.target = '_blank';
|
|
||||||
link.style.display = 'none';
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
|
|
||||||
uni.showToast({
|
|
||||||
title: '开始下载',
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
} catch (fallbackError) {
|
|
||||||
console.error('备用下载也失败:', fallbackError);
|
|
||||||
uni.showToast({
|
|
||||||
title: '下载失败',
|
|
||||||
icon: 'error'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 文件预览
|
// 文件预览
|
||||||
const previewFile = (file: FileInfo) => {
|
const previewFile = (file: FileInfo, event?: Event) => {
|
||||||
|
// 手动阻止事件冒泡
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
// 确定文件URL和名称
|
// 确定文件URL和名称
|
||||||
const fileUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
const fileUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
||||||
const fileName = file.resourName ? `${file.resourName}.${file.resSuf}` : file.name;
|
const fileName = file.resourName ? `${file.resourName}.${file.resSuf}` : file.name;
|
||||||
@ -848,65 +862,22 @@ const handlePreviewImageSingle = (imageUrl: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 文件下载
|
// 文件下载 - 支持选择下载路径
|
||||||
const downloadFile = (file: FileInfo) => {
|
const downloadFileAction = (file: FileInfo, event?: Event) => {
|
||||||
downloadFileAction(file);
|
// 手动阻止事件冒泡
|
||||||
};
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
// 文件下载实现
|
event.preventDefault();
|
||||||
const downloadFileAction = (file: FileInfo) => {
|
|
||||||
const fileUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
|
||||||
const fileName = file.resourName ? `${file.resourName}.${file.resSuf}` : file.name;
|
|
||||||
|
|
||||||
// 方法1: 使用 fetch 和 blob 方式强制下载
|
|
||||||
fetch(fileUrl)
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('网络请求失败');
|
|
||||||
}
|
}
|
||||||
return response.blob();
|
|
||||||
})
|
|
||||||
.then(blob => {
|
|
||||||
const downloadUrl = window.URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = downloadUrl;
|
|
||||||
link.download = fileName; // 使用 download 属性强制下载
|
|
||||||
link.style.display = 'none';
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
window.URL.revokeObjectURL(downloadUrl);
|
|
||||||
|
|
||||||
uni.showToast({
|
const finalUrl = file.resourUrl ? imagUrl(file.resourUrl) : imagUrl(file.url);
|
||||||
title: '开始下载',
|
// 获取原始文件名
|
||||||
icon: 'success'
|
const originalFileName = getOriginalFileName(file);
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('fetch下载失败:', error);
|
|
||||||
// 方法2: 如果fetch失败,尝试直接打开链接
|
|
||||||
try {
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = fileUrl;
|
|
||||||
link.download = fileName;
|
|
||||||
link.target = '_blank';
|
|
||||||
link.style.display = 'none';
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
|
|
||||||
uni.showToast({
|
console.log('下载文件:', { finalUrl, originalFileName, file });
|
||||||
title: '开始下载',
|
|
||||||
icon: 'success'
|
// 显示下载路径选择弹窗
|
||||||
});
|
showDownloadPathModal(finalUrl, originalFileName);
|
||||||
} catch (fallbackError) {
|
|
||||||
console.error('备用下载也失败:', fallbackError);
|
|
||||||
uni.showToast({
|
|
||||||
title: '下载失败',
|
|
||||||
icon: 'error'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 格式化时间
|
// 格式化时间
|
||||||
@ -952,6 +923,31 @@ const getFileSuffix = (file: FileInfo) => {
|
|||||||
return 'unknown';
|
return 'unknown';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取文件图标
|
||||||
|
const getFileIcon = (fileType: string) => {
|
||||||
|
const type = fileType.toLowerCase();
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'pdf':
|
||||||
|
return '/static/base/view/pdf.png';
|
||||||
|
case 'doc':
|
||||||
|
case 'docx':
|
||||||
|
return '/static/base/view/word.png';
|
||||||
|
case 'xls':
|
||||||
|
case 'xlsx':
|
||||||
|
return '/static/base/view/excel.png';
|
||||||
|
case 'ppt':
|
||||||
|
case 'pptx':
|
||||||
|
return '/static/base/view/ppt.png';
|
||||||
|
case 'zip':
|
||||||
|
case 'rar':
|
||||||
|
case '7z':
|
||||||
|
return '/static/base/view/zip.png';
|
||||||
|
default:
|
||||||
|
return '/static/base/view/more.png';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 获取状态样式类
|
// 获取状态样式类
|
||||||
const getStatusClass = (status: any) => {
|
const getStatusClass = (status: any) => {
|
||||||
const statusMap: Record<string, string> = {
|
const statusMap: Record<string, string> = {
|
||||||
@ -1040,6 +1036,314 @@ const getUrgencyText = (level: string) => {
|
|||||||
return levelMap[level] || "未知";
|
return levelMap[level] || "未知";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取原始文件名
|
||||||
|
const getOriginalFileName = (file: FileInfo) => {
|
||||||
|
// 优先使用resourName,如果没有则使用name,确保文件名正确
|
||||||
|
let fileName = '';
|
||||||
|
if (file.resourName) {
|
||||||
|
// 如果resourName已经包含扩展名,直接使用
|
||||||
|
if (file.resSuf && !file.resourName.includes('.' + file.resSuf)) {
|
||||||
|
fileName = `${file.resourName}.${file.resSuf}`;
|
||||||
|
} else {
|
||||||
|
fileName = file.resourName;
|
||||||
|
}
|
||||||
|
} else if (file.name) {
|
||||||
|
// 如果name已经包含扩展名,直接使用
|
||||||
|
if (file.resSuf && !file.name.includes('.' + file.resSuf)) {
|
||||||
|
fileName = `${file.name}.${file.resSuf}`;
|
||||||
|
} else {
|
||||||
|
fileName = file.name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 最后备用方案,从URL提取文件名
|
||||||
|
const urlFileName = file.url.split('/').pop() || '未知文件';
|
||||||
|
fileName = urlFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示下载路径选择弹窗
|
||||||
|
const showDownloadPathModal = (url: string, fileName: string) => {
|
||||||
|
downloadUrl.value = url;
|
||||||
|
downloadFileName.value = fileName;
|
||||||
|
showDownloadModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认下载
|
||||||
|
const confirmDownload = () => {
|
||||||
|
// 设置下载状态
|
||||||
|
isDownloading.value = true;
|
||||||
|
|
||||||
|
// 检查当前平台
|
||||||
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
const { platform } = systemInfo;
|
||||||
|
|
||||||
|
// 备用检测方法
|
||||||
|
const isH5 = platform === 'web' || typeof window !== 'undefined';
|
||||||
|
|
||||||
|
console.log('平台检测:', { platform, systemInfo, isH5 });
|
||||||
|
|
||||||
|
if (isH5) {
|
||||||
|
console.log('使用H5下载方式');
|
||||||
|
// H5环境下使用直接链接下载,避免跨域问题
|
||||||
|
downloadForH5(downloadUrl.value, downloadFileName.value);
|
||||||
|
} else {
|
||||||
|
console.log('使用原生下载方式');
|
||||||
|
// 原生环境下使用原有下载方式
|
||||||
|
downloadFile(downloadUrl.value, downloadFileName.value)
|
||||||
|
.then(() => {
|
||||||
|
// 下载成功后关闭弹窗
|
||||||
|
isDownloading.value = false;
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: "下载成功",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('下载失败:', error);
|
||||||
|
// 下载失败后也关闭弹窗
|
||||||
|
isDownloading.value = false;
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: "下载失败",
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// H5环境下的下载方法
|
||||||
|
const downloadForH5 = (url: string, fileName: string) => {
|
||||||
|
try {
|
||||||
|
console.log('H5下载开始:', { url, fileName });
|
||||||
|
|
||||||
|
// 直接使用强制下载方式,避免打开文件
|
||||||
|
forceDownload(url, fileName);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('H5下载失败:', error);
|
||||||
|
// 如果整个方法失败,回退到直接链接方式
|
||||||
|
fallbackDownload(url, fileName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 强制下载方法
|
||||||
|
const forceDownload = (url: string, fileName: string) => {
|
||||||
|
try {
|
||||||
|
console.log('尝试强制下载:', { url, fileName });
|
||||||
|
|
||||||
|
// 方法1: 使用fetch下载文件内容,然后创建blob下载
|
||||||
|
fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
mode: 'cors',
|
||||||
|
cache: 'no-cache'
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.blob();
|
||||||
|
})
|
||||||
|
.then(blob => {
|
||||||
|
console.log('文件下载成功,创建blob下载');
|
||||||
|
|
||||||
|
// 创建blob URL
|
||||||
|
const blobUrl = window.URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = blobUrl;
|
||||||
|
link.download = fileName;
|
||||||
|
link.style.display = 'none';
|
||||||
|
|
||||||
|
// 添加到DOM并触发点击
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
// 清理DOM和blob URL
|
||||||
|
document.body.removeChild(link);
|
||||||
|
window.URL.revokeObjectURL(blobUrl);
|
||||||
|
|
||||||
|
// 下载成功后关闭弹窗
|
||||||
|
isDownloading.value = false;
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: "下载成功",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Fetch下载失败,尝试其他方法:', error);
|
||||||
|
// 如果fetch失败,尝试其他方法
|
||||||
|
tryAlternativeDownload(url, fileName);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('强制下载失败,尝试其他方法:', error);
|
||||||
|
tryAlternativeDownload(url, fileName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 尝试替代下载方法
|
||||||
|
const tryAlternativeDownload = (url: string, fileName: string) => {
|
||||||
|
console.log('尝试替代下载方法');
|
||||||
|
|
||||||
|
// 方法1: 使用XMLHttpRequest下载
|
||||||
|
try {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, true);
|
||||||
|
xhr.responseType = 'blob';
|
||||||
|
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const blob = xhr.response;
|
||||||
|
const blobUrl = window.URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = blobUrl;
|
||||||
|
link.download = fileName;
|
||||||
|
link.style.display = 'none';
|
||||||
|
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
window.URL.revokeObjectURL(blobUrl);
|
||||||
|
|
||||||
|
// 下载成功后关闭弹窗
|
||||||
|
isDownloading.value = false;
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: "下载成功",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('XMLHttpRequest下载成功');
|
||||||
|
} else {
|
||||||
|
throw new Error(`HTTP error! status: ${xhr.status}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = function() {
|
||||||
|
console.error('XMLHttpRequest下载失败');
|
||||||
|
console.log('调用手动下载提示');
|
||||||
|
showManualDownloadModal(url, fileName);
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('XMLHttpRequest失败:', error);
|
||||||
|
console.log('调用手动下载提示(catch)');
|
||||||
|
showManualDownloadModal(url, fileName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示手动下载提示
|
||||||
|
const showManualDownloadModal = (url: string, fileName: string) => {
|
||||||
|
console.log('尝试原生下载');
|
||||||
|
|
||||||
|
// 尝试使用浏览器原生下载
|
||||||
|
try {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = fileName;
|
||||||
|
link.target = '_blank';
|
||||||
|
link.style.display = 'none';
|
||||||
|
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
console.log('原生下载已触发');
|
||||||
|
|
||||||
|
// 延迟关闭弹窗,给用户时间看到下载开始
|
||||||
|
setTimeout(() => {
|
||||||
|
isDownloading.value = false;
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: "开始下载",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('原生下载失败:', error);
|
||||||
|
// 下载失败也关闭弹窗
|
||||||
|
isDownloading.value = false;
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: "下载失败",
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 直接下载方法
|
||||||
|
const directDownload = (url: string, fileName: string) => {
|
||||||
|
try {
|
||||||
|
// 修改URL添加下载参数
|
||||||
|
const downloadUrl = url.includes('?')
|
||||||
|
? `${url}&download=1&attachment=1`
|
||||||
|
: `${url}?download=1&attachment=1`;
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = downloadUrl;
|
||||||
|
link.download = fileName;
|
||||||
|
link.target = '_self'; // 使用_self而不是_blank
|
||||||
|
link.style.display = 'none';
|
||||||
|
|
||||||
|
// 添加到DOM并触发点击
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
// 清理DOM
|
||||||
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: "开始下载",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('直接下载失败:', error);
|
||||||
|
// 最后的方法:提示用户手动下载
|
||||||
|
uni.showModal({
|
||||||
|
title: '下载提示',
|
||||||
|
content: `由于浏览器限制,无法自动下载文件。请长按链接手动保存:\n${url}`,
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '知道了'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 备用下载方法
|
||||||
|
const fallbackDownload = (url: string, fileName: string) => {
|
||||||
|
try {
|
||||||
|
console.log('使用备用下载方法');
|
||||||
|
|
||||||
|
// 使用直接下载方法
|
||||||
|
directDownload(url, fileName);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('备用下载也失败:', error);
|
||||||
|
// 最后的方法:提示用户手动下载
|
||||||
|
uni.showModal({
|
||||||
|
title: '下载提示',
|
||||||
|
content: `由于浏览器限制,无法自动下载文件。请长按链接手动保存:\n${url}`,
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '知道了'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消下载
|
||||||
|
const cancelDownload = () => {
|
||||||
|
showDownloadModal.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
// 获取创建人名称
|
// 获取创建人名称
|
||||||
const getCreatorName = (tjrId: string) => {
|
const getCreatorName = (tjrId: string) => {
|
||||||
if (!tjrId) return "未知";
|
if (!tjrId) return "未知";
|
||||||
@ -1232,9 +1536,16 @@ onMounted(() => {
|
|||||||
|
|
||||||
.file-icon {
|
.file-icon {
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
font-size: 24px;
|
|
||||||
width: 32px;
|
width: 32px;
|
||||||
text-align: center;
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.icon-image {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-info {
|
.file-info {
|
||||||
@ -1524,4 +1835,121 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.download-modal {
|
||||||
|
width: 85vw;
|
||||||
|
max-width: 450px;
|
||||||
|
padding: 20px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
.download-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
|
||||||
|
.download-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-content {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
|
||||||
|
.file-info-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.file-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #666;
|
||||||
|
margin-right: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
color: #333;
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-all;
|
||||||
|
flex: 1;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-info-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.path-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #666;
|
||||||
|
margin-right: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-text {
|
||||||
|
color: #007aff;
|
||||||
|
font-size: 14px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-tips {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.tips-text {
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.u-button {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-progress {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
|
||||||
|
.progress-spinner {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border: 2px solid #f3f3f3;
|
||||||
|
border-top: 2px solid #007aff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -79,7 +79,11 @@
|
|||||||
@click="previewAttachmentFile(file)"
|
@click="previewAttachmentFile(file)"
|
||||||
>
|
>
|
||||||
<view class="attachment-icon">
|
<view class="attachment-icon">
|
||||||
<text>📄</text>
|
<image
|
||||||
|
:src="getFileIcon(getFileSuffix(file))"
|
||||||
|
class="icon-image"
|
||||||
|
mode="aspectFit"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
<text class="attachment-name">{{ getFileName(file) }}</text>
|
<text class="attachment-name">{{ getFileName(file) }}</text>
|
||||||
</view>
|
</view>
|
||||||
@ -529,6 +533,30 @@ const getFileSuffix = (file: FileInfo) => {
|
|||||||
return 'unknown';
|
return 'unknown';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取文件图标
|
||||||
|
const getFileIcon = (fileType: string) => {
|
||||||
|
const type = fileType.toLowerCase();
|
||||||
|
switch (type) {
|
||||||
|
case 'pdf':
|
||||||
|
return '/static/base/view/pdf.png';
|
||||||
|
case 'doc':
|
||||||
|
case 'docx':
|
||||||
|
return '/static/base/view/word.png';
|
||||||
|
case 'xls':
|
||||||
|
case 'xlsx':
|
||||||
|
return '/static/base/view/excel.png';
|
||||||
|
case 'ppt':
|
||||||
|
case 'pptx':
|
||||||
|
return '/static/base/view/ppt.png';
|
||||||
|
case 'zip':
|
||||||
|
case 'rar':
|
||||||
|
case '7z':
|
||||||
|
return '/static/base/view/zip.png';
|
||||||
|
default:
|
||||||
|
return '/static/base/view/more.png';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 监听数据变化
|
// 监听数据变化
|
||||||
watch(dataList, (val) => {
|
watch(dataList, (val) => {
|
||||||
// 数据变化监听
|
// 数据变化监听
|
||||||
@ -810,8 +838,17 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.attachment-icon {
|
.attachment-icon {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
font-size: 16px;
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.icon-image {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachment-name {
|
.attachment-name {
|
||||||
|
|||||||
@ -174,6 +174,9 @@ let inspectionParams = ref({
|
|||||||
rows: 10,
|
rows: 10,
|
||||||
kyXcId: xkkc.value.id,
|
kyXcId: xkkc.value.id,
|
||||||
jsId: js.value.id,
|
jsId: js.value.id,
|
||||||
|
njId: xkkc.value.njId,
|
||||||
|
bjId: xkkc.value.bjId,
|
||||||
|
njmcId: xkkc.value.njmcId,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 巡查记录列表
|
// 巡查记录列表
|
||||||
|
|||||||
@ -269,6 +269,7 @@ const goXc = (xkkc: any) => {
|
|||||||
...xkkc,
|
...xkkc,
|
||||||
id: xkkc.id, // 课程记录ID
|
id: xkkc.id, // 课程记录ID
|
||||||
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
|
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
|
||||||
|
pbJsId: xkkc.id, // 将课程记录ID作为pbJsId传递
|
||||||
xclx: pbData.xclx,
|
xclx: pbData.xclx,
|
||||||
xcbt: pbData.xcbt,
|
xcbt: pbData.xcbt,
|
||||||
xqmc: pbData.xqmc,
|
xqmc: pbData.xqmc,
|
||||||
|
|||||||
@ -521,6 +521,7 @@ const submit = async () => {
|
|||||||
njId: xkkc.value.njId || '', // 确保年级ID不为空
|
njId: xkkc.value.njId || '', // 确保年级ID不为空
|
||||||
njmcId: xkkc.value.njmcId || '', // 确保年级名称ID不为空
|
njmcId: xkkc.value.njmcId || '', // 确保年级名称ID不为空
|
||||||
bjId: xkkc.value.bjId || '', // 确保班级ID不为空
|
bjId: xkkc.value.bjId || '', // 确保班级ID不为空
|
||||||
|
pbJsId: xkkc.value.pbJsId || xkkc.value.id, // 使用传递的pbJsId或课程记录ID
|
||||||
xctime: now.format("YYYY-MM-DD HH:mm:ss"),
|
xctime: now.format("YYYY-MM-DD HH:mm:ss"),
|
||||||
zp: getImageUrls(),
|
zp: getImageUrls(),
|
||||||
sp: getVideoUrls(),
|
sp: getVideoUrls(),
|
||||||
|
|||||||
BIN
src/static/base/view/excel.png
Normal file
BIN
src/static/base/view/excel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src/static/base/view/pdf.png
Normal file
BIN
src/static/base/view/pdf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
src/static/base/view/ppt.png
Normal file
BIN
src/static/base/view/ppt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
BIN
src/static/base/view/word.png
Normal file
BIN
src/static/base/view/word.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
BIN
src/static/base/view/zip.png
Normal file
BIN
src/static/base/view/zip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Loading…
x
Reference in New Issue
Block a user