<template>
<view>
<view class="form-item">
<view v-for="(photo,inde) in imagesLists" :key="inde" class="photo">
<image :src="photo" v-model="imagelistChange" @click="preview(photo,imagesLists)">
</image>
<view class="closeA" @tap="deletePhoto(inde)">
<u-icon name="close" color="#000000"></u-icon>
</view>
</view>
<view class="btnAddPhoto" style="margin: 5px;" @click="Imageschoose()" v-if="imagesLists.length>
<u-icon name="camera" size="28"></u-icon>
</view>
</view>
<canvas :style="{width:canvasWidth,height:canvasHeight}" canvas-id="myCanvas" v-if="flag"></canvas>
</view>
</template>
<script>
import {
imageUpload,
} from '@/api/system/applet.js' //图片上传,按照自己照片放置位置更改接口
import {
dateFormat,//日期约束
imageChoose,//拿到后台图片上传链接
text,//文字换行
previewPhoto,//图片展示
getLocation//获取定位
} from '@/utils/public.js'
export default {
props: {
images:Array,//图片数组
limit:Number,//图片限制张数
index:String,
imagesLists:Array,//父组件传过来的照片数组
},
data() {
return {
photoIndex: null, //图片上传元素下标
canvasWidth: '', //绘制图片宽度
canvasHeight: '', //绘制图片高度
imagesList: [], //定义一个数组存放原照片文件
photoArray: [], //未添加水印图片数组
flag:false,//绘制显示
longitude: '', //坐标
latitude: '', //y坐标
addressName: '', //传入公司地址
imagelistChange:this.images
}
},
methods: {
// 调用添加水印的函数
callAddWaterMart() {
this.addWaterMark(() => {
if (this.photoIndex < this.photoArray.length - 1) {
this.photoIndex++;
this.callAddWaterMart()
}else{
uni.hideLoading()
}
})
},
//图片选中,默认只允许拍照
Imageschoose() {
this.photoIndex = 0;
let num = this.limit - this.imagesList.length
uni.chooseImage({
count: num,
sourceType: ['camera', 'album'], //默认相机
sizeType: ["compressed"], //缩略图
success: res => {
this.photoArray = res.tempFilePaths;
this.callAddWaterMart();
}
})
},
// 添加水印
async addWaterMark(callback) {
let location = await getLocation()
this.addressName = location.address
this.latitude = location.lat
this.longitude = location.long
this.flag = true
uni.showLoading({
title: "图片加载中..."
})
uni.getImageInfo({
src: this.photoArray[this.photoIndex],
success: res => {
this.canvasWidth = `${res.width}px`;
this.canvasHeight = `${res.height}px`;
if (res.width > 400 && res.height > 400) {
var ctx = uni.createCanvasContext('myCanvas', this);
ctx.clearRect(0, 0, res.width, res.height); //清空指定区域的绘图
ctx.beginPath(); //开始绘制
ctx.drawImage(this.photoArray[this.photoIndex], 0, 0, res.width, res.height);
// 为图片添加水印
ctx.translate(0, res.height - 200);
let clientNameWidth = 20;
let clientNameHeight = 50
let date = new Date()
let time = dateFormat("YYYY-mm-dd HH:MM:SS", date);
ctx.beginPath();
ctx.setFontSize(30); //改字体
ctx.setFillStyle("rgba(255,255,255,1)");
ctx.fillText("时间" + ':' + time, clientNameWidth, clientNameHeight);
ctx.fillText("坐标" + ':' + this.longitude + ',' + this.latitude,
clientNameWidth, clientNameHeight + 35);
let data = "地址" + ':' + this.addressName
let result = text(data, res)
for (let i = 0; i <= result.rows; i++) {
ctx.fillText(data.slice(result.rowFontNum * (i - 1), result
.rowFontNum * i), clientNameWidth, clientNameHeight + (i +
1) * 35)
}
// 开始绘制添加水印的图片并显示在页面中
ctx.draw(false, () => {
setTimeout(() => {
uni.canvasToTempFilePath({
canvasId: "myCanvas",
destWidth: res.width,
destHeight: res.height,
fileType: 'jpg',
quality: 1,
success: res => {
//图片上传拿url
let image = imageChoose(res
.tempFilePath)
imageUpload(image).then(
response => {
this.imagesList.push(
response.data
.url);
this.$emit("list", this
.imagesList)
this.$emit("listIndex",
this.index)
this.flag = false
callback();
})
}
}, this)
}, 500)
});
} else {
uni.showToast({
title: '图片太小,请重新选择',
icon: 'none'
})
return
}
}
})
},
// 预览图片
preview(url, list) {
previewPhoto(url, list)
},
// 删除图片
deletePhoto(index) {
this.imagesList.splice(index, 1);
}
}
}
</script>
<style lang="scss">
canvas {
position: absolute;
left: 2000upx;
}
</style>
```### 公用部分的封装js
applit.js为图片上传模块,为接口项,暂不提供
```c
// 预览图片
export function previewPhoto(url, list) {
uni.previewImage({
current: url,
urls: list.map(item => item)
})
}
// 高德地圖封装
import amap from '@/utils/amap-wx.130.js'
const amapPlugin = new amap.AMapWX({
key: ''//填写自己的高德地图key
});
export function getLocation() {
var Location
return new Promise((resolve, reject) => {
uni.getSetting({
success(res) {
let location = {};
// 如果没有授权
if (!res.authSetting['scope.userLocation']) {
// 则拉起授权窗口
uni.authorize({
scope: 'scope.userLocation',
success() {
// 已授权
amapPlugin.getRegeo({
success(data) {
// let address =`${data[0].regeocodeData.addressComponent.city}${data[0].regeocodeData.addressComponent.district}`;
let address =
`${data[0].regeocodeData.formatted_address}`;
// _this.address 可根据自己的实际情况修改
// address = `${datwww.cppcns.coma[0].regeocodeData.formatted_address}`;
let lat = `${data[0].latitude}`;
let long = `${data[0].longitude}`;
let time = `${data[0]}`;
location = {
address: address,
lat: lat,
long: long,
}
resolve(location)
uni.hideLoading();
return location
},
fail(err) { //不加此字段控制台会报错
uni.getLocation({
type: 'gcj02', //返回可以用于uni.openLocation的经纬度
success: function(res) {
location = {
lat: res.latitude,
long: res.longitude,
address: '授权过期,启用内置定位'
}
resolve(location)
return location
},
fail(err) { //不加此字段控制台会报错
uni.showToast({
title: "获取位置失败",
icon: "error"
})
}
});
}
})
},
fail(error) {
//点击了拒绝授权后--就一直会进入失败回调函数--此时就可以在这里重新拉起授权窗口
uni.showModal({
title: '提示',
content: '需要授权位置信息,否则将无法使用',
cancelText: '不授权',
cancelColor: '#999',
confirmText: '授权',
confirmColor: '#f94218',
success(res) {
if (res.confirm) {
// 选择弹框内授权
uni.openSetting({
success(res) {
console.log(res.authSetting)
return
}
})
} else if (res.cancel) {
// 选择弹框内 不授权
console.log('用户点击不授权')
return
}
}
})
}
})
} else {
amapPlugin.getRegeo({
success(data) {
let address = `${data[0].regeocodeData.formatted_address}`;
// address = `${datwww.cppcns.coma[0].regeocodeData.formatted_address}`;
let lat = `${data[0].latitude}`;
let long = `${data[0].longitude}`;
Location = {
address: address,
lat: lat,
long: long,
}
resolve(Location)
uni.hideLoading();
return location
},
fail(err) {
uni.getLocation({
type: 'gcj02', //返回可以用于uni.openLocation的经纬度
success: function(res) {
location = {
lat: res.latitude,
long: res.longitude,
address: '授权过期,启用内置定位'
}
resolve(location)
return location
},
fail(err) { //不加此字段控制台会报错
uni.showToast({
title: "获取位置失败",
icon: "error"
})
}
});
}
})
}
}
})
})
}
//换行
export function text(str, res) {
// 画布总宽度 px单位
let canvasWidth = res.width / 3
// 字体大小 px单位
let fontSize = 12
// 每行所需字数 = 画布总宽度 / 单个字体大小
let rowFontNum = Math.floor(canvasWidth / fontSize)
// 字符串总长度
let strLength = str.length
// 所需行数 = 字符总长度 / 每行所需字数
let rows = Math.ceil(strLength / rowFontNum)
return {
canvasWidth,
fontSize,
rowFontNum,
strLength,
rows
}
}
// 图片添加标头区分位置
export function imageChoose(item) {
let data = {
filePath: item,
formData: {
isSystem: 'true'//保存位置分权
}
}
return data
}
//日期格式,用于绘制图片添加内容---
export function dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1]
.length, "0")))
};
};
return fmt;
}
<template>
<view>
<photoList :value="baseFormData.faceImgsFirst" :imagesLists="baseFormData.faceImgsFirst" @list="firstImage" :limit="1"/>
</view>
</template>
<script>
import photoOne from '@/pages/public/photoOne/photoOne.vue'
export default{
components: {
photoOne
},
data(){
return{
baseFormData:{}
}
},
methods:{
firstImage(val){
this.baseFormData.faceImgsFirst=val
},
}
}
</script>
limit 控制张数
<template>
<view>
<photoList :value="baseFormData.images" @list="imageList" :limit="9" :imagesLists="baseFormData.images"/>
</view>
</template>
<script>
import photoList from '@/pages/public/photoList/photoList.vue'
export default{
components: {
photoList
},
methods:{
imageList(val){
this.baseFormData.images=val//此项为你接收数据项,
},
}
}
</script>
注意imagelists必填,避免出现删除不一致现象,发送为父级数据
<template>
<view>
<uni-forms>
<uni-forms-item label="照片" required :rules="[{required: true,errorMessage: '最少一张照片'}]":name="['inspectionCustodyWorkLogDetailBoList',index,'imagelist']" label-width="100rpx">
<view class="form-item">
<photoLis :value="baseFormData.inspectionCustodyWorkLogDetailBoList[index].imagelist" :imagesLists="baseFormData.inspectionCustodyWorkLogDetailBoList[index].imagelist" :limit="9" :index="index" @listIndex="getIndex" @list="imageList"/>
</view>
</uni-forms-item>
</uni-forms>
</view>
</template>
<script>
import photoOne from '@/pages/public/photoOne/photoOne.vue'
export default{
components: {
photoOne
},
data(){
// 基础表单数据
baseFormData: {
inspectionCustodyWorkLogDetailBoList: [], //第三方服务机构工作日志检查记录
},
},
methods:{
//获取下标
getIndex(index){
this.inde=index
},
async imageList(val){
await this.getIndex()
this.baseFormData.inspectionCustodyWorkLogDetailBoList[this.inde].imagelist=val
},
//获取后台数据
getList(){
//获取自己的数据,按照实际情况填写
}
}
}
</script>