|
|
@@ -1,5 +1,12 @@
|
|
|
<template>
|
|
|
<view class="page-container">
|
|
|
+ <!-- 隐藏的Canvas用于添加水印 -->
|
|
|
+ <canvas
|
|
|
+ id="watermarkCanvas"
|
|
|
+ canvas-id="watermarkCanvas"
|
|
|
+ :style="{width: canvasWidth + 'px', height: canvasHeight + 'px', position: 'fixed', left: '-9999px', top: '-9999px'}">
|
|
|
+ </canvas>
|
|
|
+
|
|
|
<view class="form-card">
|
|
|
|
|
|
<view class="form-item">
|
|
|
@@ -56,6 +63,8 @@
|
|
|
mode="grid"
|
|
|
:limit="9"
|
|
|
title="最多选择9张图片"
|
|
|
+ @tap="checkPermissionBeforeSelect"
|
|
|
+ @select="handleFileSelect"
|
|
|
v-model="formData.photos"
|
|
|
/>
|
|
|
</view>
|
|
|
@@ -77,6 +86,10 @@ export default {
|
|
|
return {
|
|
|
edit:false,
|
|
|
isLocating:false,
|
|
|
+ canvasWidth: 800,
|
|
|
+ canvasHeight: 600,
|
|
|
+ processingImages: false,
|
|
|
+ imageAddress: '',
|
|
|
// 表单数据
|
|
|
formData: {
|
|
|
photos: [],
|
|
|
@@ -90,67 +103,322 @@ export default {
|
|
|
},
|
|
|
onLoad(opt){
|
|
|
this.edit = opt.edit == 1;
|
|
|
- if(opt.id){
|
|
|
- this.formData.storeId = opt.id;
|
|
|
- getRetailDetail(opt.id).then(res=>{
|
|
|
- let data = res.data;
|
|
|
- this.formData = {
|
|
|
- storeId: data.id,
|
|
|
- storeName: data.store_name,
|
|
|
- ownerName: data.contact_name,
|
|
|
- contact: data.contact_phone,
|
|
|
- address: data.address,
|
|
|
+ if(opt.id){
|
|
|
+ this.formData.storeId = opt.id;
|
|
|
+ getRetailDetail(opt.id).then(res=>{
|
|
|
+ let data = res.data;
|
|
|
+ this.formData = {
|
|
|
+ storeId: data.id,
|
|
|
+ storeName: data.store_name,
|
|
|
+ ownerName: data.contact_name,
|
|
|
+ contact: data.contact_phone,
|
|
|
+ address: data.address,
|
|
|
+ }
|
|
|
+ this.formData.photos = [];
|
|
|
+ let photos = data.store_photo.split(",")
|
|
|
+ for (let i = 0; i < photos.length; i++) {
|
|
|
+ let photo = photos[i];
|
|
|
+ this.formData.photos.push({url:photo})
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 点击时检查权限
|
|
|
+ async checkPermissionBeforeSelect() {
|
|
|
+ console.log("检查权限");
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 检查定位权限状态
|
|
|
+ const settingRes = await uni.getSetting();
|
|
|
+ const locationAuth = settingRes.authSetting['scope.userLocation'];
|
|
|
+
|
|
|
+ if (locationAuth === false) {
|
|
|
+ // 已拒绝授权,提示用户
|
|
|
+ const modalRes = await uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '为了给图片添加地理位置水印,需要获取您的地理位置权限。是否前往设置开启?',
|
|
|
+ confirmText: '去设置',
|
|
|
+ cancelText: '取消'
|
|
|
+ });
|
|
|
+
|
|
|
+ if (modalRes.confirm) {
|
|
|
+ // 打开设置页面
|
|
|
+ const settingResult = await uni.openSetting();
|
|
|
+ if (settingResult.authSetting['scope.userLocation']) {
|
|
|
+ // 权限开启成功,先获取位置再选择图片
|
|
|
+ await this.getLocationForImageSelection();
|
|
|
+ this.$refs.files.choose();
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: '未开启定位权限,图片将不带位置水印', icon: 'none' });
|
|
|
+ // 用户仍然可以选择图片,但没有位置水印
|
|
|
+ this.$refs.files.choose();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 用户取消开启权限,仍然允许选择图片
|
|
|
+ uni.showToast({ title: '未开启定位权限,图片将不带位置水印', icon: 'none' });
|
|
|
+ this.$refs.files.choose();
|
|
|
}
|
|
|
- this.formData.photos = [];
|
|
|
- let photos = data.store_photo.split(",")
|
|
|
- for (let i = 0; i < photos.length; i++) {
|
|
|
- let photo = photos[i];
|
|
|
- this.formData.photos.push({url:photo})
|
|
|
+ } else {
|
|
|
+ console.log("已获取定位权限");
|
|
|
+ // 已有权限或未申请过权限,先获取位置再选择图片
|
|
|
+ await this.getLocationForImageSelection();
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('权限检查失败:', error);
|
|
|
+ // 出现异常时,仍然允许选择图片
|
|
|
+ uni.showToast({ title: '权限检查失败,图片将不带位置水印', icon: 'none' });
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 专门用于图片选择的位置获取方法
|
|
|
+ async getLocationForImageSelection() {
|
|
|
+ await this.doGetLocation("imageAddress");
|
|
|
+ },
|
|
|
+
|
|
|
+ handleFileSelect(event) {
|
|
|
+ this.onFileSelect(event);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 修改后的添加水印处理函数
|
|
|
+ async addWatermarkToImage(imagePath, address) {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ uni.getImageInfo({
|
|
|
+ src: imagePath,
|
|
|
+ success: (imageInfo) => {
|
|
|
+ // 设置合理的画布尺寸
|
|
|
+ let maxWidth = 800;
|
|
|
+ let maxHeight = 1200;
|
|
|
+ let width = imageInfo.width;
|
|
|
+ let height = imageInfo.height;
|
|
|
+
|
|
|
+ // 按比例缩放
|
|
|
+ if (width > maxWidth || height > maxHeight) {
|
|
|
+ let ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
|
+ width = width * ratio;
|
|
|
+ height = height * ratio;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新画布尺寸
|
|
|
+ this.canvasWidth = Math.round(width);
|
|
|
+ this.canvasHeight = Math.round(height);
|
|
|
+
|
|
|
+ // 等待画布更新
|
|
|
+ this.$nextTick(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ const ctx = uni.createCanvasContext('watermarkCanvas', this);
|
|
|
+
|
|
|
+ // 清除画布
|
|
|
+ ctx.clearRect(0, 0, width, height);
|
|
|
+
|
|
|
+ // 绘制原图
|
|
|
+ ctx.drawImage(imagePath, 0, 0, width, height);
|
|
|
+
|
|
|
+ // 添加时间水印
|
|
|
+ const now = new Date();
|
|
|
+ const timeText = `${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
|
|
+
|
|
|
+ // 设置水印样式
|
|
|
+ ctx.setFontSize(24);
|
|
|
+ ctx.setFillStyle('rgba(255, 255, 255, 0.8)');
|
|
|
+ ctx.setTextAlign('right');
|
|
|
+
|
|
|
+ // 添加时间水印
|
|
|
+ ctx.fillText(timeText, width - 20, height - 40);
|
|
|
+
|
|
|
+ // 添加地址水印
|
|
|
+ if (address) {
|
|
|
+ let addressText = address;
|
|
|
+ if (address.length > 12) {
|
|
|
+ addressText = address.substring(0, 12) + '...';
|
|
|
+ }
|
|
|
+ ctx.fillText(addressText, width - 20, height - 15);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 绘制并导出
|
|
|
+ ctx.draw(false, () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ canvasId: 'watermarkCanvas',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ destWidth: width,
|
|
|
+ destHeight: height,
|
|
|
+ quality: 0.8,
|
|
|
+ fileType: 'jpg',
|
|
|
+ success: (res) => {
|
|
|
+ console.log('水印图片生成成功:', res.tempFilePath);
|
|
|
+ resolve(res.tempFilePath);
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('导出水印图片失败:', err);
|
|
|
+ // 如果导出失败,直接返回原图
|
|
|
+ resolve(imagePath);
|
|
|
+ }
|
|
|
+ }, this);
|
|
|
+ }, 300);
|
|
|
+ });
|
|
|
+ }, 100);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('获取图片信息失败:', err);
|
|
|
+ resolve(imagePath); // 获取图片信息失败时返回原图
|
|
|
}
|
|
|
- })
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 批量处理水印
|
|
|
+ async processImagesWithWatermark(files, address) {
|
|
|
+ const processedFiles = [];
|
|
|
+ for (let i = 0; i < files.length; i++) {
|
|
|
+ const file = files[i];
|
|
|
+ const watermarkedPath = await this.addWatermarkToImage(file.path || file.url, address);
|
|
|
+ processedFiles.push({
|
|
|
+ ...file,
|
|
|
+ path: watermarkedPath,
|
|
|
+ url: watermarkedPath
|
|
|
+ });
|
|
|
}
|
|
|
- },
|
|
|
- methods: {
|
|
|
+ return processedFiles;
|
|
|
+ },
|
|
|
+
|
|
|
getLocation() {
|
|
|
this.isLocating = true;
|
|
|
+ let self = this;
|
|
|
+ // 先检查定位权限
|
|
|
+ uni.getSetting({
|
|
|
+ success: (res) => {
|
|
|
+ // 如果没有授权定位权限
|
|
|
+ if (res.authSetting['scope.userLocation'] === false) {
|
|
|
+ // 提示用户需要授权
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '需要获取您的地理位置,请在设置中开启定位权限',
|
|
|
+ confirmText: '去设置',
|
|
|
+ cancelText: '取消',
|
|
|
+ success: (modalRes) => {
|
|
|
+ if (modalRes.confirm) {
|
|
|
+ // 打开授权设置页面
|
|
|
+ uni.openSetting({
|
|
|
+ success: (settingRes) => {
|
|
|
+ if (settingRes.authSetting['scope.userLocation']) {
|
|
|
+ // 用户打开了定位权限,重新获取位置
|
|
|
+ this.doGetLocation();
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: '未开启定位权限', icon: 'none' });
|
|
|
+ this.isLocating = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ uni.showToast({ title: '打开设置失败', icon: 'none' });
|
|
|
+ this.isLocating = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.isLocating = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 已有权限或未申请过权限,直接获取位置
|
|
|
+ this.doGetLocation();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ uni.showToast({ title: '权限检查失败', icon: 'none' });
|
|
|
+ this.isLocating = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 实际执行获取位置的方法
|
|
|
+ doGetLocation(value) {
|
|
|
let self = this;
|
|
|
uni.getLocation({
|
|
|
- type: 'gcj02', // 'wgs84' GPS坐标, 'gcj02' 国测局坐标
|
|
|
+ type: 'gcj02',
|
|
|
isHighAccuracy: true,
|
|
|
- geocode: true, // 获取带有地址信息(仅App和H5支持)
|
|
|
+ geocode: true,
|
|
|
success: (res) => {
|
|
|
console.log('当前位置信息:', res);
|
|
|
parseLocation(res.latitude, res.longitude).then(res=>{
|
|
|
if("Success" === res.data.message){
|
|
|
let formatted_addresses = res.data.result.formatted_addresses
|
|
|
+ if ( value === 'imageAddress'){
|
|
|
+ self.imageAddress = formatted_addresses.standard_address;
|
|
|
+ console.log('图片地址:', self.imageAddress);
|
|
|
+ return;
|
|
|
+ }
|
|
|
self.formData.address = formatted_addresses.standard_address
|
|
|
}else{
|
|
|
uni.showToast({ title: '解析地址失败', icon: 'none' });
|
|
|
}
|
|
|
-
|
|
|
- })
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('地址解析错误:', err);
|
|
|
+ uni.showToast({ title: '地址解析失败', icon: 'none' });
|
|
|
+ });
|
|
|
},
|
|
|
fail: (err) => {
|
|
|
- uni.showToast({ title: '获取位置失败', icon: 'none' });
|
|
|
- console.error(err);
|
|
|
+ console.error('获取位置失败:', err);
|
|
|
+ if (err.errCode === 103 || err.errMsg.includes('auth deny')) {
|
|
|
+ uni.showToast({ title: '定位权限被拒绝', icon: 'none' });
|
|
|
+ } else if (err.errCode === 101 || err.errMsg.includes('timeout')) {
|
|
|
+ uni.showToast({ title: '定位超时,请稍后重试', icon: 'none' });
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: '获取位置失败', icon: 'none' });
|
|
|
+ }
|
|
|
},
|
|
|
complete: () => {
|
|
|
this.isLocating = false;
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
+
|
|
|
+ // 修改后的图片选择处理方法
|
|
|
+ async onFileSelect(event) {
|
|
|
+ if (this.processingImages) {
|
|
|
+ uni.showToast({ title: '正在处理图片,请稍候', icon: 'none' });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.processingImages = true;
|
|
|
+ uni.showLoading({ title: '正在添加水印...' });
|
|
|
+
|
|
|
+ const newFiles = event.tempFiles;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 对新选择的文件添加水印
|
|
|
+ const watermarkedFiles = await this.processImagesWithWatermark(newFiles, this.imageAddress);
|
|
|
+
|
|
|
+ // 保留之前已选择的图片,添加新的带水印图片
|
|
|
+ const existingPhotos = this.formData.photos.filter(photo => photo.url);
|
|
|
+ const newPhotos = watermarkedFiles.map(file => ({
|
|
|
+ ...file,
|
|
|
+ url: file.path || file.url
|
|
|
+ }));
|
|
|
+
|
|
|
+ this.formData.photos = [...existingPhotos, ...newPhotos];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理图片失败:', error);
|
|
|
+ uni.showToast({ title: '图片处理失败', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ this.processingImages = false;
|
|
|
+ uni.hideLoading();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
// 提交表单
|
|
|
async submitForm() {
|
|
|
- if(this.$refs.files.files.length === 0){
|
|
|
+ if(this.formData.photos.length === 0){
|
|
|
uni.showToast({ title: '请上传门店照片', icon: 'none' });
|
|
|
return;
|
|
|
}
|
|
|
- const imageUrlarr = await uploadImage(this.$refs.files.files);
|
|
|
- if(imageUrlarr.length === 0){
|
|
|
- uni.showToast({ title: '门店照片上传失败,请重试', icon: 'none' });
|
|
|
- return;
|
|
|
- }
|
|
|
- // --- 手动进行数据校验 ---
|
|
|
+
|
|
|
+ // 数据校验
|
|
|
if (!this.formData.storeName) {
|
|
|
uni.showToast({ title: '请输入店铺名称', icon: 'none' });
|
|
|
return;
|
|
|
@@ -163,7 +431,6 @@ export default {
|
|
|
uni.showToast({ title: '请输入联系方式', icon: 'none' });
|
|
|
return;
|
|
|
}
|
|
|
- // 简单的手机号格式校验
|
|
|
if (!/^1[3-9]\d{9}$/.test(this.formData.contact)) {
|
|
|
uni.showToast({ title: '请输入正确的手机号码', icon: 'none' });
|
|
|
return;
|
|
|
@@ -173,47 +440,63 @@ export default {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- console.log('校验通过,准备提交的数据:', this.formData);
|
|
|
- // 执行提交逻辑
|
|
|
uni.showLoading({ title: '正在保存...' });
|
|
|
- if(this.formData.storeId>0){
|
|
|
- updateStore(this.formData.storeId,this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address,imageUrlarr.join(","))
|
|
|
- .then(res=>{
|
|
|
- uni.hideLoading();
|
|
|
- if(res.code == 0){
|
|
|
- uni.showToast({
|
|
|
- title: '保存成功',
|
|
|
- icon: 'success'
|
|
|
- });
|
|
|
- uni.navigateBack();
|
|
|
- }else{
|
|
|
- uni.showToast({
|
|
|
- title: res.msg,
|
|
|
- icon: 'none'
|
|
|
- });
|
|
|
- }
|
|
|
|
|
|
+ try {
|
|
|
+ // 直接上传已添加水印的图片
|
|
|
+ const filesToUpload = this.formData.photos.map(photo => ({
|
|
|
+ path: photo.url || photo.path
|
|
|
+ }));
|
|
|
|
|
|
- })
|
|
|
- }else{
|
|
|
- addStore(this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address,imageUrlarr.join(","))
|
|
|
- .then(res=>{
|
|
|
- uni.hideLoading();
|
|
|
- if(res.code == 0){
|
|
|
- uni.showToast({
|
|
|
- title: '保存成功',
|
|
|
- icon: 'success'
|
|
|
- });
|
|
|
- uni.navigateBack();
|
|
|
- }else{
|
|
|
- uni.showToast({
|
|
|
- title: res.msg,
|
|
|
- icon: 'none'
|
|
|
- });
|
|
|
- }
|
|
|
+ const imageUrlarr = await uploadImage(filesToUpload);
|
|
|
|
|
|
+ if(imageUrlarr.length === 0){
|
|
|
+ uni.showToast({ title: '门店照片上传失败,请重试', icon: 'none' });
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- })
|
|
|
+ if(this.formData.storeId>0){
|
|
|
+ updateStore(this.formData.storeId,this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address,imageUrlarr.join(","))
|
|
|
+ .then(res=>{
|
|
|
+ uni.hideLoading();
|
|
|
+ if(res.code == 0){
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存成功',
|
|
|
+ icon: 'success'
|
|
|
+ });
|
|
|
+ uni.navigateBack();
|
|
|
+ }else{
|
|
|
+ uni.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ addStore(this.formData.storeName,this.formData.ownerName,this.formData.contact,this.formData.address,imageUrlarr.join(","))
|
|
|
+ .then(res=>{
|
|
|
+ uni.hideLoading();
|
|
|
+ if(res.code == 0){
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存成功',
|
|
|
+ icon: 'success'
|
|
|
+ });
|
|
|
+ uni.navigateBack();
|
|
|
+ }else{
|
|
|
+ uni.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ uni.hideLoading();
|
|
|
+ console.error('提交失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -287,4 +570,19 @@ export default {
|
|
|
border: none;
|
|
|
}
|
|
|
}
|
|
|
-</style>
|
|
|
+
|
|
|
+/* 为uni-file-picker添加样式 */
|
|
|
+.file-picker {
|
|
|
+ margin-top: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 确保图片预览正常显示 */
|
|
|
+::v-deep .uni-file-picker__lists {
|
|
|
+ .uni-file-picker__lists-item {
|
|
|
+ image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|