零、关于开发思路

(一)拿到工作任务,先理清楚需求

1.逻辑部分

不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问

2.页面部分(含国际化)

整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用

(时间充分的前提下,不要一味先复制粘贴再提取;要先提取直接使用)

开发过程中就国际化,可以仅把中文国际化做了zh.json,英文的最后找ai直接翻译一下给到en.json文件,这样一定程度上节约了时间,并且准确率极高

(否则容易出错-如用cursor直接最后国际化页面里的文本,漏提取or直接中文文本改错,等等问题)

3.swagger接口部分

遇到无厘头但可能相关的接口,问后端!

比如下面这个,登陆的时候勾选同意xxx协议,登陆成功后就要调用这个“用户协议操作记录接口”给到后端,后端记录一下。

(二)理清需求后,调研哪些点可能有阻碍

比如微信小程序权限-系统级别、微信APP级别、微信小程序级别(弄清楚产品要求各情况怎么处理)

比如原后端上传图片接口是否适配微信小程序uploadFile()方式

这些地方都要弄清楚,避免走弯路,尽早将可能遇到的困难问题摆出来,找更有经验的开发or百度or官网寻找解决方案,跟pm明确技术风险,并合理安排时间

避免由于忽视,前期困难点未理清楚导致错误排期and前后端走弯路

一、关于oss图片上传

(一)上传图片本身接口限制

1.微信小程序上传前提

微信小程序本身不直接支持原生的 FormData 对象但可以通过以下几种方式实现类似 form-data 格式的文件上传功能(这里使用了第一种官方推荐的,其他两种没尝试)

2.具体场景分析

原接口1:APP司机注册

POST ​/xxx/driver-app​/v1​/users

表单和上传图片文件都在一起用一个接口(post、formData)上传,2个参数,单文件

这里虽然都是单张图片,但是要分别传人像照和国徽照,且非必传

而uni.uploadFile(obj)的obj中,filePath/files必填,不能为null或者“”

(这里我尝试了用一个固定的下载了线上图片得到的临时地址,可以实现,但并不推荐)

原接口2:APP端运单货物操作: 提货、确认到达

POST ​/xxx​/driver-app​/v1​/waybills​/{id}​/actions​/loadings

表单和上传图片文件都在一起用一个接口(post、formData)上传,2个参数,多文件数组

(这里swagger写的有问题,事实上是数组,且必填)

这里传的是俩file数组,更不能直接用这个接口了。

后端尝试两种解决:

第一种:oss直传(未采纳)

刚开始后端直接抄的鸿蒙app实现,结果差不多的问题,不支持

鸿蒙前端是用put传的文件,微信小程序不支持的

不支持file类型

事实上阿里云分别提供了各种设备的实践demo,各不相同,适配各种环境。

所以以后要注意不能直接鸿蒙抄到微信小程序,不一定适配的。

如何在微信小程序环境下将文件上传到OSS_对象存储(OSS)-阿里云帮助中心微信小程序可以将图片、文档、视频等文件上传到OSS,实现文件的云端存储和分发。https://help.aliyun.com/zh/oss/use-cases/wechat-applet-uploads-files-directly-to-oss?spm=a2c4g.11186623.help-menu-31815.d_6_1_2_0.2944285cQPObLQ&scm=20140722.H_92883._.OR_help-T_cn~zh-V_1

最终后端研究之后决定不采用直传->前端传文件给阿里云这种形式了(觉得比较麻烦),选择单拎文件上传接口慢慢上传->前端传文件给后端,后端传文件给阿里云

第二种:单独创建上传文件的接口+创建小程序司机注册、货物操作接口(采纳)

上传文件接口

POST ​/xxx​/driver-app​/v1​/media​/upload

注册、货物操作-小程序接口

小程序的传参file/file[]改成了传string/string[]

(二)ios微信小程序照片不显示(安卓正常显示)

1.原因

2.解决方案

看一下后端返回的图片地址是否是http开头的,是的话需要让后端配置一下改成https或者前端处理http->https

A 后端处理(问的ai,并没尝试)-后端适配会更合适

B 前端处理(需确保 Bucket 支持 HTTPS)-本次采纳

oss_url = "http://bucket.oss-cn-hangzhou.aliyuncs.com/image.jpg"
https_url = oss_url.replace("http://", "https://")

(三)微信小程序上传下载文件需配置域名白名单

记得在小程序后台开发管理页配置uploadFile和downloadFile用到的合法域名

二、关于权限

(一)相机和相册权限(仍可能在某些设备如红米等机型出现问题)

1.uniapp封装的组件-uni-file-picker(内置了微信app级别的权限判断) 

uni-app官网

实现的效果——微信app有权限即能正常使用,无权限的话内置提示

如下图(安卓ios显示不同问题不大,但是安卓红米K80的相机没有弹出首次提醒)

2.自己写微信级别、微信小程序级别的的权限

代码判断什么的自己写,跟定位权限差不多,参考下文。权限从定位改成相机、相册,不用管系统级别权限而已。

(二)定位权限

1.微信小程序权限

uni.authorize(OBJECT) | uni-app官网

 uni.openSetting(OBJECT) | uni-app官网

2.系统/微信应用权限

系统信息的概念 | uni-app官网

3.代码

流程图

a.先微信小程序级别权限
/** 1.定位
 * @param callback
 * @param isChange 是否转换坐标系
 * @param type 提示语使用哪个
*/
export const getPosition = (isChange: boolean = true) => {
    return new Promise((resolve) => {
        // 授权获取地理位置
        uni.authorize({
            scope: 'scope.userLocation',
            success() {
                getLocation((res: any) => {
                    resolve(res);
                }, isChange)
            },
            // 小程序定位拒绝
            fail() {
                uni.showModal({
                    title: i18n.global.t('locationPermissionTitle'),
                    content: i18n.global.t('locationPermissionContent'),
                    confirmText: i18n.global.t('allow'),
                    cancelText: i18n.global.t('deny'),
                    confirmColor: '#218BFE',
                    cancelColor: '#999',
                    success: res => {
                        if (res.confirm) {
                            uni.openSetting({
                                success(res) {
                                    if (!res.authSetting['scope.userLocation']) {
                                        uni.showModal({
                                            content: i18n.global.t('locationNotEnabled'),
                                            showCancel: false,
                                            confirmText: i18n.global.t('iKnow'),
                                            confirmColor: '#1677FF',
                                            complete: () => {
                                                resolve(undefined);
                                            }
                                        })
                                    } else {
                                        resolve(undefined);
                                    }
                                }
                            });
                        } else if (res.cancel) {
                            // 不允许
                            resolve(undefined);
                        }
                    },
                    fail: () => {
                        resolve(undefined);
                    }
                });
            }
        });
    })
};
 b.再系统/微信级别权限+获取定位
/**
 * 2.获取定位
 */
export const getLocation = (callback: Function, isChange: boolean = true) => {
    uni.getLocation({
        type: 'gcj02',
        isHighAccuracy: true,
        success: function (res) {
            let result: any = {};
            const {longitude, latitude} = res;
            if (isEmpty(longitude) || isEmpty(latitude)) {
                const messageError = i18n.global.t('getLocationFailed');
                uni.showToast({
                    title: messageError,
                    icon: 'none',
                    duration: 2000,
                    complete: () => {
                        // 提示关闭后进行回调操作, 这里callback入参是undefined
                        setTimeout(callback, 2000);
                    }
                });
            } else {
                if (isChange) {
                    result = qqMapTransBMap(longitude, latitude);
                } else {
                    result = {
                        longitude,
                        latitude
                    };
                }
                callback(result);
            }
        },
        // 一般是微信定位拒绝
        fail: (error) => {
            const { locationAuthorized } = uni.getSystemInfoSync();
            console.error('getLocation error', error);
            const tip = !locationAuthorized ? i18n.global.t('wechatLocationDenied') : i18n.global.t('getLocationFailedGeneral');
            uni.showToast({
                title: tip,
                icon: 'none',
                duration: 2000,
                complete: () => {
                    // 提示关闭后进行回调操作
                    setTimeout(callback, 2000);
                }
            });
        }
    });
}

三、微信小程序坐标系及地理逆编码调研

(一)坐标系及三方

https://doc.dcloud.net.cn/uni-app-x/api/get-location.html#%E5%9D%90%E6%A0%87%E7%B3%BB%E3%80%81%E7%B3%BB%E7%BB%9F%E5%AE%9A%E4%BD%8D%E3%80%81%E4%B8%89%E6%96%B9%E5%AE%9A%E4%BD%8D%E7%AD%89%E6%A6%82%E5%BF%B5https://doc.dcloud.net.cn/uni-app-x/api/get-location.html#%E5%9D%90%E6%A0%87%E7%B3%BB%E3%80%81%E7%B3%BB%E7%BB%9F%E5%AE%9A%E4%BD%8D%E3%80%81%E4%B8%89%E6%96%B9%E5%AE%9A%E4%BD%8D%E7%AD%89%E6%A6%82%E5%BF%B5

微信小程序的getLocation可以两种坐标系,国际gps或者国标局gcj02(推荐国标局gcj02,wx.openLoction()要求用gcj02坐标系,且完美适配腾讯/高德地图sdk,百度地图也提供了官方转换方式)

自带没有api实现地理逆编码,要想实现的话需要使用三方sdk/api,比如腾讯/百度/高德地图

微信小程序JavaScript SDK | 腾讯位置服务

微信小程序JavaScript API | 百度地图API SDK

概述-微信小程序插件 | 高德地图API

(二)代码

腾讯gcj02百度互转

// 腾讯地图gcj02经纬度转百度地图
export function qqMapTransBMap(lng: number, lat: number) {
      let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
      let x = lng;
      let y = lat;
      let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
      let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
      let lngs = z * Math.cos(theta) + 0.0065;
      let lats = z * Math.sin(theta) + 0.006;
     
      return {
          latitude: lats,
		  longitude: lngs
      } 
}
// 百度地图经纬度转腾讯地图gcj02
export function BMapTransQQMap(lng: number, lat: number) {
      let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
      let x = lng - 0.0065;
      let y = lat - 0.006;
      let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
      let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
      let lngs = z * Math.cos(theta);
      let lats = z * Math.sin(theta);
      
      return {
          latitude: lats,
		  longitude: lngs
      }   
}

四、关于input

正则过滤输入,不支持pattern,pattern属性html才有

最后使用的是@input过滤+debounce实现(todo:寻找更好的方法)

五、关于toast

上一个toast会被下一个toast无缝替换(看不出前面的toast,只能看到最后一个toast)

小程序的提示uni.showToas会在页面跳转时消失,导致一闪而过看不清提示的情况--需加setTimeout延迟一下

六、关于防爆

一直以为就调接口需要防爆???

结果拍照页面点击上传也需要???

业务代码里用到了事件总线,由于异步,接口loading也没用,需要手动设置标志位(类似锁)防爆

ps:使用$on,$emit——因为navigateBack不能传参,又想特定时候更新上一页数据

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐