2025-07-28 14:57:35 +08:00
|
|
|
|
<template>
|
|
|
|
|
<view class="container">
|
|
|
|
|
<view class="example">
|
|
|
|
|
<uni-forms ref="dynamicForm" :model="form" label-width="80px">
|
|
|
|
|
<uni-forms-item label="巡检点" name="inspectionPoint">
|
|
|
|
|
<uni-easyinput disabled :value="form.inspectionPoint" placeholder="请输入巡检点"></uni-easyinput>
|
|
|
|
|
</uni-forms-item>
|
|
|
|
|
<uni-forms-item label="巡检要求" name="inspectionRequirements">
|
|
|
|
|
<uni-easyinput type="textarea" disabled :value="form.inspectionRequirements" placeholder="请输入巡检要求"></uni-easyinput>
|
|
|
|
|
</uni-forms-item>
|
|
|
|
|
<uni-forms-item label="图片上传">
|
|
|
|
|
<view class="example-body">
|
|
|
|
|
<uni-file-picker limit="3" :sourceType="sourceType" :value="img" title="最多选择3张图片"
|
|
|
|
|
file-mediatype="image" @delete="deleteImg" @select="upload"
|
|
|
|
|
:auto-upload="false"></uni-file-picker>
|
|
|
|
|
</view>
|
|
|
|
|
</uni-forms-item>
|
|
|
|
|
<!-- 备注 -->
|
2025-08-07 13:01:29 +08:00
|
|
|
|
<uni-forms-item label="备注1" name="remark">
|
2025-07-28 14:57:35 +08:00
|
|
|
|
<uni-easyinput type="textarea" v-model="form.remark" placeholder="请输入备注"></uni-easyinput>
|
|
|
|
|
</uni-forms-item>
|
|
|
|
|
</uni-forms>
|
|
|
|
|
<view class="button-group">
|
|
|
|
|
<button class="btn btn-primary" @click="submit()">提交</button>
|
|
|
|
|
<button class="btn btn-cancel" @click="cancel()">取消</button>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- 消息提示框 -->
|
|
|
|
|
<view>
|
|
|
|
|
<uni-popup ref="alertDialog" type="dialog">
|
|
|
|
|
<uni-popup-dialog :type="msgType" title="消息" :content="messageText" @confirm="dialogConfirm"
|
|
|
|
|
showClose="false"></uni-popup-dialog>
|
|
|
|
|
</uni-popup>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import {
|
|
|
|
|
uploadImg
|
|
|
|
|
} from "@/api/system/user"
|
|
|
|
|
import {
|
|
|
|
|
addRecord
|
|
|
|
|
} from "@/api/inspection/record.js"
|
|
|
|
|
import {
|
|
|
|
|
addWatermarkToImage
|
|
|
|
|
} from "@/utils/watermark.js"
|
|
|
|
|
export default {
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
form: {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
inspectionType: 0,
|
|
|
|
|
inspectorId: this.$store.state.user.nickName,
|
2025-07-28 14:57:35 +08:00
|
|
|
|
inspectionPoint: "",
|
|
|
|
|
inspectionRequirements: "",
|
|
|
|
|
inspectionImg: "",
|
2025-08-07 13:01:29 +08:00
|
|
|
|
ImgUrl: [],
|
|
|
|
|
remark: ""
|
2025-07-28 14:57:35 +08:00
|
|
|
|
},
|
|
|
|
|
img: [],
|
|
|
|
|
sourceType: ['camera'],
|
|
|
|
|
imgFiles: "",
|
|
|
|
|
msgType: '',
|
|
|
|
|
messageText: '',
|
2025-08-07 13:01:29 +08:00
|
|
|
|
isUploading: false,
|
|
|
|
|
isMobileBrowser: false // 改为更通用的移动浏览器检测标志
|
2025-07-28 14:57:35 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
submit() {
|
|
|
|
|
if (this.isUploading) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.showMessage('warning', '图片正在上传中,请稍等');
|
2025-07-28 14:57:35 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!Array.isArray(this.form.ImgUrl) || this.form.ImgUrl.length === 0) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.showMessage('error', '请选择要上传的图片');
|
2025-07-28 14:57:35 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.form.inspectionImg = this.joinList();
|
2025-07-28 14:57:35 +08:00
|
|
|
|
addRecord(this.form).then(res => {
|
|
|
|
|
if (res.code === 200) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.showMessage('success', '打卡成功');
|
2025-07-28 14:57:35 +08:00
|
|
|
|
} else {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.showMessage('error', '打卡失败');
|
2025-07-28 14:57:35 +08:00
|
|
|
|
}
|
2025-08-07 13:01:29 +08:00
|
|
|
|
}).catch(err => {
|
|
|
|
|
this.showMessage('error', `提交失败: ${err.message}`);
|
|
|
|
|
});
|
2025-07-28 14:57:35 +08:00
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
deleteImg(e) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
const index = this.img.findIndex(f => f.path === e.tempFile.path);
|
2025-07-28 14:57:35 +08:00
|
|
|
|
if (index !== -1) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.form.ImgUrl.splice(index, 1);
|
|
|
|
|
this.img.splice(index, 1);
|
2025-07-28 14:57:35 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
upload(e) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
if (e.tempFiles && e.tempFiles.length > 0) {
|
|
|
|
|
this.handleImageUpload(e.tempFiles[0]);
|
|
|
|
|
}
|
2025-07-28 14:57:35 +08:00
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
cancel() {
|
|
|
|
|
uni.reLaunch({
|
|
|
|
|
url: '/pages/work/index'
|
|
|
|
|
});
|
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
joinList() {
|
|
|
|
|
return this.form.ImgUrl.join(',');
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async handleImageUpload(file) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.isUploading = true;
|
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
try {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
if (!file || !file.file) {
|
2025-07-28 14:57:35 +08:00
|
|
|
|
throw new Error('无效的文件对象');
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-07 13:01:29 +08:00
|
|
|
|
// 生成水印文字
|
|
|
|
|
const watermarkText = `${this.form.inspectionPoint || '未命名地点'} \n${this.getCurrentDate()}`;
|
2025-07-28 14:57:35 +08:00
|
|
|
|
|
2025-08-07 13:01:29 +08:00
|
|
|
|
// 添加水印
|
|
|
|
|
let processedFile = await addWatermarkToImage(file.file, watermarkText);
|
|
|
|
|
|
|
|
|
|
// 如果是移动浏览器且文件大于300KB,则进行压缩
|
|
|
|
|
if (this.isMobileBrowser && processedFile.size > 300 * 1024) {
|
|
|
|
|
console.log('原始文件大小:', (processedFile.size / 1024).toFixed(2), 'KB');
|
|
|
|
|
processedFile = await this.compressImageForMobile(processedFile);
|
|
|
|
|
console.log('压缩后文件大小:', (processedFile.size / 1024).toFixed(2), 'KB');
|
|
|
|
|
}
|
2025-07-28 14:57:35 +08:00
|
|
|
|
|
2025-08-07 13:01:29 +08:00
|
|
|
|
// 上传处理后的文件
|
|
|
|
|
const fileUrl = await this.uploadFile(processedFile);
|
|
|
|
|
|
|
|
|
|
// 更新UI显示
|
|
|
|
|
this.img.push({
|
|
|
|
|
raw: processedFile,
|
|
|
|
|
name: processedFile.name,
|
|
|
|
|
url: fileUrl
|
|
|
|
|
});
|
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
} catch (error) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
console.error("图片处理失败:", error);
|
|
|
|
|
this.showMessage('error', `图片处理失败: ${error.message}`);
|
2025-07-28 14:57:35 +08:00
|
|
|
|
} finally {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.isUploading = false;
|
2025-07-28 14:57:35 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
|
|
|
|
// 专门为移动浏览器优化的压缩方法
|
|
|
|
|
compressImageForMobile(file, quality = 0.6, maxWidth = 1200, maxHeight = 1200) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const img = new Image();
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
|
|
|
|
reader.onload = (event) => {
|
|
|
|
|
img.onload = () => {
|
|
|
|
|
// 计算压缩比例
|
|
|
|
|
let width = img.width;
|
|
|
|
|
let height = img.height;
|
|
|
|
|
|
|
|
|
|
// 限制最大尺寸
|
|
|
|
|
if (width > maxWidth || height > maxHeight) {
|
|
|
|
|
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
|
|
|
width = Math.floor(width * ratio);
|
|
|
|
|
height = Math.floor(height * ratio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建canvas
|
|
|
|
|
const canvas = document.createElement('canvas');
|
|
|
|
|
canvas.width = width;
|
|
|
|
|
canvas.height = height;
|
|
|
|
|
|
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
|
|
|
|
|
|
// 设置更高的压缩质量
|
|
|
|
|
ctx.imageSmoothingQuality = 'high';
|
|
|
|
|
ctx.drawImage(img, 0, 0, width, height);
|
|
|
|
|
|
|
|
|
|
// 使用toBlob的polyfill保证兼容性
|
|
|
|
|
if (canvas.toBlob) {
|
|
|
|
|
canvas.toBlob(
|
|
|
|
|
(blob) => {
|
|
|
|
|
if (!blob) {
|
|
|
|
|
console.warn('压缩失败,返回原始文件');
|
|
|
|
|
resolve(file);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建压缩后的文件对象
|
|
|
|
|
const compressedFile = new File([blob], file.name, {
|
|
|
|
|
type: 'image/jpeg',
|
|
|
|
|
lastModified: Date.now()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
resolve(compressedFile);
|
|
|
|
|
},
|
|
|
|
|
'image/jpeg',
|
|
|
|
|
quality
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
// 不支持toBlob的浏览器直接返回原文件
|
|
|
|
|
console.warn('浏览器不支持toBlob方法,无法压缩');
|
|
|
|
|
resolve(file);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
img.onerror = () => {
|
|
|
|
|
console.warn('图片加载失败,返回原始文件');
|
|
|
|
|
resolve(file);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
img.src = event.target.result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
reader.onerror = () => {
|
|
|
|
|
console.warn('文件读取失败,返回原始文件');
|
|
|
|
|
resolve(file);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async uploadFile(file) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
// 创建预览URL用于显示
|
|
|
|
|
const previewUrl = URL.createObjectURL(file);
|
|
|
|
|
|
|
|
|
|
// 实际上传
|
|
|
|
|
uploadImg({
|
|
|
|
|
filePath: previewUrl
|
|
|
|
|
}).then(res => {
|
|
|
|
|
this.form.ImgUrl.push(res.fileName);
|
|
|
|
|
resolve(previewUrl);
|
|
|
|
|
}).catch(err => {
|
|
|
|
|
reject(err);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
getCurrentDate() {
|
|
|
|
|
const now = new Date();
|
|
|
|
|
const year = now.getFullYear();
|
|
|
|
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
const day = String(now.getDate()).padStart(2, '0');
|
|
|
|
|
const hours = String(now.getHours()).padStart(2, '0');
|
|
|
|
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
|
|
|
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
|
|
|
|
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
dialogConfirm() {
|
|
|
|
|
if (this.msgType == 'success') {
|
|
|
|
|
uni.reLaunch({
|
|
|
|
|
url: '/pages/work/index'
|
2025-08-07 13:01:29 +08:00
|
|
|
|
});
|
2025-07-28 14:57:35 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
|
|
|
|
showMessage(type, text) {
|
|
|
|
|
this.msgType = type;
|
|
|
|
|
this.messageText = text;
|
|
|
|
|
this.$refs.alertDialog.open();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 检测移动浏览器环境
|
|
|
|
|
checkMobileBrowser() {
|
|
|
|
|
// 更全面的移动设备检测
|
|
|
|
|
const userAgent = navigator.userAgent.toLowerCase();
|
|
|
|
|
const isMobile = /iphone|ipod|android|windows phone|mobile|blackberry/.test(userAgent);
|
|
|
|
|
|
|
|
|
|
// 如果是通过uni-app的web-view打开,也认为是移动环境
|
|
|
|
|
this.isMobileBrowser = isMobile || window.__uniAppWebview;
|
|
|
|
|
}
|
2025-07-28 14:57:35 +08:00
|
|
|
|
},
|
|
|
|
|
onLoad(option) {
|
2025-08-07 13:01:29 +08:00
|
|
|
|
this.form.inspectionPoint = option.inspectionPoint || '';
|
|
|
|
|
this.form.inspectionRequirements = option.inspectionRequirements || '';
|
|
|
|
|
this.form.inspectionPointId = option.inspectionPointId || '';
|
2025-07-28 14:57:35 +08:00
|
|
|
|
},
|
2025-08-07 13:01:29 +08:00
|
|
|
|
mounted() {
|
|
|
|
|
this.checkMobileBrowser();
|
2025-07-28 14:57:35 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
2025-08-07 13:01:29 +08:00
|
|
|
|
|
2025-07-28 14:57:35 +08:00
|
|
|
|
<style lang="scss">
|
|
|
|
|
page {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
height: 90vh;
|
|
|
|
|
/* 使页面高度占满整个视口 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.container {
|
|
|
|
|
flex: 1;
|
|
|
|
|
/* 让 container 占满剩余空间 */
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
/* 设置为列方向 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.example {
|
|
|
|
|
flex: 1;
|
|
|
|
|
/* 让 example 占满 container 的剩余空间 */
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
/* 设置为列方向,确保子元素垂直排列 */
|
|
|
|
|
padding: 15px;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 样式沉底
|
|
|
|
|
.button-group {
|
|
|
|
|
position: fixed;
|
|
|
|
|
bottom: 20px;
|
|
|
|
|
left: 0;
|
|
|
|
|
/* 使用 margin-top: auto 来将按钮组推到 example 容器的底部 */
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%;
|
|
|
|
|
justify-content: space-around;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.button-group button {
|
|
|
|
|
flex: 1;
|
|
|
|
|
background: #fff;
|
|
|
|
|
color: #000;
|
|
|
|
|
/* 使按钮平分可用空间 */
|
|
|
|
|
/* 可能还需要设置一些其他的样式来确保按钮看起来正确,比如 text-align, padding 等 */
|
|
|
|
|
}
|
|
|
|
|
</style>
|