| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- <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">
- <text class="form-label">店铺名称</text>
- <input
- class="form-input"
- v-model="formData.storeName"
- placeholder="请输入店铺名称"
- placeholder-class="placeholder"
- />
- </view>
- <view class="form-item">
- <text class="form-label">店主名称</text>
- <input
- class="form-input"
- v-model="formData.ownerName"
- placeholder="请输入店主名称"
- placeholder-class="placeholder"
- />
- </view>
- <view class="form-item">
- <text class="form-label">联系方式</text>
- <input
- class="form-input"
- type="number"
- maxlength="11"
- v-model="formData.contact"
- placeholder="请输入联系方式"
- placeholder-class="placeholder"
- />
- </view>
- <view class="form-item" style="position: relative">
- <text class="form-label">店铺地址</text>
- <input
- class="form-input"
- v-model="formData.address"
- placeholder="请输入店铺地址"
- placeholder-class="placeholder"
- />
- <uni-icons @click="getLocation" style="position: absolute;bottom:20px;right: 20px;z-index: 999" type="location-filled" size="30" color="#3c82f8"></uni-icons>
- </view>
- <view class="form-item">
- <text class="form-label">店铺照片</text>
- <uni-file-picker
- class="file-picker"
- ref="files"
- :del-icon="edit"
- file-mediatype="image"
- mode="grid"
- :limit="9"
- title="最多选择9张图片"
- @tap="checkPermissionBeforeSelect"
- @select="handleFileSelect"
- v-model="formData.photos"
- />
- </view>
- </view>
- <view class="footer-save-button" v-if="edit">
- <button class="save-btn" @click="submitForm" >保 存</button>
- </view>
- </view>
- </template>
- <script>
- import {addStore, getRetailDetail, updateStore, uploadImage,parseLocation} from "@/api/hexiao";
- export default {
- data() {
- return {
- edit:false,
- isLocating:false,
- canvasWidth: 800,
- canvasHeight: 600,
- processingImages: false,
- imageAddress: '',
- // 表单数据
- formData: {
- photos: [],
- storeId: 0,
- storeName: '',
- ownerName: '',
- contact: '',
- address: ''
- }
- };
- },
- 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,
- }
- 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();
- }
- } 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 > 20) {
- addressText = address.substring(0, 20) + '...';
- }
- 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
- });
- }
- 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',
- isHighAccuracy: true,
- 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) => {
- 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.formData.photos.length === 0){
- uni.showToast({ title: '请上传门店照片', icon: 'none' });
- return;
- }
- // 数据校验
- if (!this.formData.storeName) {
- uni.showToast({ title: '请输入店铺名称', icon: 'none' });
- return;
- }
- if (!this.formData.ownerName) {
- uni.showToast({ title: '请输入店主名称', icon: 'none' });
- return;
- }
- if (!this.formData.contact) {
- uni.showToast({ title: '请输入联系方式', icon: 'none' });
- return;
- }
- if (!/^1[3-9]\d{9}$/.test(this.formData.contact)) {
- uni.showToast({ title: '请输入正确的手机号码', icon: 'none' });
- return;
- }
- if (!this.formData.address) {
- uni.showToast({ title: '请输入店铺地址', icon: 'none' });
- return;
- }
- uni.showLoading({ title: '正在保存...' });
- try {
- // 直接上传已添加水印的图片
- const filesToUpload = this.formData.photos.map(photo => ({
- path: photo.url || photo.path
- }));
- 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'
- });
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .page-container {
- min-height: 100vh;
- background: linear-gradient(to bottom, #e4efff, #f5f6fa 40%);
- padding: 30rpx;
- box-sizing: border-box;
- }
- .form-card {
- background-color: #ffffff;
- border-radius: 20rpx;
- padding: 0 40rpx; // 左右内边距
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
- }
- .form-item {
- padding: 30rpx 0;
- border-bottom: 1rpx solid #f0f0f0;
- // 最后一个item不需要下边框
- &:last-child {
- border-bottom: none;
- }
- }
- .form-label {
- display: block; // 确保独占一行
- font-size: 30rpx;
- color: #333;
- font-weight: 500;
- }
- .form-input {
- margin-top: 20rpx; // 与label的间距
- font-size: 28rpx;
- color: #333;
- }
- .placeholder {
- color: #c0c4cc;
- }
- .footer-save-button {
- position: fixed;
- left: 0;
- bottom: 0;
- width: 100%;
- padding: 20rpx 30rpx;
- background-color: #f5f6fa;
- box-sizing: border-box;
- padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
- padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
- }
- .save-btn {
- background-color: #409eff;
- color: #ffffff;
- border-radius: 50rpx;
- font-size: 32rpx;
- height: 90rpx;
- line-height: 90rpx;
- &::after {
- border: none;
- }
- }
- /* 为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>
|