feat: CRM 报告与双端结果页、管理端用户/设置与默认企业配置
1、修复了用户详情与人脸/DISC 展示、手机号与资料校验、相机页与测试选择等体验问题。 2、新增了 SystemDefaultEnterprise、discDisplay、管理端设置扩展接口;CrmReport/Test/Analyze 等 API 与路由能力补强。 3、优化了 resultFormat、descriptions、payment、企业上下文;海报与 PDP/DISC 文案;超管 Commerce/Users 与 admin Settings/Users。 Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// pages/index/camera.js - 拍照页,拍完后上传到服务器再跳转结果页
|
||||
const app = getApp()
|
||||
const { hasPhone, bindPhoneByCode, ensureProfileCompleteAndRedirect } = require('../../utils/phoneAuth.js')
|
||||
const { ensureProfileCompleteAndRedirect } = require('../../utils/phoneAuth.js')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -9,7 +9,6 @@ Page({
|
||||
guideTexts: ['请正对镜头', '请向左转45°', '请向右转45°'],
|
||||
guideText: '请正对镜头',
|
||||
uploading: false,
|
||||
needPhoneAuth: false,
|
||||
aiAnalysisText: '分析',
|
||||
reviewMode: true
|
||||
},
|
||||
@@ -104,30 +103,6 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
// 本页就地授权手机号
|
||||
onGetPhoneNumber(e) {
|
||||
const { code, errMsg } = e.detail || {}
|
||||
if (errMsg && errMsg.indexOf('getPhoneNumber:fail') === 0) {
|
||||
wx.showToast({ title: '需要授权手机号才能继续', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!code && !hasPhone()) {
|
||||
wx.showToast({ title: '获取手机号失败', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!code && hasPhone()) {
|
||||
// 已有手机号,无需重复请求
|
||||
this.setData({ needPhoneAuth: false })
|
||||
return
|
||||
}
|
||||
bindPhoneByCode(code).then(() => {
|
||||
this.setData({ needPhoneAuth: false })
|
||||
}).catch(() => {
|
||||
// 失败时保持 needPhoneAuth 为 true,等待用户重新授权
|
||||
this.setData({ needPhoneAuth: !hasPhone() })
|
||||
})
|
||||
},
|
||||
|
||||
// 拍照
|
||||
takePhoto() {
|
||||
if (this.data.photos.length >= 3) {
|
||||
@@ -201,11 +176,6 @@ Page({
|
||||
|
||||
// 完成拍照:先上传 3 张图到服务器,拿到 URL 后再跳转结果页
|
||||
completeCapture() {
|
||||
if (!hasPhone()) {
|
||||
wx.showToast({ title: '请先授权手机号', icon: 'none' })
|
||||
this.setData({ needPhoneAuth: true })
|
||||
return
|
||||
}
|
||||
const photos = this.data.photos
|
||||
if (!photos || photos.length === 0) {
|
||||
wx.showToast({ title: '请先拍摄照片', icon: 'none' })
|
||||
|
||||
@@ -67,14 +67,6 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号授权入口:仅在未授权时显示,就地弹出微信系统手机号授权 -->
|
||||
<view class="phone-auth-section" wx:if="{{needPhoneAuth}}">
|
||||
<text class="phone-auth-tip">为保障服务与联系,请先授权手机号。</text>
|
||||
<button class="phone-auth-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
|
||||
授权手机号后继续拍摄
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<custom-tab-bar />
|
||||
</view>
|
||||
|
||||
@@ -225,31 +225,6 @@
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.phone-auth-section {
|
||||
padding: 24rpx 24rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.phone-auth-tip {
|
||||
font-size: 26rpx;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.phone-auth-btn {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(135deg, #7c3aed 0%, #5b21b6 100%);
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.phone-auth-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.capture-button {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
@@ -303,8 +303,8 @@
|
||||
.report-gate-cta-wrap {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
/* 占遮罩层约一半高度,保证内部 flex 垂直居中真正留白上下对称 */
|
||||
height: 48%;
|
||||
/* 遮挡/雾面展示区占 report-gate 整体的 55%,与渐变分层一致 */
|
||||
height: 55%;
|
||||
min-height: 400rpx;
|
||||
max-height: 640rpx;
|
||||
display: flex;
|
||||
@@ -323,14 +323,14 @@
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
/* 约前 50% 区域保持清晰预览,以下渐强变白 */
|
||||
/* 约前 45% 清晰预览;以下 55% 为渐强遮罩展示区 */
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0) 0%,
|
||||
rgba(255, 255, 255, 0) 50%,
|
||||
rgba(255, 255, 255, 0.2) 52%,
|
||||
rgba(255, 255, 255, 0.55) 68%,
|
||||
rgba(255, 255, 255, 0.82) 88%,
|
||||
rgba(255, 255, 255, 0) 45%,
|
||||
rgba(255, 255, 255, 0.2) 48%,
|
||||
rgba(255, 255, 255, 0.55) 64%,
|
||||
rgba(255, 255, 255, 0.82) 85%,
|
||||
rgba(255, 255, 255, 0.92) 100%
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
const app = getApp()
|
||||
const payment = require('../../utils/payment')
|
||||
const { getTypeOnly } = require('../../utils/resultFormat')
|
||||
const { isReportProfileComplete } = require('../../utils/phoneAuth.js')
|
||||
|
||||
function toProfileLockedDisc(full) {
|
||||
if (!full) return full
|
||||
return { dominantType: full.dominantType || full.disc || '', locked: true }
|
||||
}
|
||||
|
||||
function toIntPercent(v) {
|
||||
if (v == null) return 0
|
||||
@@ -28,10 +34,10 @@ Page({
|
||||
/** 主+次高权重展示(如 S+I型),与接口摘要一致 */
|
||||
typeSummaryLine: '',
|
||||
typeList: [
|
||||
{ type: 'D', label: 'D型 - 支配型', colorClass: 'fill-d' },
|
||||
{ type: 'I', label: 'I型 - 影响型', colorClass: 'fill-i' },
|
||||
{ type: 'S', label: 'S型 - 稳健型', colorClass: 'fill-s' },
|
||||
{ type: 'C', label: 'C型 - 谨慎型', colorClass: 'fill-c' }
|
||||
{ type: 'D', label: 'D型 - 力量', colorClass: 'fill-d' },
|
||||
{ type: 'I', label: 'I型 - 活跃', colorClass: 'fill-i' },
|
||||
{ type: 'S', label: 'S型 - 和平', colorClass: 'fill-s' },
|
||||
{ type: 'C', label: 'C型 - 完美', colorClass: 'fill-c' }
|
||||
],
|
||||
payInfo: { requiresPayment: false, isPaid: false, amountYuan: 0 },
|
||||
testResultId: null,
|
||||
@@ -46,10 +52,11 @@ Page({
|
||||
this.loadDetail(id)
|
||||
return
|
||||
}
|
||||
const result = wx.getStorageSync('discResult')
|
||||
if (result) {
|
||||
const r = withPercentagesInt(result)
|
||||
this.setData({ result: r, typeSummaryLine: getTypeOnly(result, 'disc') })
|
||||
const raw = wx.getStorageSync('discResult')
|
||||
if (raw) {
|
||||
const gated = isReportProfileComplete() ? raw : toProfileLockedDisc(raw)
|
||||
const r = withPercentagesInt(gated)
|
||||
this.setData({ result: r, typeSummaryLine: getTypeOnly(gated, 'disc') })
|
||||
this.initPayInfoFromRuntime('disc')
|
||||
} else {
|
||||
wx.showToast({ title: '暂无测试结果', icon: 'none' })
|
||||
@@ -95,6 +102,19 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (this.data.testResultId) return
|
||||
const raw = wx.getStorageSync('discResult')
|
||||
if (!raw) return
|
||||
const gated = isReportProfileComplete() ? raw : toProfileLockedDisc(raw)
|
||||
const r = withPercentagesInt(gated)
|
||||
this.setData({ result: r, typeSummaryLine: getTypeOnly(gated, 'disc') })
|
||||
},
|
||||
|
||||
goCompleteProfile() {
|
||||
wx.navigateTo({ url: '/pages/user-profile/index' })
|
||||
},
|
||||
|
||||
initPayInfoFromRuntime(testType) {
|
||||
app.getRuntimeConfig()
|
||||
.then((cfg) => {
|
||||
|
||||
@@ -25,7 +25,17 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scores-section" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="paywall-card" wx:elif="{{result && result.locked}}">
|
||||
<view class="paywall-content">
|
||||
<text class="paywall-fake-title">完整报告需完善资料</text>
|
||||
<text class="paywall-fake-line">请补全头像、昵称并绑定手机号后查看完整 DISC 报告。</text>
|
||||
<view class="paywall-btn" bindtap="goCompleteProfile">
|
||||
<text class="paywall-btn-main">去完善资料</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scores-section" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="section-title">DISC得分详情</text>
|
||||
<view class="score-item" wx:for="{{typeList}}" wx:key="type">
|
||||
<view class="score-header">
|
||||
@@ -39,7 +49,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="card-title">主要性格特征分析</text>
|
||||
<view class="trait-section">
|
||||
<text class="trait-title">优势</text>
|
||||
@@ -57,7 +67,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="card-title">职业匹配度分析</text>
|
||||
<view class="career-item" wx:for="{{result.description.careers}}" wx:key="*this">
|
||||
<view class="career-dot"></view>
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// pages/result/mbti.js - MBTI结果页(支持付费墙 + 历史详情拉取)
|
||||
const app = getApp()
|
||||
const payment = require('../../utils/payment')
|
||||
const { hasPhone, bindPhoneByCode } = require('../../utils/phoneAuth.js')
|
||||
const { hasPhone, bindPhoneByCode, isReportProfileComplete } = require('../../utils/phoneAuth.js')
|
||||
|
||||
function toProfileLockedMbti(full) {
|
||||
if (!full) return full
|
||||
return { mbtiType: full.mbtiType || full.mbti || '', locked: true }
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -35,8 +40,9 @@ Page({
|
||||
return
|
||||
}
|
||||
|
||||
const result = wx.getStorageSync('mbtiResult')
|
||||
if (result) {
|
||||
const raw = wx.getStorageSync('mbtiResult')
|
||||
if (raw) {
|
||||
const result = isReportProfileComplete() ? raw : toProfileLockedMbti(raw)
|
||||
this.applyResult(result)
|
||||
this.initPayInfoFromRuntime('mbti')
|
||||
} else {
|
||||
@@ -47,6 +53,16 @@ Page({
|
||||
|
||||
onShow() {
|
||||
this.setData({ hasPhone: hasPhone() })
|
||||
if (this.data.testResultId) return
|
||||
const raw = wx.getStorageSync('mbtiResult')
|
||||
if (raw) {
|
||||
const result = isReportProfileComplete() ? raw : toProfileLockedMbti(raw)
|
||||
this.applyResult(result)
|
||||
}
|
||||
},
|
||||
|
||||
goCompleteProfile() {
|
||||
wx.navigateTo({ url: '/pages/user-profile/index' })
|
||||
},
|
||||
|
||||
loadDetail(id) {
|
||||
|
||||
@@ -42,7 +42,17 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dimensions-section" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="paywall-card" wx:elif="{{result && result.locked}}">
|
||||
<view class="paywall-content">
|
||||
<text class="paywall-fake-title">完整报告需完善资料</text>
|
||||
<text class="paywall-fake-line">请补全头像、昵称并绑定手机号后查看完整性格分析。</text>
|
||||
<button class="paywall-btn" bindtap="goCompleteProfile">
|
||||
<text class="paywall-btn-main">去完善资料</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dimensions-section" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<view class="dimension-item" wx:for="{{dimensions}}" wx:key="key">
|
||||
<view class="dimension-labels">
|
||||
<text class="label-left">{{item.left}}</text>
|
||||
@@ -59,7 +69,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="card-title">性格特征分析</text>
|
||||
<view class="trait-section">
|
||||
<text class="trait-title">优势</text>
|
||||
@@ -86,7 +96,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{(!payInfo.requiresPayment || payInfo.isPaid) && mbtiDesc.relationships}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid) && mbtiDesc.relationships}}">
|
||||
<text class="card-title">人际关系分析</text>
|
||||
<text class="relationship-text">{{mbtiDesc.relationships}}</text>
|
||||
</view>
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
const app = getApp()
|
||||
const payment = require('../../utils/payment')
|
||||
const { getTypeOnly } = require('../../utils/resultFormat')
|
||||
const { isReportProfileComplete } = require('../../utils/phoneAuth.js')
|
||||
|
||||
function toProfileLockedPdp(full) {
|
||||
if (!full) return full
|
||||
const desc = full.description || {}
|
||||
return {
|
||||
description: { type: desc.type || '', emoji: desc.emoji || '' },
|
||||
locked: true
|
||||
}
|
||||
}
|
||||
|
||||
const PDP_KEYS = ['Tiger', 'Peacock', 'Koala', 'Owl', 'Chameleon']
|
||||
|
||||
@@ -28,7 +38,7 @@ Page({
|
||||
typeList: [
|
||||
{ type: 'Tiger', emoji: '🐅', label: '老虎型', colorClass: 'fill-tiger' },
|
||||
{ type: 'Peacock', emoji: '🦚', label: '孔雀型', colorClass: 'fill-peacock' },
|
||||
{ type: 'Koala', emoji: '🐨', label: '考拉型', colorClass: 'fill-koala' },
|
||||
{ type: 'Koala', emoji: '🐨', label: '无尾熊型', colorClass: 'fill-koala' },
|
||||
{ type: 'Owl', emoji: '🦉', label: '猫头鹰型', colorClass: 'fill-owl' },
|
||||
{ type: 'Chameleon', emoji: '🦎', label: '变色龙型', colorClass: 'fill-chameleon' }
|
||||
],
|
||||
@@ -95,6 +105,21 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (this.data.testResultId) return
|
||||
const raw = wx.getStorageSync('pdpResult')
|
||||
if (!raw) return
|
||||
const gated = isReportProfileComplete() ? raw : toProfileLockedPdp(raw)
|
||||
this.setData({
|
||||
result: withPercentagesInt(gated),
|
||||
typeSummaryLine: getTypeOnly(gated, 'pdp')
|
||||
})
|
||||
},
|
||||
|
||||
goCompleteProfile() {
|
||||
wx.navigateTo({ url: '/pages/user-profile/index' })
|
||||
},
|
||||
|
||||
initPayInfoFromRuntime(testType) {
|
||||
app.getRuntimeConfig()
|
||||
.then((cfg) => {
|
||||
|
||||
@@ -26,7 +26,17 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scores-section" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="paywall-card" wx:elif="{{result && result.locked}}">
|
||||
<view class="paywall-content">
|
||||
<text class="paywall-fake-title">完整报告需完善资料</text>
|
||||
<text class="paywall-fake-line">请补全头像、昵称并绑定手机号后查看完整 PDP 报告。</text>
|
||||
<view class="paywall-btn" bindtap="goCompleteProfile">
|
||||
<text class="paywall-btn-main">去完善资料</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scores-section" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="section-title">PDP得分详情</text>
|
||||
<view class="score-item" wx:for="{{typeList}}" wx:key="type">
|
||||
<view class="score-header">
|
||||
@@ -40,7 +50,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="card-title">性格特征</text>
|
||||
<view class="trait-section">
|
||||
<text class="trait-title">优势</text>
|
||||
@@ -58,12 +68,12 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="card-title">团队角色</text>
|
||||
<text class="relationship-text">{{result.description.teamRole}}</text>
|
||||
</view>
|
||||
|
||||
<view class="analysis-card" wx:if="{{!payInfo.requiresPayment || payInfo.isPaid}}">
|
||||
<view class="analysis-card" wx:if="{{result && !result.locked && (!payInfo.requiresPayment || payInfo.isPaid)}}">
|
||||
<text class="card-title">推荐职业</text>
|
||||
<view class="career-item" wx:for="{{result.description.careers}}" wx:key="*this">
|
||||
<view class="career-dot"></view>
|
||||
|
||||
@@ -21,7 +21,8 @@ Page({
|
||||
amountYuan: 0
|
||||
},
|
||||
testResultId: 0,
|
||||
paying: false
|
||||
paying: false,
|
||||
profileGate: false
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
@@ -36,8 +37,19 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
const id = this.data.testResultId
|
||||
if (id && this.data.profileGate) {
|
||||
this.loadFromHistory(String(id))
|
||||
}
|
||||
},
|
||||
|
||||
goCompleteProfile() {
|
||||
wx.navigateTo({ url: '/pages/user-profile/index' })
|
||||
},
|
||||
|
||||
loadFromHistory(id) {
|
||||
this.setData({ loading: true, error: '', content: '', sections: [], resumeData: null })
|
||||
this.setData({ loading: true, error: '', content: '', sections: [], resumeData: null, profileGate: false })
|
||||
const apiBase = (app.globalData && app.globalData.apiBase) || wx.getStorageSync('apiBase') || ''
|
||||
const token = (app.globalData && app.globalData.token) || wx.getStorageSync('token') || ''
|
||||
wx.request({
|
||||
@@ -53,30 +65,43 @@ Page({
|
||||
// 兼容:历史数据可能是字符串,或包在 content 里的 JSON 字符串
|
||||
data = this.normalizeStructuredData(data)
|
||||
|
||||
const profileIncomplete = payload.profileIncomplete === true
|
||||
const locked = !!(data && data.locked)
|
||||
const structured = !!data && data._structured === true
|
||||
|
||||
const requiresPayment = !!payload.requiresPayment
|
||||
const isPaid = !!payload.isPaid
|
||||
const amountYuan = payload.paidAmount ? payload.paidAmount / 100 : 0
|
||||
const payWall = requiresPayment && !isPaid
|
||||
const profileGate = !payWall && (profileIncomplete || locked)
|
||||
|
||||
let content = ''
|
||||
let sections = []
|
||||
let resumeData = null
|
||||
|
||||
if (structured) {
|
||||
if (payWall || profileGate) {
|
||||
content = ''
|
||||
sections = []
|
||||
resumeData = null
|
||||
} else if (structured) {
|
||||
const built = this.buildSectionsFromStructured(data)
|
||||
content = built.content
|
||||
sections = built.sections
|
||||
resumeData = data
|
||||
} else {
|
||||
const raw = data.content || ''
|
||||
content = raw
|
||||
sections = this.parseContent(raw)
|
||||
}
|
||||
const requiresPayment = !!payload.requiresPayment
|
||||
const isPaid = !!payload.isPaid
|
||||
const amountYuan = payload.paidAmount ? payload.paidAmount / 100 : 0
|
||||
|
||||
this.setData({
|
||||
loading: false,
|
||||
testResultId: payload.id || parseInt(id) || 0,
|
||||
content: (!requiresPayment || isPaid) ? content : '',
|
||||
sections: (!requiresPayment || isPaid) ? sections : [],
|
||||
resumeData: structured ? data : null,
|
||||
payInfo: { requiresPayment: requiresPayment && !isPaid, isPaid, amountYuan }
|
||||
content,
|
||||
sections,
|
||||
resumeData,
|
||||
profileGate,
|
||||
payInfo: { requiresPayment: payWall, isPaid, amountYuan }
|
||||
})
|
||||
} else {
|
||||
this.setData({ loading: false, error: '加载历史记录失败,请返回重试。' })
|
||||
@@ -140,15 +165,23 @@ Page({
|
||||
// 兼容:API 直接返回结构化对象,或把 JSON 放在 content 里
|
||||
d = this.normalizeStructuredData(d)
|
||||
|
||||
const locked = !!(d && d.locked)
|
||||
const structured = !!d && d._structured === true
|
||||
|
||||
let content = ''
|
||||
let sections = []
|
||||
let resumeData = null
|
||||
let profileGate = false
|
||||
|
||||
if (structured) {
|
||||
if (requiresPayment) {
|
||||
profileGate = false
|
||||
} else if (locked) {
|
||||
profileGate = true
|
||||
} else if (structured) {
|
||||
const built = this.buildSectionsFromStructured(d)
|
||||
content = built.content
|
||||
sections = built.sections
|
||||
resumeData = d
|
||||
} else {
|
||||
const raw = d.content || ''
|
||||
content = raw || '分析已完成,但未返回可展示的内容。'
|
||||
@@ -161,7 +194,8 @@ Page({
|
||||
testResultId: resultId,
|
||||
content: requiresPayment ? '' : content,
|
||||
sections: requiresPayment ? [] : sections,
|
||||
resumeData: structured ? d : null,
|
||||
resumeData,
|
||||
profileGate,
|
||||
payInfo: { requiresPayment, isPaid: !requiresPayment, amountYuan }
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 结果显示 -->
|
||||
<block wx:if="{{!loading || error || content}}">
|
||||
<block wx:if="{{!loading || error || content || profileGate}}">
|
||||
|
||||
<!-- 页面顶部 Hero -->
|
||||
<view class="hero-banner {{error ? 'hero-error' : 'hero-success'}}">
|
||||
@@ -50,8 +50,18 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 资料未完善:与问卷/面相报告一致 -->
|
||||
<view class="card pay-gate-card" wx:if="{{profileGate && (!payInfo.requiresPayment || payInfo.isPaid) && !error}}">
|
||||
<text class="pay-gate-icon">📝</text>
|
||||
<text class="pay-gate-title">完善资料后查看完整报告</text>
|
||||
<text class="pay-gate-desc">请补全头像、昵称并绑定手机号\n即可查看简历综合分析全文</text>
|
||||
<view class="pay-gate-btn" bindtap="goCompleteProfile">
|
||||
<text class="pay-gate-btn-text">去完善资料</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 成功内容:分块卡片展示 -->
|
||||
<block wx:if="{{content && sections.length > 0 && !payInfo.requiresPayment}}">
|
||||
<block wx:if="{{content && sections.length > 0 && !payInfo.requiresPayment && !profileGate}}">
|
||||
<view class="card section-card" wx:for="{{sections}}" wx:key="index">
|
||||
<view class="section-header">
|
||||
<text class="section-icon">{{item.icon}}</text>
|
||||
@@ -71,10 +81,10 @@
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-section" wx:if="{{!loading || error}}">
|
||||
<button class="btn btn-primary" open-type="share" wx:if="{{!payInfo.requiresPayment && content}}">
|
||||
<button class="btn btn-primary" open-type="share" wx:if="{{!payInfo.requiresPayment && !profileGate && content}}">
|
||||
<text class="btn-text">分享分析报告</text>
|
||||
</button>
|
||||
<view class="btn btn-outline" bindtap="fetchResumeAnalysis" wx:if="{{!loading && content && !payInfo.requiresPayment}}">
|
||||
<view class="btn btn-outline" bindtap="fetchResumeAnalysis" wx:if="{{!loading && content && !payInfo.requiresPayment && !profileGate}}">
|
||||
<text class="btn-text-outline">重新分析生成</text>
|
||||
</view>
|
||||
<view class="btn btn-outline" bindtap="goHome">
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</view>
|
||||
<view class="entry-content">
|
||||
<text class="entry-name">PDP 行为偏好测试</text>
|
||||
<text class="entry-brief">老虎 / 孔雀 / 考拉 / 猫头鹰 · 行为风格</text>
|
||||
<text class="entry-brief">老虎 / 孔雀 / 无尾熊 / 猫头鹰 / 变色龙 · 行为风格</text>
|
||||
</view>
|
||||
<text class="entry-arrow">→</text>
|
||||
</view>
|
||||
|
||||
@@ -19,15 +19,16 @@
|
||||
<text class="question-text">{{currentQuestion.question}}</text>
|
||||
<view class="options-container">
|
||||
<view
|
||||
class="option-item {{selectedAnswer === option.value ? 'selected' : ''}}"
|
||||
class="option-item {{answers[currentQuestion.id] === option.value ? 'selected' : ''}}"
|
||||
wx:for="{{currentQuestion.options}}"
|
||||
wx:for-item="option"
|
||||
wx:key="value"
|
||||
wx:for-index="optIdx"
|
||||
wx:key="optIdx"
|
||||
bindtap="selectAnswer"
|
||||
data-value="{{option.value}}"
|
||||
>
|
||||
<view class="radio-button {{selectedAnswer === option.value ? 'checked' : ''}}">
|
||||
<view wx:if="{{selectedAnswer === option.value}}" class="radio-inner"></view>
|
||||
<view class="radio-button {{answers[currentQuestion.id] === option.value ? 'checked' : ''}}">
|
||||
<view wx:if="{{answers[currentQuestion.id] === option.value}}" class="radio-inner"></view>
|
||||
</view>
|
||||
<text class="option-text">{{option.text}}</text>
|
||||
</view>
|
||||
|
||||
@@ -171,7 +171,7 @@ Page({
|
||||
finishTest() {
|
||||
const q = this.data.currentQuestion
|
||||
if (!q) return
|
||||
if (this.data.answers[q.id] == null && this.data.selectedAnswer == null) {
|
||||
if (this.data.answers[q.id] == null) {
|
||||
wx.showToast({ title: '请先选择一项', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,15 +19,16 @@
|
||||
<text class="question-text">{{currentQuestion.question}}</text>
|
||||
<view class="options-container">
|
||||
<view
|
||||
class="option-item {{selectedAnswer === option.value ? 'selected' : ''}}"
|
||||
class="option-item {{answers[currentQuestion.id] === option.value ? 'selected' : ''}}"
|
||||
wx:for="{{currentQuestion.options}}"
|
||||
wx:for-item="option"
|
||||
wx:key="value"
|
||||
wx:for-index="optIdx"
|
||||
wx:key="optIdx"
|
||||
bindtap="selectAnswer"
|
||||
data-value="{{option.value}}"
|
||||
>
|
||||
<view class="radio-button {{selectedAnswer === option.value ? 'checked' : ''}}">
|
||||
<view wx:if="{{selectedAnswer === option.value}}" class="radio-inner"></view>
|
||||
<view class="radio-button {{answers[currentQuestion.id] === option.value ? 'checked' : ''}}">
|
||||
<view wx:if="{{answers[currentQuestion.id] === option.value}}" class="radio-inner"></view>
|
||||
</view>
|
||||
<text class="option-text">{{option.text}}</text>
|
||||
</view>
|
||||
|
||||
@@ -19,15 +19,16 @@
|
||||
<text class="question-text">{{currentQuestion.question}}</text>
|
||||
<view class="options-container">
|
||||
<view
|
||||
class="option-item {{selectedAnswer === option.value ? 'selected' : ''}}"
|
||||
class="option-item {{answers[currentQuestion.id] === option.value ? 'selected' : ''}}"
|
||||
wx:for="{{currentQuestion.options}}"
|
||||
wx:for-item="option"
|
||||
wx:key="value"
|
||||
wx:for-index="optIdx"
|
||||
wx:key="optIdx"
|
||||
bindtap="selectAnswer"
|
||||
data-value="{{option.value}}"
|
||||
>
|
||||
<view class="radio-button {{selectedAnswer === option.value ? 'checked' : ''}}">
|
||||
<view wx:if="{{selectedAnswer === option.value}}" class="radio-inner"></view>
|
||||
<view class="radio-button {{answers[currentQuestion.id] === option.value ? 'checked' : ''}}">
|
||||
<view wx:if="{{answers[currentQuestion.id] === option.value}}" class="radio-inner"></view>
|
||||
</view>
|
||||
<text class="option-text">{{option.text}}</text>
|
||||
</view>
|
||||
|
||||
@@ -45,7 +45,7 @@ Page({
|
||||
const gender = (userInfo.gender !== undefined && userInfo.gender !== null) ? Number(userInfo.gender) : 0
|
||||
const genderText = this._genderText(gender)
|
||||
const genderIndex = Math.min(Math.max(0, gender), 2)
|
||||
const phone = userInfo.phone || ''
|
||||
const phone = (userInfo.phone || userInfo.phoneNumber || '').trim()
|
||||
|
||||
const { avatarLetter, avatarBgColor } = this._avatarFromNickname(nickname || '我')
|
||||
|
||||
@@ -123,7 +123,8 @@ Page({
|
||||
return
|
||||
}
|
||||
bindPhoneByCode(code).then((user) => {
|
||||
this.setData({ phone: user.phone || '' })
|
||||
const phone = ((user && (user.phone || user.phoneNumber)) || '').trim()
|
||||
this.setData({ phone })
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
@@ -153,7 +154,28 @@ Page({
|
||||
this.setData({ gender, genderIndex: idx, genderText })
|
||||
},
|
||||
|
||||
/** 保存前校验:头像、昵称、手机号均必填(与页面提示及后端门禁一致) */
|
||||
_validateRequiredForSave() {
|
||||
const avatar = (this.data.avatar || '').trim()
|
||||
const nickname = (this.data.nickname || '').trim()
|
||||
const phone = (this.data.phone || this.data.userInfo?.phone || this.data.userInfo?.phoneNumber || '').trim()
|
||||
const missing = []
|
||||
if (!avatar) missing.push('头像')
|
||||
if (!nickname) missing.push('昵称')
|
||||
if (!phone) missing.push('手机号')
|
||||
if (missing.length === 0) return ''
|
||||
return missing.length === 1
|
||||
? (missing[0] === '头像' ? '请先上传头像' : missing[0] === '昵称' ? '请填写昵称' : '请先授权绑定手机号')
|
||||
: `请完善:${missing.join('、')}`
|
||||
},
|
||||
|
||||
onSave() {
|
||||
const tip = this._validateRequiredForSave()
|
||||
if (tip) {
|
||||
wx.showToast({ title: tip, icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const { nickname, birthday, gender, userInfo } = this.data
|
||||
const profile = {}
|
||||
const origNickname = (userInfo?.nickname || userInfo?.nickName || '').trim()
|
||||
|
||||
Reference in New Issue
Block a user