1. 浙政钉微应用开发环境搭建开发浙政钉微应用前需要做好以下准备工作。首先确保你的开发环境已经安装Node.js建议版本12.x以上和npm包管理工具。与常规UniApp项目不同浙政钉微应用有特殊的构建要求。我推荐使用Vue CLI方式创建项目而不是直接使用HBuilder X。这是因为浙政钉要求前端文件必须部署到第三方服务器上需要通过npm run build命令构建。执行以下命令初始化项目npm install -g vue/cli vue create -p dcloudio/uni-preset-vue my-project项目创建完成后需要特别注意输出目录的配置。浙政钉默认要求输出到build目录但UniApp默认输出到dist目录。这里有两个解决方案第一种是修改package.json中的构建命令scripts: { build:h5: cross-env UNI_OUTPUT_DIRbuild NODE_ENVproduction UNI_PLATFORMh5 vue-cli-service uni-build }第二种是在项目根目录创建gbc.json配置文件{ type: build-config, version: 0.0.1, outputPath: dist }manifest.json文件也需要特殊配置否则会出现白屏或资源加载失败的问题{ h5: { publicPath: ./, router: { base: ./, mode: hash } } }2. 单点登录功能实现详解浙政钉微应用需要同时支持APP和支付宝小程序两种环境单点登录的实现方式也有所不同。我们先要检测当前运行环境const sUserAgent navigator.userAgent.toLowerCase(); const isDtDreamApp sUserAgent.indexOf(dtdreamweb) -1; // 浙政钉APP const isAlipayMini sUserAgent.indexOf(miniprogram) -1 sUserAgent.indexOf(alipay) -1; // 支付宝小程序针对不同环境的登录跳转实现function redirectToLogin() { if (isAlipayMini) { window.location.href https://puser.zjzwfw.gov.cn/sso/alipay.do?actionssoLoginservicecode你的接入码redirectUrl${encodeURIComponent(window.location.href)}; } else { window.location.href https://puser.zjzwfw.gov.cn/sso/mobile.do?actionoauthscope1servicecode你的接入码redirectUrl${encodeURIComponent(window.location.href)}; } }这里有几个关键点需要注意接入码需要向浙政钉申请服务接入获取redirectUrl参数需要encodeURIComponent编码如果不指定redirectUrl将使用后台配置的默认回调地址处理登录回调时我们需要从URL中提取ticket参数function getQueryParam(name) { const reg new RegExp((^|)${name}([^]*)(|$)); const r window.location.search.substr(1).match(reg); return r ! null ? decodeURIComponent(r[2]) : null; } const ticket getQueryParam(ticket);3. 用户信息获取的三种方式3.1 直接调用SSO接口拿到ticket后我们可以直接调用浙政钉的SSO接口获取用户信息。首先需要获取tokenasync function getToken(ticket) { const timeStr formatDate(new Date(), yyyymmddhhMMss); const params { servicecode: 你的接入码, time: timeStr, sign: md5(你的接入码${你的接入码密码}${timeStr}), st: ticket, datatype: json }; const res await uni.request({ url: https://appapi.zjzwfw.gov.cn/sso/servlet/simpleauth?methodticketValidation${serializeParams(params)}, method: POST }); if (res.data.result 0) { return res.data.token; } throw new Error(获取token失败); }获取到token后再调用获取用户信息接口async function getUserInfo(token) { const timeStr formatDate(new Date(), yyyymmddhhMMss); const params { servicecode: 你的接入码, time: timeStr, sign: md5(你的接入码${你的接入码密码}${timeStr}), token: token, datatype: json }; const res await uni.request({ url: https://appapi.zjzwfw.gov.cn/sso/servlet/simpleauth?methodgetUserInfo${serializeParams(params)}, method: POST }); if (res.data.result 0) { return res.data; } throw new Error(获取用户信息失败); }3.2 通过RPC网关调用直接调用接口可能会遇到跨域问题更推荐使用RPC网关方式。首先需要在中控台创建RPC系统并配置API安装网关SDKnpm install aligov/jssdk-mgop3.0.0网关调用示例import { mgop } from aligov/jssdk-mgop; async function getUserInfoByGateway(ticket) { const timeStr new Date().toGMTString(); const data { method: ticketValidation, servicecode: 你的接入码, time: formatDate(new Date(), yyyymmddhhMMss), st: ticket, datatype: json }; const res await mgop({ api: 你的API名称, host: https://mapi.zjzwfw.gov.cn/, data: data, dataType: JSON, type: POST, appKey: 你的AppKey, onSuccess: (res) { if (res.data.result 0) { return res.data; } throw new Error(res.data.message); }, onFail: (err) { throw new Error(err); } }); return res; }3.3 使用官方单点登录组件浙政钉还提供了官方单点登录组件使用起来更加方便// 在index.html中引入JSBridge script src//assets.zjzwfw.gov.cn/assets/ZWJSBridge/1.1.0/zwjsbridge.js/script // 在Vue组件中使用 ZWJSBridge.ssoTicket().then(res { if (res.result res.ticketId) { this.ticket res.ticketId; // 使用ticket获取用户信息 } else { ZWJSBridge.openLink({ type: reload }).then(res { this.ticket res.ticketId; }); } });4. 用户行为埋点实现方案4.1 旧版aplus.js埋点在public/index.html中引入aplus.jsscript (function(w, d, s, q, i) { w[q] w[q] || []; var f d.getElementsByTagName(s)[0], j d.createElement(s); j.async true; j.id beacon-aplus; j.src https://d.alicdn.com/alilog/mlog/aplus.js?id202951085; f.parentNode.insertBefore(j, f); })(window, document, script, aplus_queue); aplus_queue.push({ action: aplus.setMetaInfo, arguments: [aplus-rhost-v, alog.zjzwfw.gov.cn] }); // 其他初始化配置... /script页面PV埋点示例aplus_queue.push({ action: aplus.sendPV, arguments: [{ is_auto: false }, { miniAppId: 你的AppId, miniAppName: 你的应用名称, long: 经度, lati: 纬度, userType: 用户类型 }] });4.2 新版zwlog.js埋点新版埋点使用zwlog.js先在index.html中引入script src//assets.zjzwfw.gov.cn/assets/zwlog/1.0.0/zwlog.js/script初始化zwlog实例const zwlog new ZwLog({ _user_id: userInfo.userid || defaultId, _user_nick: userInfo.username || defaultName });发送页面PV和事件埋点// 页面PV zwlog.sendPV({ miniAppId: 你的AppId, Page_duration: 页面停留时长, t2: 页面加载时间 }); // 自定义事件 zwlog.record(eventCode, CLK, { buttonName: 提交按钮, clickTime: 2023-01-01 });5. JSBridge的深度应用浙政钉提供了丰富的JSBridge API需要在index.html中引入script src//assets.zjzwfw.gov.cn/assets/ZWJSBridge/1.1.0/zwjsbridge.js/script常用API示例// 设置页面标题 ZWJSBridge.setTitle({ title: 我的应用 }); // 获取用户位置 ZWJSBridge.getLocation().then(res { this.longitude res.longitude; this.latitude res.latitude; }); // 获取设备信息 ZWJSBridge.getDeviceInfo().then(res { console.log(res.deviceId, res.osVersion); }); // 调用扫一扫功能 ZWJSBridge.scanQRCode().then(res { this.scanResult res.text; });6. 适老化改造实践浙政钉要求应用支持适老化模式我们可以通过以下方式实现首先获取用户UI风格偏好ZWJSBridge.getUiStyle().then(res { this.uiStyle res.uiStyle elder ? elder : normal; });在样式中定义两套样式/* 普通模式 */ .normal-style { font-size: 14px; color: #333; } /* 适老模式 */ .elder-style { font-size: 18px; color: #000; line-height: 1.8; }在模板中动态应用样式view :class[uiStyle -style] !-- 页面内容 -- /view对于交互元素也需要做相应调整// 按钮点击效果增强 function handleClick() { if (this.uiStyle elder) { uni.showToast({ title: 操作成功, icon: none, duration: 2000 }); } // 正常业务逻辑 }7. 常见问题解决方案在实际开发中我遇到过几个典型问题问题1支付宝环境下图片上传损坏解决方案是重写上传组件使用浙政钉提供的APIZWJSBridge.chooseImage({ upload: true }).then(res { res.picPath.forEach(img { uni.uploadFile({ url: 你的上传接口, filePath: img, name: file, success: (uploadRes) { console.log(上传成功, uploadRes); } }); }); });问题2缓存API在支付宝环境首次加载失败建议使用uni-app自带的缓存API替代// 存储 uni.setStorageSync(key, value); // 读取 const value uni.getStorageSync(key);问题3地图集成问题高德地图在浙政钉环境下的特殊集成方式function initAMap() { return new Promise((resolve) { if (window.AMap) return resolve(window.AMap); const script document.createElement(script); script.src https://webapi.amap.com/maps?v1.4.15key你的keycallbackonAMapLoaded; document.head.appendChild(script); window.onAMapLoaded () resolve(window.AMap); }); }8. 性能优化与安全建议性能优化方面使用分包加载减少首屏体积// pages.json { subPackages: [{ root: subPackageA, pages: [...] }] }图片资源使用CDN加速image srchttps://your-cdn.com/image.png modeaspectFit/image安全建议敏感数据传输加密import JSEncrypt from jsencrypt; const encryptor new JSEncrypt(); encryptor.setPublicKey(你的公钥); const encrypted encryptor.encrypt(敏感数据);用户信息脱敏处理function desensitize(str, start, end) { if (!str) return ; const len str.length; const first str.substr(0, start); const last end 0 ? str.substr(len end) : str.substr(end); const stars *.repeat(len - start - Math.abs(end)); return first stars last; } // 使用示例 desensitize(13800138000, 3, -4); // 138****8000