feat(miniapp): align UI with H5 and harden device debugging

五个页面按 h5/css 的 style.css → ui-20261009 → ui-20261012 覆盖顺序逐条重排,
换算规则固定为 calc(N * var(--u)) → 2N rpx,固定 px 的字号保持 px。

- app.acss:换回 H5 设计 token(方角小倒角按钮 10rpx、卡片 14rpx、.chev 折线箭头)
- splash/profile/history:底图与按钮文字图改用 H5 资源,隐私/政策弹窗按 H5 重排
- report:环形分用 conic-gradient、人脸裁切窗口叠加 face_maps、标记点百分比盒、
  侧脸皱纹 pending/unavailable 文案;用 Playwright 抓 H5 94 个选择器几何比对,
  整页高 2438.7 vs 2438.67
- camera:淘宝 <camera> 组件在真机整页崩溃(嵌了微信专有的 <cover-view>),
  改为默认系统相机 + `config.nativeCamera` 开关 + pages/camtest 冒烟页验证组件
- permissions:淘宝用带前缀的 scope.camera(裸名返回 5022 Scope:camera信息不存在),
  先试带前缀再退回裸名,拒绝后不再重复弹窗
- voice:非 HTTPS 资源导致的异常不再冒泡成整页崩溃;app.js 加开发版错误 toast
- 开发版入口:权限诊断(启动页/相机页)、相机组件测试
- 测试 20/20(新增权限与相机能力用例)
This commit is contained in:
xsl
2026-11-01 23:30:38 +08:00
parent f5c416dd9d
commit fed52930cc
33 changed files with 3061 additions and 876 deletions
+35 -6
View File
@@ -1,6 +1,7 @@
var api = require('../../utils/api'), image = require('../../utils/image'), voice = require('../../utils/voice');
var permissions = require('../../utils/permissions');
var development = require('../../utils/development');
var config = require('../../config');
var STEPS = [
{ target: 'front', tip: '请单人正脸出镜', turn: '正脸居中', mask: 0 },
{ target: 'right', tip: '请右脸出镜', turn: '请向左转头', mask: 2 },
@@ -9,14 +10,24 @@ var STEPS = [
Page({
data: { stepIndex: 0, stepText: '1/3', stepTip: STEPS[0].tip, guides: ['正脸居中', '取下眼镜', '光线充足'],
maskStep: 0, devicePosition: 'front', camError: false, previewUrl: '', doneTip: '', analyzing: false,
compressWidth: 1, compressHeight: 1, cameraEnabled: false, permissionMessage: '拍摄面部照片用于肌肤检测,请开启相机权限。',
debugMode: false, debugComplete: false, debugPhotos: [] },
compressWidth: 1, compressHeight: 1, cameraEnabled: false, permissionMessage: '',
debugMode: false, debugComplete: false, debugPhotos: [],
showDiagnose: config.environment !== 'production', diagText: '', cameraSupported: false },
onLoad: function (query) {
this.alive = true; this.visible = true; this.photos = []; this.busy = false; this.seq = 0;
var supported = config.nativeCamera === true &&
(typeof permissions.cameraSupported === 'function' ? permissions.cameraSupported() : true);
this.cameraSupported = supported;
this.debugMode = !!(query && query.debug === 'camera' && development.cameraDebugEnabled());
this.setData({ debugMode: this.debugMode });
this.setData({ debugMode: this.debugMode, cameraSupported: supported });
if (this.debugMode) return;
if (!api.user() || !getApp().globalData.profile) my.redirectTo({ url: '/pages/splash/splash' });
var app = typeof getApp === 'function' ? getApp() : null;
if (!api.user() || !app || !app.globalData.profile) { my.redirectTo({ url: '/pages/splash/splash' }); return; }
if (!supported) {
// 淘宝 <camera> 组件不可用:直接用系统相机/相册,页面不再挂相机组件(否则整页崩溃)
this.setData({ cameraEnabled: false, camError: true,
permissionMessage: '请用下方按钮拍摄,三张依次为正脸、右脸、左脸。' });
}
},
onReady: function () {
this.pageReady = true;
@@ -25,15 +36,17 @@ Page({
onShow: function () {
this.visible = true;
if (!this.data.previewUrl && !this.data.analyzing && !this.data.debugComplete) this.renderStep();
if (!this.cameraSupported) return; // 平台没有内置相机:直接用系统相机/相册
var that = this;
permissions.settings().then(function (current) {
if (!that.alive || !that.visible) return;
if (permissions.state(current, 'scope.camera') === true) { that.cameraAuthorized = true; that.mountCamera(); }
else if (permissions.state(current, 'scope.camera') === false) that.setData({ cameraEnabled: false, permissionMessage: '相机权限未开启,可前往授权设置或使用相册。' });
});
}).catch(function () {});
},
mountCamera: function () {
if (!this.alive || !this.visible || !this.pageReady || this.data.cameraEnabled || this.data.debugComplete) return;
if (!this.cameraSupported) return;
var that = this;
this.setData({ cameraEnabled: true, camError: false }, function () {
if (!that.alive || !that.visible) return;
@@ -56,6 +69,17 @@ Page({
if (permissions.state(current, 'scope.camera') === true) { that.cameraAuthorized = true; that.mountCamera(); }
}).catch(function (err) { if (that.alive) my.showToast({ content: err.message, type: 'none' }); });
},
onCloseDiagnose: function () { this.setData({ diagText: '' }); },
// 开发版:把真机上的相机能力/授权返回值直接打在页面上,供截图定位
onDiagnose: function () {
var that = this;
this.setData({ diagText: '检测中…' });
permissions.diagnose().then(function (info) {
if (that.alive) that.setData({ diagText: info.join('\n') });
}).catch(function (err) {
if (that.alive) that.setData({ diagText: 'diagnose error: ' + (err && err.message ? err.message : String(err)) });
});
},
onHide: function () { this.pause(); },
onUnload: function () { this.pause(); this.alive = false; this.photos = []; this.debugResults = []; },
pause: function () {
@@ -89,7 +113,12 @@ Page({
if (file) that.setData({ previewUrl: file });
else my.showToast({ content: '拍摄失败,请重试', type: 'none' });
}, fail: function () {
if (that.alive && that.visible) my.showToast({ content: '拍摄失败,请重试', type: 'none' });
if (!that.alive || !that.visible || seq !== that.seq) return;
// 真机上内置相机 takePhoto 失败(机型/组件差异、权限被拒等):
// 不打断流程,直接退回系统相机走 my.chooseImage 那条已验证过的路。
that.busy = false;
my.showToast({ content: '内置相机不可用,改用系统相机', type: 'none' });
that.choose(['camera']);
}, complete: function () { if (seq === that.seq) that.busy = false; } });
},
choose: function (sourceType) {