Files
pasd_app/pages/work/inspection/scanSign/index.vue

278 lines
8.8 KiB
Vue
Raw Normal View History

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">
2025-09-04 20:45:49 +08:00
<uni-file-picker limit="3" :sourceType="sourceType" :value="img" title="最多选择3张图片"
file-mediatype="image" @delete="deleteImg" @select="upload"
:auto-upload="false"></uni-file-picker>
2025-07-28 14:57:35 +08:00
</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>
2025-09-04 21:06:29 +08:00
import { addRecord } from "@/api/inspection/record.js"
// 如果你已有 uploadImg 封装且内部就是 uni.uploadFile可以继续用
// 但前提是它支持 H5 直接传 File 对象(不是 URL 字符串)。
// 这里我示范“直接用 uni.uploadFile”的写法更稳妥。
import { addWatermarkToImage } from "@/utils/watermark.js"
import appConfig from '@/config'
const UPLOAD_URL = appConfig.baseUrl + "/common/upload" // 按你后端改
2025-07-28 14:57:35 +08:00
2025-09-04 21:06:29 +08:00
export default {
data() {
return {
form: {
inspectionType: 0,
inspectorId: this.$store.state.user.nickName,
inspectionPoint: "",
inspectionRequirements: "",
inspectionImg: "",
ImgUrl: [], // 存后端返回的文件名/URL
remark: ""
},
img: [], // 绑定给 uni-file-picker 的预览列表
sourceType: ['camera'],
msgType: '',
messageText: '',
isUploading: false,
isMobileBrowser: false
}
},
methods: {
async submit() {
if (this.isUploading) {
this.showMessage('warning', '图片正在上传中,请稍等')
return
}
if (!Array.isArray(this.form.ImgUrl) || this.form.ImgUrl.length === 0) {
this.showMessage('error', '请选择要上传的图片')
return
}
this.form.inspectionImg = this.joinList()
try {
const res = await addRecord(this.form)
if (res.code === 200) {
this.showMessage('success', '打卡成功')
} else {
this.showMessage('error', '打卡失败')
}
} catch (err) {
this.showMessage('error', `提交失败: ${err.message}`)
}
},
2025-08-07 13:01:29 +08:00
2025-09-04 21:06:29 +08:00
// uni-file-picker 删除e.tempFile 里通常有 {url/path},与你传给 value 的结构需一致
deleteImg(e) {
const url = e.tempFile?.url || e.tempFile?.path
const idx = this.img.findIndex(x => x.url === url)
if (idx !== -1) {
this.img.splice(idx, 1)
// 同步移除已上传结果(按你的业务,可以用同索引移除或按返回名移除)
this.form.ImgUrl.splice(idx, 1)
}
},
2025-08-07 13:01:29 +08:00
2025-09-04 21:06:29 +08:00
// 选择文件(支持多张)
async upload(e) {
if (!e?.tempFiles?.length) return
if (this.isUploading) {
this.showMessage('warning', '图片正在上传中,请稍等')
return
}
2025-08-07 13:01:29 +08:00
2025-09-04 21:06:29 +08:00
this.isUploading = true
try {
// 逐张处理
for (const tf of e.tempFiles) {
await this.handleImageUpload(tf) // 这里传入每个 tempFile
}
this.showMessage('success', '图片处理/上传完成')
} catch (err) {
console.error(err)
this.showMessage('error', `图片上传失败:${err.message || err}`)
} finally {
this.isUploading = false
}
},
2025-09-04 20:26:46 +08:00
2025-09-04 21:06:29 +08:00
// 单张处理:加水印 ->(可选)压缩 -> 上传
async handleImageUpload(tempFile) {
// tempFile.file: H5 下是 File 对象App/小程序是临时路径
const raw = tempFile.file || tempFile // 兼容各端
// 生成水印文字
const watermarkText = `${this.form.inspectionPoint || '未命名地点'} \n${this.getCurrentDate()}`
// 加水印(返回 File/Blob
const watermarked = await addWatermarkToImage(raw, watermarkText)
// 可选:移动端压缩(你已有方法,按需启用)
// const finalFile = await this.compressImageForMobile(watermarked)
2025-09-04 20:26:46 +08:00
2025-09-04 21:06:29 +08:00
const finalFile = watermarked
2025-08-07 13:01:29 +08:00
2025-09-04 21:06:29 +08:00
// 预览:用本地 URL仅供前端显示
const previewUrl = URL.createObjectURL(finalFile)
this.img.push({
url: previewUrl, // uni-file-picker 识别 url
name: finalFile.name || `image_${Date.now()}.jpg`,
extname: 'jpg'
})
2025-07-28 14:57:35 +08:00
2025-09-04 21:06:29 +08:00
// 真正上传:**不要传 previewUrl 字符串**,而是传二进制 `file`
// H5 下uni.uploadFile 支持传 `file: File`
const uploadedName = await this.uploadFileWithUni(finalFile)
// 回填后端返回的文件名/URL
this.form.ImgUrl.push(uploadedName)
},
2025-09-04 20:45:49 +08:00
2025-09-04 21:06:29 +08:00
// 用 uni.uploadFile 直接传二进制
uploadFileWithUni(file) {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: UPLOAD_URL,
name: 'file', // 后端接收字段名(按你的后端改)
file, // H5 直接传 File 对象(重点!)
// 如果后端还需要额外字段:
// formData: { bizType: 'inspection' },
success: (res) => {
try {
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
if (data.code === 200) {
// 假设后端返回 { code:200, fileName: 'xxx.jpg', url:'...' }
resolve(data.fileName || data.url)
} else {
reject(new Error(data.msg || '上传失败'))
}
} catch (e) {
reject(new Error('上传响应解析失败'))
}
},
fail: (err) => reject(err)
})
})
},
2025-08-07 13:01:29 +08:00
2025-09-04 21:06:29 +08:00
cancel() {
uni.reLaunch({ url: '/pages/work/index' })
},
2025-08-07 13:01:29 +08:00
2025-09-04 21:06:29 +08:00
joinList() {
return this.form.ImgUrl.join(',')
},
2025-07-28 14:57:35 +08:00
2025-09-04 21:06:29 +08:00
getCurrentDate() {
const now = new Date()
const y = now.getFullYear()
const m = String(now.getMonth() + 1).padStart(2, '0')
const d = String(now.getDate()).padStart(2, '0')
const hh = String(now.getHours()).padStart(2, '0')
const mm = String(now.getMinutes()).padStart(2, '0')
const ss = String(now.getSeconds()).padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
},
2025-07-28 14:57:35 +08:00
2025-09-04 21:06:29 +08:00
dialogConfirm() {
if (this.msgType === 'success') {
uni.reLaunch({ url: '/pages/work/index' })
}
},
showMessage(type, text) {
this.msgType = type
this.messageText = text
this.$refs.alertDialog.open()
},
checkMobileBrowser() {
const ua = navigator.userAgent.toLowerCase()
const isMobile = /iphone|ipod|android|windows phone|mobile|blackberry/.test(ua)
this.isMobileBrowser = isMobile || window.__uniAppWebview
}
},
onLoad(option) {
this.form.inspectionPoint = option.inspectionPoint || ''
this.form.inspectionRequirements = option.inspectionRequirements || ''
this.form.inspectionPointId = option.inspectionPointId || ''
},
mounted() {
this.checkMobileBrowser()
}
}
2025-07-28 14:57:35 +08:00
</script>
2025-08-07 13:01:29 +08:00
2025-09-04 21:06: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 等 */
}
2025-09-04 20:26:46 +08:00
2025-07-28 14:57:35 +08:00
</style>