feat(环境配置): 根据环境变量动态设置BASE_URL并优化页面配置
refactor(API): 移除mock接口,使用真实API调用 docs: 添加微信小程序发布审核指南文档
Showing
4 changed files
with
166 additions
and
71 deletions
doc/微信小程序发布审核指南.md
0 → 100644
| 1 | +# 微信小程序发布审核指南(实战版) | ||
| 2 | + | ||
| 3 | +目标:减少“代码审核不通过/反复驳回/二审时间变长”的概率,把风险点提前清掉。 | ||
| 4 | + | ||
| 5 | +本文聚焦两类信息: | ||
| 6 | +- 官方明确写在规则/指南里的硬性红线与提审要求 | ||
| 7 | +- 开发者高频踩坑(审核员常用驳回口径、容易被机器识别的文案/路径) | ||
| 8 | + | ||
| 9 | +## 1. 提审流程要点(别在流程上翻车) | ||
| 10 | + | ||
| 11 | +### 1.1 提审信息填写 | ||
| 12 | +- 服务类目必须与实际功能一致,且“类目对应页面”可直接体验(不隐藏、不多次跳转) | ||
| 13 | +- 简介要写清楚功能点,避免“提高体验/提升效率”等空话,且与名称、功能一致 | ||
| 14 | +- 若存在登录/付费/受限功能:必须提供可用测试账号/测试路径/说明,否则按“不可用/不完整”驳回 | ||
| 15 | + | ||
| 16 | +官方参考: | ||
| 17 | +- 小程序平台常见拒绝情形(含类目、基本信息、功能完整性等)https://developers.weixin.qq.com/minigame/product/reject | ||
| 18 | + | ||
| 19 | +### 1.2 审核可用性(审核员常用检查方式) | ||
| 20 | +- 从首页出发:两次点击内能到达所有核心功能页(尤其是你在提审页选择的类目对应页面) | ||
| 21 | +- 新用户体验:无缓存/无登录态打开不报错,不出现空白页/死循环 loading | ||
| 22 | +- 弱网/断网:不要直接白屏或无限 toast;至少给明确提示或离线降级 | ||
| 23 | + | ||
| 24 | +## 2. 最容易被拒的“写法/文案/入口” | ||
| 25 | + | ||
| 26 | +### 2.1 诱导分享/诱导关注(机器+人工都很敏感) | ||
| 27 | +高风险特征(建议彻底避免): | ||
| 28 | +- “分享/转发/朋友圈/群/邀请” + “奖励/积分/解锁/才能继续” | ||
| 29 | +- “关注公众号/关注后继续/关注领取/关注获取福利” | ||
| 30 | +- 用红点/强提示/遮罩引导用户点击分享 | ||
| 31 | + | ||
| 32 | +官方参考(诱导行为规则与处罚): | ||
| 33 | +- 运营规范/诱导分享相关条款(开放文档)https://developers.weixin.qq.com/minigame/product/index.html | ||
| 34 | +- 开放社区:滥用分享违规说明(含深度互动/利益诱导等示例)https://developers.weixin.qq.com/community/business/doc/0000441e234178e10d3d49fe45180d | ||
| 35 | + | ||
| 36 | +### 2.2 外链/跳转到非业务域名(尤其 web-view) | ||
| 37 | +高风险特征: | ||
| 38 | +- 在小程序内直接引导去 H5 付费/登录/完成核心流程 | ||
| 39 | +- web-view 打开未配置的业务域名,或用于绕过平台能力限制 | ||
| 40 | + | ||
| 41 | +建议: | ||
| 42 | +- 能用小程序原生能力就别用 web-view 承担核心流程 | ||
| 43 | +- 如果必须 web-view:业务域名在公众平台“开发-开发设置-业务域名”配置并校验 | ||
| 44 | + | ||
| 45 | +### 2.3 “虚拟支付”相关展示(iOS 特别敏感) | ||
| 46 | +典型驳回口径:小程序涉及虚拟产品购买,iOS 不支持,任何引导到支付流程的路径/文案都可能被拒(包含价格展示、购买按钮、引导去公众号/H5/外链付费等)。 | ||
| 47 | + | ||
| 48 | +官方/社区案例参考: | ||
| 49 | +- 开放社区驳回示例(含 iOS 虚拟支付常见口径)https://developers.weixin.qq.com/community/develop/doc/000082c5c882c8e25e297442a51400 | ||
| 50 | + | ||
| 51 | +注意: | ||
| 52 | +- 这里的“虚拟支付”主要指非实物/数字内容类;线下服务、门票等通常走正常微信支付更常见,但仍要避免“引导去外部支付”这类写法 | ||
| 53 | + | ||
| 54 | +## 3. 隐私合规与权限(2023+ 强制门槛,缺了直接拦截) | ||
| 55 | + | ||
| 56 | +### 3.1 必做:配置《用户隐私保护指引》 | ||
| 57 | +- 在小程序管理后台按实际情况声明:你收集哪些信息、用途、保存期限、共享对象等 | ||
| 58 | +- 若代码调用了微信“隐私接口/组件”,但后台未声明,会直接报无权限(也可能导致提审拦截) | ||
| 59 | + | ||
| 60 | +官方参考: | ||
| 61 | +- 用户隐私保护指引填写说明 https://developers.weixin.qq.com/miniprogram/dev/framework/user-privacy/ | ||
| 62 | +- 隐私协议开发指南(含 open-type=agreePrivacyAuthorization 等)https://developers.weixin.qq.com/miniprogram/dev/framework/user-privacy/PrivacyAuthorize.html | ||
| 63 | + | ||
| 64 | +### 3.2 隐私接口/组件常见清单(用到就要声明+授权同步) | ||
| 65 | +常见触发隐私合规校验的能力包括(举例): | ||
| 66 | +- 获取手机号(getPhoneNumber / getRealtimePhoneNumber) | ||
| 67 | +- 获取用户昵称头像组件(如 input type="nickname" 等) | ||
| 68 | +- 位置、相册、摄像头、通讯录、运动步数等相关能力(以官方隐私指引映射为准) | ||
| 69 | + | ||
| 70 | +开发建议: | ||
| 71 | +- 权限申请必须由用户主动触发(按钮点击等),不要在 onLoad/onShow 自动弹授权 | ||
| 72 | +- 只申请“用得到的最小权限”,并在 UI 上解释用途(更利于审核员理解) | ||
| 73 | + | ||
| 74 | +## 4. 容易被忽略但会驳回的工程类问题 | ||
| 75 | + | ||
| 76 | +### 4.1 “测试页/演示页/调试入口”进入生产包 | ||
| 77 | +常见后果: | ||
| 78 | +- 被认定为“功能不完整/不可用/与类目不一致” | ||
| 79 | +- 审核员进入测试页看到“模拟/开发调试/仅开发者工具可用”等字样,直接扣分 | ||
| 80 | + | ||
| 81 | +建议: | ||
| 82 | +- 测试页不要出现在生产 pages 列表里(开发环境可保留) | ||
| 83 | +- 不要在正式 UI 中暴露“模拟支付/测试按钮/开发入口” | ||
| 84 | + | ||
| 85 | +### 4.2 空白页、死循环、错误弹窗 | ||
| 86 | +常见后果:按“可用性和完整性不符合规则”驳回。 | ||
| 87 | + | ||
| 88 | +建议: | ||
| 89 | +- 核心流程必须能走通:预约->提交->支付->成功/失败->订单/二维码展示 | ||
| 90 | +- 网络错误要有兜底页或明确提示,避免无限 loading/toast | ||
| 91 | + | ||
| 92 | +## 5. 提交前自检清单(可直接照抄做发布门禁) | ||
| 93 | + | ||
| 94 | +### 5.1 功能可用性 | ||
| 95 | +- 新用户冷启动:首页可见内容不空白,不要求先手动操作才能看到任何内容 | ||
| 96 | +- 登录/授权:失败有明确提示,且不会无限跳转 | ||
| 97 | +- 支付(如有):成功/失败/取消都能回到可理解的状态;无“引导去外部付费” | ||
| 98 | + | ||
| 99 | +### 5.2 合规与文案 | ||
| 100 | +- 无“诱导分享/诱导关注/诱导下载/诱导抽奖”的强引导文案或图标 | ||
| 101 | +- 无“朋友圈”强指向文案(更建议用“分享给好友”“保存图片”这类中性表述) | ||
| 102 | +- 若涉及用户信息(身份证/手机号等):在产品侧能让用户查看隐私政策入口,后台隐私指引已按实际填写并通过 | ||
| 103 | + | ||
| 104 | +### 5.3 生产包清洁度 | ||
| 105 | +- pages 列表不包含 demo/test/nfc 等测试页面 | ||
| 106 | +- console/error 日志不输出敏感信息(身份证号、手机号、session 等) | ||
| 107 | + | ||
| 108 | +## 6. 发生驳回后的处理套路(提效) | ||
| 109 | +- 严格按驳回点改:只改一类问题,避免一次性改太多导致定位困难 | ||
| 110 | +- 截图/录屏给审核员“可复现路径”:从首页点击到具体页,展示已整改 | ||
| 111 | +- 不建议频繁撤回重提:重排队成本高;除非重大 bug 才撤回 | ||
| 112 | + | ||
| 113 | +社区经验参考(审核节奏、加急等): | ||
| 114 | +- 微信小程序过审指南(经验总结)https://github.com/lingziyao115/miniprogram |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-08-24 09:42:27 | 2 | * @Date: 2023-08-24 09:42:27 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-13 18:30:30 | 4 | + * @LastEditTime: 2026-01-13 20:55:13 |
| 5 | * @FilePath: /xyxBooking-weapp/src/api/index.js | 5 | * @FilePath: /xyxBooking-weapp/src/api/index.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -28,6 +28,7 @@ const Api = { | ... | @@ -28,6 +28,7 @@ const Api = { |
| 28 | QUERY_QR_CODE: '/srv/?a=api&t=id_number_query_qr_code', | 28 | QUERY_QR_CODE: '/srv/?a=api&t=id_number_query_qr_code', |
| 29 | ICBC_ORDER_QRY: '/srv/?a=icbc_orderqry', | 29 | ICBC_ORDER_QRY: '/srv/?a=icbc_orderqry', |
| 30 | WX_PAY: '/srv/?a=icbc_pay_wxamp', | 30 | WX_PAY: '/srv/?a=icbc_pay_wxamp', |
| 31 | + // TODO: 3个关于核销的接口都是假的, 等待真实接口 | ||
| 31 | VOLUNTEER_LOGIN: '/srv/?a=api&t=volunteer_login', | 32 | VOLUNTEER_LOGIN: '/srv/?a=api&t=volunteer_login', |
| 32 | VERIFY_TICKET: '/srv/?a=api&t=verify_ticket', | 33 | VERIFY_TICKET: '/srv/?a=api&t=verify_ticket', |
| 33 | GET_USER_INFO: '/srv/?a=api&t=get_user_info', | 34 | GET_USER_INFO: '/srv/?a=api&t=get_user_info', |
| ... | @@ -37,51 +38,21 @@ const Api = { | ... | @@ -37,51 +38,21 @@ const Api = { |
| 37 | * @description: 获取用户信息 (Mock) | 38 | * @description: 获取用户信息 (Mock) |
| 38 | */ | 39 | */ |
| 39 | export const getUserInfoAPI = () => { | 40 | export const getUserInfoAPI = () => { |
| 40 | - return new Promise((resolve) => { | 41 | + return fn(fetch.get(Api.GET_USER_INFO)); |
| 41 | - setTimeout(() => { | ||
| 42 | - // 模拟返回义工信息 | ||
| 43 | - resolve({ | ||
| 44 | - code: 1, | ||
| 45 | - data: { | ||
| 46 | - id: 'v_001', | ||
| 47 | - name: '义工管理员', | ||
| 48 | - role: 'volunteer', | ||
| 49 | - avatar: 'https://img12.360buyimg.com/imagetools/jfs/t1/196130/38/13621/2930/60c73831E00c07f30/526e068832877520.png' | ||
| 50 | - }, | ||
| 51 | - msg: '获取成功' | ||
| 52 | - }); | ||
| 53 | - }, 300); | ||
| 54 | - }); | ||
| 55 | - // 实际对接后应使用: return fn(fetch.get(Api.GET_USER_INFO)); | ||
| 56 | }; | 42 | }; |
| 57 | 43 | ||
| 58 | /** | 44 | /** |
| 59 | * @description: 义工登录 (Mock) | 45 | * @description: 义工登录 (Mock) |
| 60 | */ | 46 | */ |
| 61 | export const volunteerLoginAPI = (params) => { | 47 | export const volunteerLoginAPI = (params) => { |
| 62 | - return new Promise((resolve) => { | 48 | + return fn(fetch.post(Api.VOLUNTEER_LOGIN, params)); |
| 63 | - setTimeout(() => { | ||
| 64 | - // 简单模拟: 任意非空账号密码即成功,或者指定 admin/123456 | ||
| 65 | - if (params.username && params.password) { | ||
| 66 | - resolve({ code: 1, data: { token: 'mock_token' }, msg: '登录成功' }); | ||
| 67 | - } else { | ||
| 68 | - resolve({ code: 0, data: null, msg: '账号或密码错误' }); | ||
| 69 | - } | ||
| 70 | - }, 500); | ||
| 71 | - }); | ||
| 72 | - // 实际对接后应使用: return fn(fetch.post(Api.VOLUNTEER_LOGIN, params)); | ||
| 73 | }; | 49 | }; |
| 74 | 50 | ||
| 75 | /** | 51 | /** |
| 76 | * @description: 核销门票 (Mock) | 52 | * @description: 核销门票 (Mock) |
| 77 | */ | 53 | */ |
| 78 | -export const verifyTicketAPI = () => { | 54 | +export const verifyTicketAPI = (params) => { |
| 79 | - return new Promise((resolve) => { | 55 | + return fn(fetch.post(Api.VERIFY_TICKET, params)); |
| 80 | - setTimeout(() => { | ||
| 81 | - resolve({ code: 1, data: { status: 'success' }, msg: '核销成功' }); | ||
| 82 | - }, 500); | ||
| 83 | - }); | ||
| 84 | - // 实际对接后应使用: return fn(fetch.post(Api.VERIFY_TICKET, params)); | ||
| 85 | }; | 56 | }; |
| 86 | 57 | ||
| 87 | /** | 58 | /** | ... | ... |
| ... | @@ -5,42 +5,51 @@ | ... | @@ -5,42 +5,51 @@ |
| 5 | * @FilePath: /xyxBooking-weapp/src/app.config.js | 5 | * @FilePath: /xyxBooking-weapp/src/app.config.js |
| 6 | * @Description: 小程序配置文件 | 6 | * @Description: 小程序配置文件 |
| 7 | */ | 7 | */ |
| 8 | +const pages = [ | ||
| 9 | + 'pages/index/index', | ||
| 10 | + 'pages/auth/index', | ||
| 11 | + 'pages/notice/index', | ||
| 12 | + 'pages/booking/index', | ||
| 13 | + 'pages/submit/index', | ||
| 14 | + 'pages/addVisitor/index', | ||
| 15 | + 'pages/success/index', | ||
| 16 | + 'pages/bookingCode/index', | ||
| 17 | + 'pages/bookingList/index', | ||
| 18 | + 'pages/bookingDetail/index', | ||
| 19 | + 'pages/me/index', | ||
| 20 | + 'pages/waiting/index', | ||
| 21 | + 'pages/callback/index', | ||
| 22 | + 'pages/search/index', | ||
| 23 | + 'pages/visitorList/index', | ||
| 24 | + 'pages/volunteerLogin/index', | ||
| 25 | + 'pages/verificationResult/index', | ||
| 26 | + 'pages/weakNetwork/index', | ||
| 27 | + 'pages/offlineBookingCode/index', | ||
| 28 | + 'pages/offlineBookingList/index', | ||
| 29 | + 'pages/offlineBookingDetail/index', | ||
| 30 | +] | ||
| 31 | + | ||
| 32 | +if (process.env.NODE_ENV === 'development') { | ||
| 33 | + pages.push('pages/nfcTest/index') | ||
| 34 | + pages.push('pages/tailwindTest/index') | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +const subpackages = process.env.NODE_ENV === 'development' | ||
| 38 | + ? [ | ||
| 39 | + { | ||
| 40 | + root: 'pages/demo', | ||
| 41 | + pages: ['index'], | ||
| 42 | + }, | ||
| 43 | + ] | ||
| 44 | + : [] | ||
| 45 | + | ||
| 8 | export default { | 46 | export default { |
| 9 | - pages: [ | 47 | + pages, |
| 10 | - 'pages/index/index', | 48 | + subpackages, |
| 11 | - 'pages/auth/index', | ||
| 12 | - 'pages/notice/index', | ||
| 13 | - 'pages/booking/index', | ||
| 14 | - 'pages/submit/index', | ||
| 15 | - 'pages/addVisitor/index', | ||
| 16 | - 'pages/success/index', | ||
| 17 | - 'pages/bookingCode/index', | ||
| 18 | - 'pages/bookingList/index', | ||
| 19 | - 'pages/bookingDetail/index', | ||
| 20 | - 'pages/me/index', | ||
| 21 | - 'pages/waiting/index', | ||
| 22 | - 'pages/callback/index', | ||
| 23 | - 'pages/search/index', | ||
| 24 | - 'pages/visitorList/index', | ||
| 25 | - 'pages/volunteerLogin/index', | ||
| 26 | - 'pages/verificationResult/index', | ||
| 27 | - 'pages/weakNetwork/index', | ||
| 28 | - 'pages/offlineBookingCode/index', | ||
| 29 | - 'pages/offlineBookingList/index', | ||
| 30 | - 'pages/offlineBookingDetail/index', | ||
| 31 | - 'pages/nfcTest/index', | ||
| 32 | - 'pages/tailwindTest/index', | ||
| 33 | - ], | ||
| 34 | - subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去 | ||
| 35 | - { | ||
| 36 | - root: 'pages/demo', | ||
| 37 | - pages: ['index'], | ||
| 38 | - }, | ||
| 39 | - ], | ||
| 40 | window: { | 49 | window: { |
| 41 | backgroundTextStyle: 'light', | 50 | backgroundTextStyle: 'light', |
| 42 | navigationBarBackgroundColor: '#fff', | 51 | navigationBarBackgroundColor: '#fff', |
| 43 | navigationBarTitleText: '西园寺预约', | 52 | navigationBarTitleText: '西园寺预约', |
| 44 | - navigationBarTextStyle: 'black' | 53 | + navigationBarTextStyle: 'black', |
| 45 | - } | 54 | + }, |
| 46 | } | 55 | } | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-08 16:42:38 | 4 | + * @LastEditTime: 2026-01-13 20:49:09 |
| 5 | * @FilePath: /xyxBooking-weapp/src/utils/config.js | 5 | * @FilePath: /xyxBooking-weapp/src/utils/config.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| 8 | // TAG:服务器环境配置 | 8 | // TAG:服务器环境配置 |
| 9 | -const BASE_URL = "https://oa-dev.onwall.cn"; // 测试服务器 | 9 | +const BASE_URL = process.env.NODE_ENV === 'production' |
| 10 | -// const BASE_URL = "https://oa.onwall.cn"; // 正式服务器 | 10 | + ? 'https://oa.onwall.cn' |
| 11 | + : 'https://oa-dev.onwall.cn' | ||
| 11 | 12 | ||
| 12 | /** | 13 | /** |
| 13 | * 接口默认公共参数(避免在多个文件里硬编码) | 14 | * 接口默认公共参数(避免在多个文件里硬编码) | ... | ... |
-
Please register or login to post a comment