feat: 同步今日小程序与后台迭代版本
集中提交今日 API、管理端、小程序与部署文档调整,确保 Gitea 主分支与本地最新开发版本一致。 Made-with: Cursor
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
const app = getApp()
|
||||
const { getTypeOnly } = require('../../utils/resultFormat')
|
||||
const { request } = require('../../utils/request')
|
||||
const { buildRecoMiniProgramPath } = require('../../utils/recoMiniProgram.js')
|
||||
const { isAuditHideAiMode } = require('../../utils/miniprogramAuditGate.js')
|
||||
|
||||
/** 与超管「小程序 · 推荐文章展示」中「区块标题」一致;接口无字段时的兜底 */
|
||||
const PROFILE_RECO_LABEL_FALLBACK = '我的由来'
|
||||
|
||||
/** recent 单条:优先用 resultMeta 与结果页一致的「双项」文案 */
|
||||
function summaryFromRecentRecord(rec, testType) {
|
||||
@@ -34,6 +39,10 @@ Page({
|
||||
pdpTime: '',
|
||||
aiTime: '',
|
||||
reviewMode: false,
|
||||
/** 超管「小程序提审模式」:与 reviewMode 一样隐藏推广/部分营销入口 */
|
||||
mpAuditMode: false,
|
||||
/** 仅 miniprogramAuditMode:隐藏「了解自己」深度套餐入口(虚拟商品合规) */
|
||||
showDeepPricingEntry: true,
|
||||
/** 最近记录的数据库 ID,用于跳转时传参 */
|
||||
mbtiResultId: null,
|
||||
sbtiResultId: null,
|
||||
@@ -66,15 +75,16 @@ Page({
|
||||
showLatestTestRow: false,
|
||||
/** 用户卡片下性格标签:在「当前权限下无任何问卷结果」时显示灰色提示 */
|
||||
showEmptyPersonalityTags: true,
|
||||
/** 我的页底部 Soul 推荐条(超管可配) */
|
||||
profileRecoShow: false,
|
||||
profileRecoSectionLabel: '',
|
||||
profileRecoArticle: null
|
||||
profileRecoArticle: null,
|
||||
/** 与神仙 AI 精选推荐同源:配置了 AppID 时优先跳转目标小程序 */
|
||||
profileRecoJump: null
|
||||
},
|
||||
|
||||
_computeShowLatestTestRow(d) {
|
||||
const rm = !!(d.reviewMode)
|
||||
if (rm) {
|
||||
const hideFace = !!(d.reviewMode || d.mpAuditMode)
|
||||
if (hideFace) {
|
||||
return !!(d.permMbti || d.permSbti || d.permPdp || d.permDisc)
|
||||
}
|
||||
return !!(d.permMbti || d.permSbti || d.permPdp || d.permDisc || d.permFace)
|
||||
@@ -94,7 +104,8 @@ Page({
|
||||
this.runLoginThenLoad()
|
||||
},
|
||||
_syncPerms(overrides = {}) {
|
||||
const p = app.globalData.enterprisePermissions
|
||||
const gd = app.globalData || {}
|
||||
const p = gd.enterprisePermissions
|
||||
const next = {
|
||||
permFace: !p || p.face !== false,
|
||||
permMbti: !p || p.mbti !== false,
|
||||
@@ -102,6 +113,7 @@ Page({
|
||||
permPdp: !p || p.pdp !== false,
|
||||
permDisc: !p || p.disc !== false,
|
||||
permDistribution: !p || p.distribution !== false,
|
||||
showDeepPricingEntry: !gd.miniprogramAuditMode,
|
||||
...overrides
|
||||
}
|
||||
const d = { ...this.data, ...next }
|
||||
@@ -114,7 +126,10 @@ Page({
|
||||
|
||||
onShow() {
|
||||
const gd = app.globalData
|
||||
this._syncPerms({ reviewMode: !!(gd.reviewMode || gd.maintenanceMode) })
|
||||
this._syncPerms({
|
||||
reviewMode: !!(gd.reviewMode || gd.maintenanceMode),
|
||||
mpAuditMode: isAuditHideAiMode(gd)
|
||||
})
|
||||
// 如果是从其他页面返回,且已经登录,则只刷新数据而不重新执行登录流程
|
||||
if (this.data.hasLogin) {
|
||||
this.loadData()
|
||||
@@ -173,7 +188,10 @@ Page({
|
||||
|
||||
loadData() {
|
||||
const gd = app.globalData
|
||||
this._syncPerms({ reviewMode: !!(gd.reviewMode || gd.maintenanceMode) })
|
||||
this._syncPerms({
|
||||
reviewMode: !!(gd.reviewMode || gd.maintenanceMode),
|
||||
mpAuditMode: isAuditHideAiMode(gd)
|
||||
})
|
||||
|
||||
const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo')
|
||||
const token = app.globalData.token || wx.getStorageSync('token')
|
||||
@@ -209,41 +227,105 @@ Page({
|
||||
this._loadPromoStats()
|
||||
this._loadProfileRecoTeaser()
|
||||
} else {
|
||||
this.setData({ profileRecoShow: false, profileRecoArticle: null, profileRecoSectionLabel: '' })
|
||||
this.setData({
|
||||
profileRecoShow: false,
|
||||
profileRecoArticle: null,
|
||||
profileRecoSectionLabel: '',
|
||||
profileRecoJump: null
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/** 拉取「我的」页推荐条:与超管 Soul 文章推荐位第 1 篇一致 */
|
||||
_parseRecoJumpFromDisplay(d) {
|
||||
if (!d || typeof d !== 'object') return null
|
||||
const appId = ((d.recoJumpMiniAppId || '') + '').trim()
|
||||
if (!appId || !/^wx[0-9a-f]{16}$/i.test(appId)) return null
|
||||
const envRaw = ((d.recoJumpMiniEnvVersion || 'release') + '').trim().toLowerCase()
|
||||
const env = envRaw === 'trial' || envRaw === 'develop' ? envRaw : 'release'
|
||||
let path = ((d.recoJumpMiniPath || 'pages/index/index') + '').trim().replace(/^\//, '')
|
||||
if (!path) path = 'pages/index/index'
|
||||
return { appId: appId.toLowerCase(), path, envVersion: env }
|
||||
},
|
||||
|
||||
_applyProfileTeaserPayload(d) {
|
||||
const art = d.article && d.article.url ? d.article : null
|
||||
const show = !!(d.enabled && art)
|
||||
this.setData({
|
||||
profileRecoShow: show,
|
||||
profileRecoSectionLabel: (d.sectionLabel && String(d.sectionLabel).trim()) || PROFILE_RECO_LABEL_FALLBACK,
|
||||
profileRecoArticle: show ? art : null,
|
||||
profileRecoJump: show ? this._parseRecoJumpFromDisplay(d) : null
|
||||
})
|
||||
},
|
||||
|
||||
_loadProfileRecoTeaser() {
|
||||
const t = Date.now()
|
||||
const finishFail = () =>
|
||||
this.setData({
|
||||
profileRecoShow: false,
|
||||
profileRecoArticle: null,
|
||||
profileRecoSectionLabel: '',
|
||||
profileRecoJump: null
|
||||
})
|
||||
|
||||
const tryLegacyPath = () => {
|
||||
request({
|
||||
url: `/api/ai/articles/profile-teaser?_t=${Date.now()}`,
|
||||
method: 'GET',
|
||||
needAuth: false,
|
||||
success: (res) => {
|
||||
const payload = res && res.data
|
||||
if (!payload || payload.code !== 200 || !payload.data) {
|
||||
finishFail()
|
||||
return
|
||||
}
|
||||
this._applyProfileTeaserPayload(payload.data)
|
||||
},
|
||||
fail: finishFail
|
||||
})
|
||||
}
|
||||
|
||||
// 优先走 recommended?usage=profile(与已放行路径一致);部署新 API 后与 profile-teaser 结构相同
|
||||
request({
|
||||
url: `/api/ai/articles/profile-teaser?_t=${t}`,
|
||||
url: `/api/ai/articles/recommended?usage=profile&_t=${t}`,
|
||||
method: 'GET',
|
||||
needAuth: false,
|
||||
success: (res) => {
|
||||
const payload = res && res.data
|
||||
if (!payload || payload.code !== 200 || !payload.data) {
|
||||
this.setData({ profileRecoShow: false, profileRecoArticle: null })
|
||||
tryLegacyPath()
|
||||
return
|
||||
}
|
||||
const d = payload.data
|
||||
const art = d.article && d.article.url ? d.article : null
|
||||
const show = !!(d.enabled && art)
|
||||
this.setData({
|
||||
profileRecoShow: show,
|
||||
profileRecoSectionLabel: (d.sectionLabel && String(d.sectionLabel).trim()) || '推荐阅读',
|
||||
profileRecoArticle: show ? art : null
|
||||
})
|
||||
if (Object.prototype.hasOwnProperty.call(d, 'article')) {
|
||||
this._applyProfileTeaserPayload(d)
|
||||
return
|
||||
}
|
||||
if (Array.isArray(d.list) && d.list.length) {
|
||||
const disp = d.display || {}
|
||||
const first = d.list[0]
|
||||
if (disp.enabled !== false && first && first.url) {
|
||||
this.setData({
|
||||
profileRecoShow: true,
|
||||
profileRecoSectionLabel: (disp.profileSectionLabel && String(disp.profileSectionLabel).trim()) || PROFILE_RECO_LABEL_FALLBACK,
|
||||
profileRecoArticle: first,
|
||||
profileRecoJump: this._parseRecoJumpFromDisplay(disp)
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
tryLegacyPath()
|
||||
},
|
||||
fail: () => {
|
||||
this.setData({ profileRecoShow: false, profileRecoArticle: null })
|
||||
}
|
||||
fail: tryLegacyPath
|
||||
})
|
||||
},
|
||||
|
||||
onTapProfileReco(e) {
|
||||
const { id, url, title } = (e && e.currentTarget && e.currentTarget.dataset) || {}
|
||||
if (!url) return
|
||||
const ds = (e && e.currentTarget && e.currentTarget.dataset) || {}
|
||||
const id = ds.id
|
||||
const url = ds.url
|
||||
const title = ds.title
|
||||
const sourceId = ds.sourceId
|
||||
try {
|
||||
require('../../utils/analytics').track('tap_ai_article', {
|
||||
articleId: id,
|
||||
@@ -261,6 +343,39 @@ Page({
|
||||
fail() {}
|
||||
})
|
||||
}
|
||||
const jump = this.data.profileRecoJump
|
||||
if (jump && jump.appId) {
|
||||
const path = buildRecoMiniProgramPath(jump.path, {
|
||||
id,
|
||||
title,
|
||||
sourceId,
|
||||
fromTag: 'mbti_profile_reco'
|
||||
})
|
||||
const env = jump.envVersion === 'trial' || jump.envVersion === 'develop' ? jump.envVersion : 'release'
|
||||
wx.navigateToMiniProgram({
|
||||
appId: jump.appId,
|
||||
path,
|
||||
envVersion: env,
|
||||
fail: (err) => {
|
||||
if (url) {
|
||||
const enc = encodeURIComponent(url)
|
||||
wx.navigateTo({
|
||||
url: `/pages/webview/index?url=${enc}`,
|
||||
fail: () => {
|
||||
wx.setClipboardData({
|
||||
data: url,
|
||||
success: () => wx.showToast({ title: '已复制链接', icon: 'none' })
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: (err && err.errMsg) || '无法打开目标小程序', icon: 'none' })
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!url) return
|
||||
const enc = encodeURIComponent(url)
|
||||
wx.navigateTo({
|
||||
url: `/pages/webview/index?url=${enc}`,
|
||||
@@ -436,6 +551,10 @@ Page({
|
||||
},
|
||||
/** 深度服务统一入口(页内 Tab:个人 / 团队与企业) */
|
||||
goToDeepService() {
|
||||
if (app.globalData && app.globalData.miniprogramAuditMode) {
|
||||
wx.showToast({ title: '版本审核中暂不可用', icon: 'none' })
|
||||
return
|
||||
}
|
||||
try { require('../../utils/analytics').track('tap_deep_service', {}) } catch (e) {}
|
||||
wx.navigateTo({ url: '/pages/purchase/index' })
|
||||
},
|
||||
@@ -447,9 +566,27 @@ Page({
|
||||
try { require('../../utils/analytics').track('tap_my_orders', {}) } catch (e) {}
|
||||
wx.navigateTo({ url: '/pages/order/index' })
|
||||
},
|
||||
goToPurchase() { wx.navigateTo({ url: '/pages/purchase/index' }) },
|
||||
goToPurchasePersonal() { wx.navigateTo({ url: '/pages/purchase/index?tab=personal' }) },
|
||||
goToPurchaseEnterprise() { wx.navigateTo({ url: '/pages/purchase/index?tab=enterprise' }) },
|
||||
goToPurchase() {
|
||||
if (app.globalData && app.globalData.miniprogramAuditMode) {
|
||||
wx.showToast({ title: '版本审核中暂不可用', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.navigateTo({ url: '/pages/purchase/index' })
|
||||
},
|
||||
goToPurchasePersonal() {
|
||||
if (app.globalData && app.globalData.miniprogramAuditMode) {
|
||||
wx.showToast({ title: '版本审核中暂不可用', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.navigateTo({ url: '/pages/purchase/index?tab=personal' })
|
||||
},
|
||||
goToPurchaseEnterprise() {
|
||||
if (app.globalData && app.globalData.miniprogramAuditMode) {
|
||||
wx.showToast({ title: '版本审核中暂不可用', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.navigateTo({ url: '/pages/purchase/index?tab=enterprise' })
|
||||
},
|
||||
goToEnterprise() { wx.navigateTo({ url: '/pages/enterprise/index' }) },
|
||||
goToPromoWithdrawals() {
|
||||
try { require('../../utils/analytics').track('tap_promo_withdrawals', { from: 'profile' }) } catch (e) {}
|
||||
@@ -526,7 +663,10 @@ Page({
|
||||
|
||||
onShareAppMessage() {
|
||||
const { getSharePathByScope } = require('../../utils/share')
|
||||
const rm = !!app.globalData.reviewMode
|
||||
const gd = app.globalData || {}
|
||||
if (gd.miniprogramAuditMode || gd.reviewMode || gd.maintenanceMode) {
|
||||
return { title: '性格测试', path: '/pages/index/index' }
|
||||
}
|
||||
return {
|
||||
title: '神仙团队性格测试 - 发现你的MBTI类型',
|
||||
path: getSharePathByScope('/pages/index/index')
|
||||
@@ -535,7 +675,10 @@ Page({
|
||||
|
||||
onShareTimeline() {
|
||||
const { buildShareQuery } = require('../../utils/share')
|
||||
const rm = !!app.globalData.reviewMode
|
||||
const gd = app.globalData || {}
|
||||
if (gd.miniprogramAuditMode || gd.reviewMode || gd.maintenanceMode) {
|
||||
return { title: '性格测试', query: '' }
|
||||
}
|
||||
return {
|
||||
title: '神仙团队性格测试 - 发现你的MBTI类型',
|
||||
query: buildShareQuery()
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
</view>
|
||||
<view
|
||||
class="user-stat"
|
||||
wx:if="{{promoDistributionEnabled && !reviewMode && permDistribution}}"
|
||||
wx:if="{{promoDistributionEnabled && !reviewMode && !mpAuditMode && permDistribution}}"
|
||||
bindtap="goToPromo"
|
||||
>
|
||||
<text class="user-stat__v">{{promoTotalInvite || 0}}</text>
|
||||
@@ -79,7 +79,7 @@
|
||||
<!-- 第三格:可提现 → 分销中心 -->
|
||||
<view
|
||||
class="user-stat user-stat--highlight"
|
||||
wx:if="{{promoDistributionEnabled && !reviewMode && permDistribution}}"
|
||||
wx:if="{{promoDistributionEnabled && !reviewMode && !mpAuditMode && permDistribution}}"
|
||||
bindtap="goToPromo"
|
||||
>
|
||||
<text class="user-stat__v">¥{{promoWithdrawable || '0.00'}}</text>
|
||||
@@ -88,7 +88,7 @@
|
||||
<!-- 第四格:累计 → 提现记录 -->
|
||||
<view
|
||||
class="user-stat user-stat--sub"
|
||||
wx:if="{{promoDistributionEnabled && !reviewMode && permDistribution}}"
|
||||
wx:if="{{promoDistributionEnabled && !reviewMode && !mpAuditMode && permDistribution}}"
|
||||
bindtap="goToPromoWithdrawals"
|
||||
>
|
||||
<text class="user-stat__v user-stat__v--sm">¥{{promoTotalEarned || '0.00'}}</text>
|
||||
@@ -144,7 +144,7 @@
|
||||
<text class="card-value">{{discType || '未测评'}}</text>
|
||||
<text class="card-time">{{discTime || '—'}}</text>
|
||||
</view>
|
||||
<view class="result-card card-teal {{(gallupPreview || aiType) ? '' : 'result-card--placeholder'}}" bindtap="viewGallup" wx:if="{{!reviewMode && permFace}}">
|
||||
<view class="result-card card-teal {{(gallupPreview || aiType) ? '' : 'result-card--placeholder'}}" bindtap="viewGallup" wx:if="{{!reviewMode && !mpAuditMode && permFace}}">
|
||||
<view class="card-deco"></view>
|
||||
<view class="card-icon-wrap card-icon-teal">
|
||||
<text class="card-icon">⭐</text>
|
||||
@@ -153,7 +153,7 @@
|
||||
<text class="card-value card-value--small">{{gallupPreview || (aiType ? '见面相报告' : '未测评')}}</text>
|
||||
<text class="card-time">{{aiTime || '—'}}</text>
|
||||
</view>
|
||||
<view class="result-card card-rose {{aiType ? '' : 'result-card--placeholder'}}" bindtap="viewAI" wx:if="{{!reviewMode && permFace}}">
|
||||
<view class="result-card card-rose {{aiType ? '' : 'result-card--placeholder'}}" bindtap="viewAI" wx:if="{{!reviewMode && !mpAuditMode && permFace}}">
|
||||
<view class="card-deco"></view>
|
||||
<view class="card-icon-wrap card-icon-rose">
|
||||
<text class="card-icon">👁️</text>
|
||||
@@ -178,7 +178,7 @@
|
||||
<view class="quick-grid__ic quick-grid__ic--emerald">🧾</view>
|
||||
<text class="quick-grid__label">我的订单</text>
|
||||
</view>
|
||||
<view class="quick-grid__item" bindtap="goToDeepService">
|
||||
<view class="quick-grid__item" wx:if="{{showDeepPricingEntry}}" bindtap="goToDeepService">
|
||||
<view class="quick-grid__ic quick-grid__ic--indigo">💎</view>
|
||||
<text class="quick-grid__label">了解自己</text>
|
||||
</view>
|
||||
@@ -189,7 +189,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Soul 引流:后台「当前推荐」第 1 篇 + 可配区块标题(灰字可点) -->
|
||||
<!-- Soul 引流:超管「我的页展示首条」+ 当前推荐第 1 篇 -->
|
||||
<view class="section px-section profile-reco-wrap" wx:if="{{hasLogin && profileRecoShow}}">
|
||||
<view
|
||||
class="profile-reco-card"
|
||||
@@ -198,6 +198,7 @@
|
||||
data-id="{{profileRecoArticle.id}}"
|
||||
data-url="{{profileRecoArticle.url}}"
|
||||
data-title="{{profileRecoArticle.title}}"
|
||||
data-source-id="{{profileRecoArticle.sourceId}}"
|
||||
>
|
||||
<text class="profile-reco-label">{{profileRecoSectionLabel}}</text>
|
||||
<view class="profile-reco-row">
|
||||
|
||||
@@ -6,8 +6,7 @@ page {
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background-color: #F9FAFB;
|
||||
/* 自定义 tabBar 加高 + 中间浮钮上移,多留底边距 */
|
||||
padding-bottom: calc(168rpx + env(safe-area-inset-bottom));
|
||||
/* 底栏避让由全局 .tabbar-pad / --tabbar-pad 统一控制 */
|
||||
}
|
||||
|
||||
custom-tab-bar {
|
||||
@@ -843,7 +842,6 @@ custom-tab-bar {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* ===== 我的页 · Soul 推荐条(灰字、可读) ===== */
|
||||
.profile-reco-wrap {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
@@ -862,7 +860,6 @@ custom-tab-bar {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #9ca3af;
|
||||
letter-spacing: 0.02em;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.profile-reco-row {
|
||||
|
||||
Reference in New Issue
Block a user