|
|
@@ -519,6 +519,28 @@
|
|
|
@select="handleUploadActionSelect"
|
|
|
@close="showUploadActionSheet = false"
|
|
|
></u-action-sheet>
|
|
|
+
|
|
|
+ <!-- 删除违纪记录确认对话框 -->
|
|
|
+ <u-modal
|
|
|
+ :show="showDeleteConfirm"
|
|
|
+ title="确认删除"
|
|
|
+ content="确认删除这条违纪记录吗?"
|
|
|
+ :show-cancel-button="true"
|
|
|
+ confirm-color="#ff5722"
|
|
|
+ @confirm="confirmDeleteViolation"
|
|
|
+ @cancel="cancelDeleteViolation"
|
|
|
+ ></u-modal>
|
|
|
+
|
|
|
+ <!-- 删除附件确认对话框 -->
|
|
|
+ <u-modal
|
|
|
+ :show="showDeleteImageConfirm"
|
|
|
+ title="确认删除"
|
|
|
+ content="确定要删除这张图片吗?删除后无法恢复。"
|
|
|
+ :show-cancel-button="true"
|
|
|
+ confirm-color="#ff5722"
|
|
|
+ @confirm="confirmDeleteImage"
|
|
|
+ @cancel="cancelDeleteImage"
|
|
|
+ ></u-modal>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
@@ -590,6 +612,11 @@ export default {
|
|
|
currentViolation: null,
|
|
|
currentViolationIndex: -1,
|
|
|
|
|
|
+ // 删除违纪记录确认对话框
|
|
|
+ showDeleteConfirm: false,
|
|
|
+ deleteViolationStudentId: null,
|
|
|
+ deleteViolationIndex: -1,
|
|
|
+
|
|
|
// 附件数据
|
|
|
attachmentList: [],
|
|
|
|
|
|
@@ -601,6 +628,10 @@ export default {
|
|
|
// 附件上传操作选择框
|
|
|
showUploadActionSheet: false,
|
|
|
uploadActions: [{ name: '选择图片' }],
|
|
|
+
|
|
|
+ // 删除附件确认弹窗
|
|
|
+ showDeleteImageConfirm: false,
|
|
|
+ deleteImageTarget: null,
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -712,6 +743,10 @@ export default {
|
|
|
await this.checkWechatEnvironment();
|
|
|
this.initComponent();
|
|
|
},
|
|
|
+ beforeDestroy() {
|
|
|
+ // 清理blob URL,防止内存泄漏
|
|
|
+ this.cleanupBlobUrls();
|
|
|
+ },
|
|
|
methods: {
|
|
|
// 检查微信环境并自动初始化SDK
|
|
|
async checkWechatEnvironment() {
|
|
|
@@ -881,9 +916,425 @@ export default {
|
|
|
},
|
|
|
|
|
|
// 加载编辑数据
|
|
|
- loadEditData() {
|
|
|
- // TODO: 加载现有检查数据进行编辑
|
|
|
- console.log('加载编辑数据:', this.existingData);
|
|
|
+ async loadEditData() {
|
|
|
+ console.log('📝 加载编辑数据:', this.existingData);
|
|
|
+
|
|
|
+ if (!this.existingData) {
|
|
|
+ console.warn('⚠️ 没有现有数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 1️⃣ 回显表单基础数据
|
|
|
+ this.formData.disciplineTypeId = this.existingData.disciplineTypeId || null;
|
|
|
+ this.formData.disciplineTypeName = this.existingData.disciplineTypeName || '';
|
|
|
+ this.formData.totalScore = this.existingData.totalScore || 0;
|
|
|
+ this.formData.hygieneGrade = this.existingData.hygieneGrade || 'A';
|
|
|
+ this.formData.checkRemarks = this.existingData.checkRemarks || '';
|
|
|
+ this.formData.attachmentIds = this.existingData.attachmentIds || '';
|
|
|
+
|
|
|
+ console.log('✅ 表单基础数据回显完成:', this.formData);
|
|
|
+
|
|
|
+ // 2️⃣ 回显附件数据
|
|
|
+ if (this.existingData.attachmentIds) {
|
|
|
+ await this.loadAttachments(this.existingData.attachmentIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3️⃣ 从后端接口加载学生评分数据、违纪记录和请假信息(复用Web端接口)
|
|
|
+ // 注意:loadStudentScoresFromAPI 内部会自动调用 loadViolationRecordsFromAPI 和 loadStudentLeaves
|
|
|
+ if (this.existingData.id) {
|
|
|
+ await this.loadStudentScoresFromAPI(this.existingData.id);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('✅ 所有数据回显完成');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 加载编辑数据失败:', error);
|
|
|
+ uni.showToast({ title: '加载数据失败', icon: 'none' });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 从后端API加载学生评分数据(复用Web端接口)
|
|
|
+ async loadStudentScoresFromAPI(checkId) {
|
|
|
+ if (!checkId) {
|
|
|
+ console.warn('⚠️ 没有检查ID,无法加载学生评分数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.studentsLoading = true;
|
|
|
+ try {
|
|
|
+ console.log('🔄 从API加载学生评分数据,检查ID:', checkId);
|
|
|
+
|
|
|
+ const res = await request({
|
|
|
+ url: `/dormHygieneStudentScore/dormHygieneStudentScore/getByCheckId/${checkId}`,
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.code === 200 && res.data && res.data.length > 0) {
|
|
|
+ console.log('✅ 成功获取学生评分数据:', res.data.length, '条');
|
|
|
+
|
|
|
+ // 将后端返回的学生评分数据映射到roomStudents
|
|
|
+ this.roomStudents = res.data.map((studentScore) => ({
|
|
|
+ // 学生基本信息
|
|
|
+ studentId: studentScore.studentId,
|
|
|
+ studentName: studentScore.studentName,
|
|
|
+ studentNo: studentScore.studentNo,
|
|
|
+ className: studentScore.className,
|
|
|
+ majorName: studentScore.majorName,
|
|
|
+ collegeName: studentScore.collegeName,
|
|
|
+ bedId: studentScore.bedId,
|
|
|
+ bedName: studentScore.bedCode,
|
|
|
+ bedCode: studentScore.bedCode,
|
|
|
+ gender: studentScore.gender || '1',
|
|
|
+ // 评分数据
|
|
|
+ student_score: studentScore.studentScore || 0,
|
|
|
+ attendance_status: studentScore.attendanceStatus || '1',
|
|
|
+ student_grade: studentScore.studentGrade || 'A',
|
|
|
+ isResponsiblePerson: studentScore.isResponsiblePerson || 0,
|
|
|
+ scoreRemarks: studentScore.scoreRemarks || '',
|
|
|
+ improvementNotes: studentScore.improvementNotes || '',
|
|
|
+ // UI状态
|
|
|
+ showAttendancePicker: false,
|
|
|
+ showGradePicker: false,
|
|
|
+ }));
|
|
|
+
|
|
|
+ console.log('✅ 学生评分数据映射完成');
|
|
|
+
|
|
|
+ // 🔴 同时加载违纪记录和请假信息(复用Web端逻辑)
|
|
|
+ await Promise.all([
|
|
|
+ this.loadViolationRecordsFromAPI(checkId),
|
|
|
+ this.loadStudentLeaves(),
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ console.warn('⚠️ 未获取到学生评分数据,保持当前学生列表');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 加载学生评分数据失败:', error);
|
|
|
+ uni.showToast({ title: '加载学生评分数据失败', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ this.studentsLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 从后端API加载违纪记录数据(复用Web端接口)
|
|
|
+ async loadViolationRecordsFromAPI(checkId) {
|
|
|
+ if (!checkId) {
|
|
|
+ console.warn('⚠️ 没有检查ID,无法加载违纪记录数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ console.log('🔄 从API加载违纪记录数据,检查ID:', checkId);
|
|
|
+
|
|
|
+ const res = await request({
|
|
|
+ url: `/dormHygieneCheck/dormHygieneCheck/getViolations/${checkId}`,
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ console.log('✅ 成功获取违纪记录数据:', res.data.length, '条');
|
|
|
+
|
|
|
+ // 清空现有违纪记录
|
|
|
+ this.violationRecords.clear();
|
|
|
+
|
|
|
+ // 按学生ID分组违纪记录
|
|
|
+ res.data.forEach((violation) => {
|
|
|
+ const studentId = violation.studentId;
|
|
|
+ if (!studentId) return;
|
|
|
+
|
|
|
+ const violations = this.violationRecords.get(studentId) || [];
|
|
|
+ violations.push({
|
|
|
+ disciplineTypeId: violation.disciplineTypeId,
|
|
|
+ disciplineTypeName: violation.disciplineTypeName,
|
|
|
+ scoreDeduction: violation.scoreDeduction,
|
|
|
+ violationDescription:
|
|
|
+ violation.disciplineContent || violation.disciplineReason || '',
|
|
|
+ // 🔴 统一使用 attachmentOssIds 字段名
|
|
|
+ attachmentOssIds: violation.attachmentOssIds || '',
|
|
|
+ });
|
|
|
+
|
|
|
+ this.violationRecords.set(studentId, violations);
|
|
|
+ console.log(
|
|
|
+ `✅ 学生ID ${studentId} 违纪记录加载完成,数量:`,
|
|
|
+ violations.length,
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log(
|
|
|
+ '✅ 所有违纪记录数据加载完成,总学生数:',
|
|
|
+ this.violationRecords.size,
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ console.warn('⚠️ 未获取到违纪记录数据');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 加载违纪记录数据失败:', error);
|
|
|
+ // 不显示错误提示,因为可能确实没有违纪记录
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载附件数据
|
|
|
+ async loadAttachments(attachmentIds) {
|
|
|
+ if (!attachmentIds) {
|
|
|
+ console.log('📎 没有附件数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ console.log('📎 开始加载附件数据, IDs:', attachmentIds);
|
|
|
+
|
|
|
+ const ossIds = attachmentIds.toString().trim();
|
|
|
+ const response = await request({
|
|
|
+ url: `/resource/oss/listByIds/${ossIds}`,
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response.code === 200 && response.data) {
|
|
|
+ console.log('📎 附件数据加载成功,数量:', response.data.length);
|
|
|
+
|
|
|
+ const attachmentFiles = response.data.map((item, index) => {
|
|
|
+ // 使用fileSuffix字段判断文件类型
|
|
|
+ const fileType = this.getFileTypeBySuffix(item.fileSuffix);
|
|
|
+ const isImage = this.isImageFile({
|
|
|
+ name: item.originalName,
|
|
|
+ type: fileType,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 处理图片URL - 确保有正确的API前缀
|
|
|
+ let processedUrl = item.url;
|
|
|
+ if (isImage && item.url && item.url.startsWith('/resource/')) {
|
|
|
+ // 图片文件需要添加/api前缀
|
|
|
+ processedUrl = `/api${item.url}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构造完整的文件名(包含扩展名)
|
|
|
+ let fullFileName = item.originalName || `附件${index + 1}`;
|
|
|
+ if (
|
|
|
+ item.fileSuffix &&
|
|
|
+ !fullFileName
|
|
|
+ .toLowerCase()
|
|
|
+ .endsWith(`.${item.fileSuffix.toLowerCase()}`)
|
|
|
+ ) {
|
|
|
+ fullFileName = `${fullFileName}.${item.fileSuffix}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ const fileObj = {
|
|
|
+ uid: `existing_${index}_${Date.now()}`,
|
|
|
+ name: fullFileName,
|
|
|
+ url: processedUrl,
|
|
|
+ ossId: item.ossId,
|
|
|
+ status: 'success',
|
|
|
+ type: fileType,
|
|
|
+ size: item.fileSize || 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log(`📎 附件${index + 1}:`, fileObj);
|
|
|
+ return fileObj;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.attachmentList = attachmentFiles;
|
|
|
+
|
|
|
+ // 为图片文件获取blob数据以确保正确显示
|
|
|
+ await this.processImageFiles();
|
|
|
+
|
|
|
+ // 强制刷新组件显示
|
|
|
+ this.$nextTick(() => {
|
|
|
+ // 预加载图片以确保能正确显示
|
|
|
+ this.preloadImages();
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('✅ 附件数据处理完成');
|
|
|
+ } else {
|
|
|
+ console.warn('⚠️ 获取附件信息失败:', response.msg);
|
|
|
+ this.attachmentList = [];
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 获取附件失败:', error);
|
|
|
+ this.attachmentList = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 根据文件后缀获取文件类型
|
|
|
+ getFileTypeBySuffix(fileSuffix) {
|
|
|
+ if (!fileSuffix) return '';
|
|
|
+
|
|
|
+ // 移除点号,转换为小写
|
|
|
+ const ext = fileSuffix.replace('.', '').toLowerCase();
|
|
|
+
|
|
|
+ const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
|
|
|
+ if (imageTypes.includes(ext)) {
|
|
|
+ const mimeTypeMap = {
|
|
|
+ jpg: 'image/jpeg',
|
|
|
+ jpeg: 'image/jpeg',
|
|
|
+ png: 'image/png',
|
|
|
+ gif: 'image/gif',
|
|
|
+ bmp: 'image/bmp',
|
|
|
+ webp: 'image/webp',
|
|
|
+ };
|
|
|
+ return mimeTypeMap[ext] || `image/${ext}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 其他文件类型
|
|
|
+ const docTypes = {
|
|
|
+ pdf: 'application/pdf',
|
|
|
+ doc: 'application/msword',
|
|
|
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
+ xls: 'application/vnd.ms-excel',
|
|
|
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
|
+ };
|
|
|
+
|
|
|
+ return docTypes[ext] || `file/${ext}`;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理图片文件,获取blob数据以确保正确显示
|
|
|
+ async processImageFiles() {
|
|
|
+ console.log('=== 处理图片文件 ===');
|
|
|
+ const imageFiles = this.attachmentList.filter((file) => this.isImageFile(file));
|
|
|
+
|
|
|
+ for (const file of imageFiles) {
|
|
|
+ if (file.url && !file.blobUrl) {
|
|
|
+ try {
|
|
|
+ console.log(`处理图片文件: ${file.name}`);
|
|
|
+ const blobUrl = await this.getImageBlobUrl(file.url);
|
|
|
+ if (blobUrl) {
|
|
|
+ // 更新文件对象,添加blob URL,并标记为图片
|
|
|
+ file.blobUrl = blobUrl;
|
|
|
+ file.url = blobUrl; // 🔴 关键:使用blob URL作为显示URL,解决灰白背景问题
|
|
|
+ file.fileType = 'image';
|
|
|
+ file.type =
|
|
|
+ file.type && file.type.startsWith('image') ? file.type : 'image';
|
|
|
+ file.isImage = true;
|
|
|
+ console.log(`图片文件处理成功: ${file.name} - ${blobUrl}`);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`处理图片文件失败: ${file.name}`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取图片blob URL
|
|
|
+ async getImageBlobUrl(imageUrl) {
|
|
|
+ try {
|
|
|
+ console.log(`获取图片blob数据: ${imageUrl}`);
|
|
|
+
|
|
|
+ // 处理图片URL路径
|
|
|
+ let apiUrl = imageUrl;
|
|
|
+ if (imageUrl.startsWith('/api/')) {
|
|
|
+ // 移除/api前缀,因为request会自动添加baseURL
|
|
|
+ apiUrl = imageUrl.replace('/api', '');
|
|
|
+ } else if (imageUrl.startsWith('/resource/')) {
|
|
|
+ // 直接使用相对路径
|
|
|
+ apiUrl = imageUrl;
|
|
|
+ } else if (imageUrl.startsWith('http')) {
|
|
|
+ // 完整URL,需要特殊处理
|
|
|
+ console.log('检测到完整URL,直接返回原URL');
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(`API请求URL: ${apiUrl}`);
|
|
|
+
|
|
|
+ // 使用request方法获取图片数据
|
|
|
+ const response = await request({
|
|
|
+ url: apiUrl,
|
|
|
+ method: 'GET',
|
|
|
+ responseType: 'arraybuffer', // 设置响应类型为arraybuffer
|
|
|
+ header: {
|
|
|
+ isToken: true,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将arraybuffer转换为blob
|
|
|
+ const blob = new Blob([response], { type: 'image/*' });
|
|
|
+ const blobUrl = URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ console.log(`成功创建blob URL: ${blobUrl}`);
|
|
|
+ return blobUrl;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`获取图片blob数据失败: ${imageUrl}`, error);
|
|
|
+ // 如果请求失败,返回原始URL作为备用方案
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 预加载图片以确保能正确显示
|
|
|
+ async preloadImages() {
|
|
|
+ console.log('=== 预加载图片 ===');
|
|
|
+ const imageFiles = this.attachmentList.filter((file) => this.isImageFile(file));
|
|
|
+
|
|
|
+ for (const file of imageFiles) {
|
|
|
+ if (file.blobUrl || file.url) {
|
|
|
+ try {
|
|
|
+ const imgUrl = file.blobUrl || file.url;
|
|
|
+ console.log(`预加载图片: ${file.name} - ${imgUrl}`);
|
|
|
+ // 注意:在uni-app中,可能需要使用不同的预加载方式
|
|
|
+ // 这里只是简单的日志记录,实际预加载由image标签自动完成
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`预加载图片失败: ${file.name}`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 回显学生评分数据
|
|
|
+ loadStudentScores(studentScores) {
|
|
|
+ console.log('👥 回显学生评分数据:', studentScores);
|
|
|
+
|
|
|
+ studentScores.forEach((scoreData) => {
|
|
|
+ const student = this.roomStudents.find((s) => s.studentId === scoreData.studentId);
|
|
|
+ if (student) {
|
|
|
+ student.student_score = scoreData.studentScore || 0;
|
|
|
+ student.attendance_status = scoreData.attendanceStatus || '1';
|
|
|
+ student.student_grade = scoreData.studentGrade || 'A';
|
|
|
+ student.scoreRemarks = scoreData.scoreRemarks || '';
|
|
|
+ student.improvementNotes = scoreData.improvementNotes || '';
|
|
|
+ console.log(`✅ 学生 ${student.studentName} 评分数据回显完成`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 回显违纪记录数据
|
|
|
+ loadViolationRecords(violationData) {
|
|
|
+ console.log('⚠️ 回显违纪记录数据:', violationData);
|
|
|
+
|
|
|
+ this.violationRecords.clear();
|
|
|
+
|
|
|
+ violationData.forEach((violation) => {
|
|
|
+ const studentId = violation.studentId;
|
|
|
+ if (!studentId) return;
|
|
|
+
|
|
|
+ const violations = this.violationRecords.get(studentId) || [];
|
|
|
+ violations.push({
|
|
|
+ disciplineTypeId: violation.disciplineTypeId,
|
|
|
+ disciplineTypeName: violation.disciplineTypeName,
|
|
|
+ scoreDeduction: violation.scoreDeduction,
|
|
|
+ violationDescription: violation.violationDescription,
|
|
|
+ // 🔴 修复字段名不一致问题:统一使用 attachmentOssIds
|
|
|
+ // 兼容后端可能返回的两种字段名
|
|
|
+ attachmentOssIds:
|
|
|
+ violation.violationAttachmentIds || violation.attachmentOssIds || '',
|
|
|
+ });
|
|
|
+
|
|
|
+ this.violationRecords.set(studentId, violations);
|
|
|
+ console.log(
|
|
|
+ `✅ 学生ID ${studentId} 违纪记录回显完成,附件IDs:`,
|
|
|
+ violation.violationAttachmentIds || violation.attachmentOssIds,
|
|
|
+ );
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清理blob URL,防止内存泄漏
|
|
|
+ cleanupBlobUrls() {
|
|
|
+ console.log('=== 清理blob URL ===');
|
|
|
+ this.attachmentList.forEach((file) => {
|
|
|
+ if (file.blobUrl && file.blobUrl.startsWith('blob:')) {
|
|
|
+ try {
|
|
|
+ URL.revokeObjectURL(file.blobUrl);
|
|
|
+ console.log(`已清理blob URL: ${file.name}`);
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`清理blob URL失败: ${file.name}`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
},
|
|
|
|
|
|
// 违纪类型确认处理
|
|
|
@@ -1150,39 +1601,109 @@ export default {
|
|
|
// 上传文件到服务器
|
|
|
async uploadFileToServer(file) {
|
|
|
try {
|
|
|
+ console.log('🚀 === 开始上传文件到服务器 ===');
|
|
|
+ console.log('📁 待上传文件对象:', file);
|
|
|
+ console.log('📁 文件对象属性:', Object.keys(file));
|
|
|
+
|
|
|
+ // 更新文件状态
|
|
|
file.status = 'uploading';
|
|
|
|
|
|
// 🔴 关键修复:保存原始文件名,防止被后端UUID覆盖
|
|
|
const originalName = file.name;
|
|
|
console.log('📝 上传前文件名:', originalName);
|
|
|
|
|
|
+ // 确定正确的文件路径 - uview2通常使用url属性
|
|
|
+ const filePath = file.url || file.tempFilePath || file.path;
|
|
|
+ console.log('🎯 文件路径优先级选择:', {
|
|
|
+ url: file.url,
|
|
|
+ tempFilePath: file.tempFilePath,
|
|
|
+ path: file.path,
|
|
|
+ selected: filePath,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!filePath) {
|
|
|
+ const error = new Error('文件路径不存在');
|
|
|
+ console.error('❌ 上传失败 - 文件路径为空:', file);
|
|
|
+ file.status = 'error';
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示上传进度
|
|
|
+ uni.showLoading({
|
|
|
+ title: `上传${file.name}...`,
|
|
|
+ mask: true,
|
|
|
+ });
|
|
|
+ console.log(`💫 开始上传文件: ${file.name}`);
|
|
|
+
|
|
|
+ // 调用智能上传API(自动适配微信环境)
|
|
|
+ console.log('📡 调用智能上传API...');
|
|
|
const response = await smartUploadFile('/resource/oss/upload', file, {
|
|
|
bizType: 'dorm_hygiene_check_attachment',
|
|
|
});
|
|
|
|
|
|
- console.log('📡 上传响应:', response);
|
|
|
- console.log('🔍 上传后file.name:', file.name);
|
|
|
+ console.log('📡 上传API响应:', response);
|
|
|
+ uni.hideLoading();
|
|
|
|
|
|
if (response && response.code === 200) {
|
|
|
+ // 上传成功
|
|
|
file.url = response.data.url;
|
|
|
file.ossId = response.data.ossId;
|
|
|
file.status = 'success';
|
|
|
// 🔴 恢复原始文件名,不使用后端返回的fileName(UUID)
|
|
|
file.name = originalName;
|
|
|
- console.log('✅ 恢复文件名为:', file.name);
|
|
|
- uni.showToast({ title: '上传成功', icon: 'success', duration: 1500 });
|
|
|
+
|
|
|
+ console.log('✅ 文件上传成功:', {
|
|
|
+ fileName: file.name,
|
|
|
+ ossId: file.ossId,
|
|
|
+ url: file.url,
|
|
|
+ });
|
|
|
+
|
|
|
+ uni.showToast({
|
|
|
+ title: '上传成功',
|
|
|
+ icon: 'success',
|
|
|
+ duration: 1500,
|
|
|
+ });
|
|
|
+
|
|
|
+ return response;
|
|
|
} else {
|
|
|
+ // 上传失败
|
|
|
file.status = 'error';
|
|
|
+ const errorMsg = (response && response.msg) || '上传失败';
|
|
|
+ console.error('❌ 上传失败 - API返回错误:', {
|
|
|
+ response: response,
|
|
|
+ fileName: file.name,
|
|
|
+ errorMsg: errorMsg,
|
|
|
+ });
|
|
|
+
|
|
|
uni.showToast({
|
|
|
- title: (response && response.msg) || '上传失败',
|
|
|
+ title: errorMsg,
|
|
|
icon: 'none',
|
|
|
- duration: 2000,
|
|
|
+ duration: 3000,
|
|
|
});
|
|
|
+
|
|
|
+ throw new Error(errorMsg);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- console.error('上传文件失败:', error);
|
|
|
+ console.error('❌ 上传文件失败:', error);
|
|
|
file.status = 'error';
|
|
|
- uni.showToast({ title: '上传失败', icon: 'none', duration: 2000 });
|
|
|
+ uni.hideLoading();
|
|
|
+
|
|
|
+ // 如果是已知错误,直接显示
|
|
|
+ if (error.message && error.message !== 'undefined') {
|
|
|
+ uni.showToast({
|
|
|
+ title: error.message,
|
|
|
+ icon: 'none',
|
|
|
+ duration: 2000,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: '上传失败,请重试',
|
|
|
+ icon: 'none',
|
|
|
+ duration: 2000,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ throw error;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
@@ -1401,41 +1922,47 @@ export default {
|
|
|
event.preventDefault();
|
|
|
}
|
|
|
|
|
|
- uni.showModal({
|
|
|
- title: '确认删除',
|
|
|
- content: '确定要删除这张图片吗?删除后无法恢复。',
|
|
|
- confirmColor: '#ff5722',
|
|
|
- success: (res) => {
|
|
|
- if (res.confirm) {
|
|
|
- // 从附件列表中删除
|
|
|
- const attachmentIndex = this.attachmentList.findIndex(
|
|
|
- (file) =>
|
|
|
- file.uid === image.uid ||
|
|
|
- (file.ossId && file.ossId === image.ossId) ||
|
|
|
- (file.url && file.url === image.url),
|
|
|
- );
|
|
|
+ // 🔴 修复:使用 u-modal 组件替代 uni.showModal,解决 z-index 层级冲突
|
|
|
+ this.showDeleteImageConfirm = true;
|
|
|
+ this.deleteImageTarget = { image, index };
|
|
|
+ },
|
|
|
|
|
|
- if (attachmentIndex >= 0) {
|
|
|
- this.attachmentList.splice(attachmentIndex, 1);
|
|
|
- }
|
|
|
+ // 确认删除图片
|
|
|
+ confirmDeleteImage() {
|
|
|
+ const { image, index } = this.deleteImageTarget;
|
|
|
|
|
|
- // 清理blob URL,防止内存泄漏
|
|
|
- if (image.blobUrl && image.blobUrl.startsWith('blob:')) {
|
|
|
- URL.revokeObjectURL(image.blobUrl);
|
|
|
- }
|
|
|
+ // 从附件列表中删除
|
|
|
+ const attachmentIndex = this.attachmentList.findIndex(
|
|
|
+ (file) =>
|
|
|
+ file.uid === image.uid ||
|
|
|
+ (file.ossId && file.ossId === image.ossId) ||
|
|
|
+ (file.url && file.url === image.url),
|
|
|
+ );
|
|
|
|
|
|
- uni.showToast({
|
|
|
- title: '删除成功',
|
|
|
- icon: 'success',
|
|
|
- });
|
|
|
- }
|
|
|
- },
|
|
|
- fail: (err) => {
|
|
|
- console.error('删除确认对话框显示失败:', err);
|
|
|
- },
|
|
|
+ if (attachmentIndex >= 0) {
|
|
|
+ this.attachmentList.splice(attachmentIndex, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理blob URL,防止内存泄漏
|
|
|
+ if (image.blobUrl && image.blobUrl.startsWith('blob:')) {
|
|
|
+ URL.revokeObjectURL(image.blobUrl);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.showDeleteImageConfirm = false;
|
|
|
+ this.deleteImageTarget = null;
|
|
|
+
|
|
|
+ uni.showToast({
|
|
|
+ title: '删除成功',
|
|
|
+ icon: 'success',
|
|
|
});
|
|
|
},
|
|
|
|
|
|
+ // 取消删除图片
|
|
|
+ cancelDeleteImage() {
|
|
|
+ this.showDeleteImageConfirm = false;
|
|
|
+ this.deleteImageTarget = null;
|
|
|
+ },
|
|
|
+
|
|
|
// 获取文件名短格式
|
|
|
getShortFileName(fileName) {
|
|
|
if (!fileName) return '';
|
|
|
@@ -1574,24 +2101,39 @@ export default {
|
|
|
|
|
|
// 删除违纪记录
|
|
|
removeViolationRecord(studentId, index) {
|
|
|
- uni.showModal({
|
|
|
- title: '确认删除',
|
|
|
- content: '确认删除这条违纪记录吗?',
|
|
|
- success: (res) => {
|
|
|
- if (res.confirm) {
|
|
|
- const violations = this.violationRecords.get(studentId) || [];
|
|
|
- violations.splice(index, 1);
|
|
|
+ // 保存要删除的记录信息
|
|
|
+ this.deleteViolationStudentId = studentId;
|
|
|
+ this.deleteViolationIndex = index;
|
|
|
+ // 显示确认对话框
|
|
|
+ this.showDeleteConfirm = true;
|
|
|
+ },
|
|
|
|
|
|
- if (violations.length === 0) {
|
|
|
- this.violationRecords.delete(studentId);
|
|
|
- } else {
|
|
|
- this.violationRecords.set(studentId, violations);
|
|
|
- }
|
|
|
+ // 确认删除违纪记录
|
|
|
+ confirmDeleteViolation() {
|
|
|
+ if (this.deleteViolationStudentId !== null && this.deleteViolationIndex >= 0) {
|
|
|
+ const violations = this.violationRecords.get(this.deleteViolationStudentId) || [];
|
|
|
+ violations.splice(this.deleteViolationIndex, 1);
|
|
|
|
|
|
- uni.showToast({ title: '违纪记录删除成功', icon: 'success' });
|
|
|
- }
|
|
|
- },
|
|
|
- });
|
|
|
+ if (violations.length === 0) {
|
|
|
+ this.violationRecords.delete(this.deleteViolationStudentId);
|
|
|
+ } else {
|
|
|
+ this.violationRecords.set(this.deleteViolationStudentId, violations);
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showToast({ title: '违纪记录删除成功', icon: 'success' });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置状态
|
|
|
+ this.showDeleteConfirm = false;
|
|
|
+ this.deleteViolationStudentId = null;
|
|
|
+ this.deleteViolationIndex = -1;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 取消删除违纪记录
|
|
|
+ cancelDeleteViolation() {
|
|
|
+ this.showDeleteConfirm = false;
|
|
|
+ this.deleteViolationStudentId = null;
|
|
|
+ this.deleteViolationIndex = -1;
|
|
|
},
|
|
|
|
|
|
// 获取学生违纪记录
|