chore:
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<view data-component-name="diy-recommend-code">
|
||||
|
||||
<!-- ============ 未登录:占位引导卡片(保持原有风格与逻辑一致) ============ -->
|
||||
<view class="invite-login-tip" v-if="!storeToken" @tap="goLogin"
|
||||
:style="loginWrapStyle">
|
||||
@@ -12,10 +11,8 @@
|
||||
{{ value.loginBtnText || '去登录' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- ============ 已登录:推荐码卡片(后端驱动,3 套预设 + consent 遮罩) ============ -->
|
||||
<view v-else>
|
||||
|
||||
<!-- ============ Consent 同意遮罩(requireConsent 开启 + 后端返回 consent_required=true 才显示) ============ -->
|
||||
<view v-if="showConsent" class="consent-overlay" :style="cardBaseStyle">
|
||||
<view class="consent-header">
|
||||
@@ -289,17 +286,16 @@ export default {
|
||||
shareLink: '',
|
||||
qrcodeUrl: '',
|
||||
/* 状态机 */
|
||||
showConsent: false, // 是否弹同意遮罩
|
||||
loadingCode: false, // 接口 loading 中
|
||||
codeLoaded: false, // 是否至少成功调过一次 getMyCode(防止登录后重复接口)
|
||||
/* 内部缓存(防止 watch / 登录成功重复刷接口时丢失) */
|
||||
showConsent: false,
|
||||
loadingCode: false,
|
||||
codeLoaded: false,
|
||||
|
||||
__lastConsentRequired: false,
|
||||
/* 渲染调试用:组件实例唯一ID,多个组件同屏时能区分日志 */
|
||||
|
||||
__cid: 'rc_' + Date.now() + '_' + Math.floor(Math.random() * 10000)
|
||||
};
|
||||
},
|
||||
/* ✅ 关键修复:props.value 为空对象 {} 时,Vue 的 props default 不会生效(只有 value === undefined 才用 default)
|
||||
这里做一次深 merge:把 props.value 里非空字段覆盖到默认 defaultValue 上,保证商家后台没配置的字段也能拿到默认值,否则所有 style 都是 undefined 导致模板样式全空,组件透明不可见 */
|
||||
|
||||
computed: {
|
||||
nc() {
|
||||
const raw = (this.value && typeof this.value === 'object') ? this.value : {};
|
||||
@@ -385,7 +381,7 @@ export default {
|
||||
bookGoldStyle() {
|
||||
const v = this.nc;
|
||||
return this.cardBaseStyle + [
|
||||
`background:#FFFFFF;`, // 原来渐变改成纯白
|
||||
`background:#FFFFFF;`,
|
||||
'box-shadow:0 12rpx 36rpx rgba(166,139,106,0.15);',
|
||||
'border-radius:24rpx;'
|
||||
].join('');
|
||||
@@ -401,7 +397,7 @@ export default {
|
||||
bookGoldCopyBtnStyle() {
|
||||
const v = this.nc;
|
||||
return [
|
||||
`background:#B8A08A;`, // 灰褐金按钮
|
||||
`background:#B8A08A;`,
|
||||
`color:#ffffff;`,
|
||||
`border-radius:40rpx;`,
|
||||
`font-size:24rpx;padding:10rpx 24rpx;`
|
||||
@@ -420,7 +416,6 @@ export default {
|
||||
`border:2rpx dashed ${v.codeColor || '#6B4423'};`,
|
||||
`border-radius:${this.px2rpx(Math.max(4, (Number(v.borderRadius) || 8) - 4))}rpx;`,
|
||||
'margin-top:28rpx;',
|
||||
// 新增布局行内样式,强制横向
|
||||
'display:flex;flex-direction:row;align-items:center;flex-wrap:nowrap;'
|
||||
].join('');
|
||||
},
|
||||
@@ -495,8 +490,6 @@ export default {
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
/* 登录态切换:guest → login → 自动调 getMyCode;logout → 清空状态
|
||||
全部 try-catch 包裹:任何 watcher 错误不会冒泡到父级,避免整个 diy-group 崩掉 */
|
||||
'storeToken'(nv) {
|
||||
try {
|
||||
if (nv) {
|
||||
@@ -522,12 +515,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
/* 页面/组件 created 生命周期:首次登录好的直接拉码 */
|
||||
/**
|
||||
* 关键修复:捕获子组件/本组件任何渲染错误,避免因为 ns-login / $refs / Vuex commit 等小问题
|
||||
* 导致整个 diy-group 渲染中断、页面底部导航点了也不切换(BUG1 的连锁问题)
|
||||
* Vue 的 errorCaptured 返回 false 时阻止错误继续向上冒泡
|
||||
*/
|
||||
errorCaptured(err, vm, info) {
|
||||
try { console.error('[RecommendDiy][' + this.__cid + '][errorCaptured] 组件内部错误(已拦截):', err && err.message ? err.message : err, 'info=', info); } catch (e) {}
|
||||
return false;
|
||||
@@ -589,17 +576,7 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/* ======================== 工具:万能响应解包(兼容后端各种嵌套结构) ======================== */
|
||||
|
||||
/**
|
||||
* 万能解包:后端返回结构可能是:
|
||||
* 标准 {code:0, msg:'ok', data:{code:'...', share_link:'...'}}
|
||||
* 嵌套 {data:{code:0, data:{...}}}
|
||||
* 双data {code:0, data:{data:{...}}}
|
||||
* TP风格 {status:200, info:'ok', data:{...}}
|
||||
* 裸返回 {code:'...', share_link:'...'} (没包 code/msg 外层)
|
||||
* 统一返回 { ok: bool, businessCode: number, msg: string, data: object, raw: any }
|
||||
*/
|
||||
|
||||
mainBtnBgStyle(isCopyMini) {
|
||||
const v = this.nc;
|
||||
const sp = this.stylePreset;
|
||||
@@ -651,14 +628,13 @@ export default {
|
||||
var codeVal = Number(obj[codeKey]) || 0;
|
||||
out.businessCode = codeVal;
|
||||
if (messageKey) out.msg = String(obj[messageKey]);
|
||||
// 业务码为 0 / 200 / '0' / '200' → 成功
|
||||
if (codeVal === 0 || codeVal === 200) {
|
||||
out.ok = true;
|
||||
// data 优先级:obj.data > obj.result > 整个 obj(防止把 {code,msg,data} 里的 data 当外层当 data 用)
|
||||
var d = null;
|
||||
if (obj.data && typeof obj.data === 'object') d = obj.data;
|
||||
else if (obj.result && typeof obj.result === 'object') d = obj.result;
|
||||
else d = obj; // 兜底:裸对象,code/share_link 在最外层
|
||||
else d = obj;
|
||||
out.data = d && typeof d === 'object' ? d : {};
|
||||
// 特殊处理:如果 data 里又有 data(后端双 data 包裹),再解一层
|
||||
if (out.data.data && typeof out.data.data === 'object' && !out.data.code && !out.data.share_link) {
|
||||
@@ -668,7 +644,6 @@ export default {
|
||||
return out;
|
||||
}
|
||||
} else if (typeof obj.code === 'string' || typeof obj.share_link === 'string') {
|
||||
// 裸对象:外层没有 code/status 业务码,但内层直接有 code/share_link → 当成成功处理
|
||||
out.ok = true;
|
||||
out.businessCode = 0;
|
||||
out.msg = 'ok';
|
||||
@@ -677,7 +652,7 @@ export default {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
// 没解出来:打印完整 res 给用户看
|
||||
|
||||
try { console.warn('[RecommendDiy][' + cid + '][解包] ⚠️ 未能识别后端响应结构,raw=', JSON.stringify(res).slice(0, 500)); } catch(e){}
|
||||
} catch (e) {
|
||||
try { console.error('[RecommendDiy][' + cid + '][解包] 异常:', e && e.message ? e.message : e); } catch(_){}
|
||||
@@ -735,7 +710,7 @@ export default {
|
||||
// 本次尝试业务失败(可能是 method 不对,或者 token 不对,或者 code!=0)
|
||||
lastMsg = unpacked.msg ? String(unpacked.msg) : ('推荐码获取失败(业务码=' + unpacked.businessCode + ')');
|
||||
try { console.warn('[RecommendDiy][' + cid + '][loadCode][' + meta.label + '] 业务失败:businessCode=' + unpacked.businessCode + ',msg=' + unpacked.msg + ',准备尝试下一个 method'); } catch(e){}
|
||||
// 第一个 method 失败 → 尝试下一个(GET→POST);最后一个失败就停
|
||||
|
||||
if (attemptIdx < attempts.length) {
|
||||
doOneAttempt();
|
||||
} else {
|
||||
@@ -796,15 +771,12 @@ export default {
|
||||
}
|
||||
doOneAttempt();
|
||||
},
|
||||
|
||||
/** 用户点击同意按钮 → consent=1 再调一次 getMyCode 拿真码 */
|
||||
confirmConsent() {
|
||||
this.loadCode(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* 接口 2:POST /recommend/api/recommend/regenerateCode
|
||||
* 换新码:旧码立即 status=0 失效,后端返回新 code + share_link + old_code + regenerated_at
|
||||
*/
|
||||
regenerate() {
|
||||
const vm = this;
|
||||
@@ -858,7 +830,6 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** 【接口 5:占位】调 getMyQrcode(可选兜底,失败不影响 showQR,本组件会 fallback 到 qrserver) */
|
||||
loadQrcodeIfNeeded() {
|
||||
const vm = this;
|
||||
@@ -946,21 +917,11 @@ onShareClick() {
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 从后端返回的 share_link 中提取小程序相对 path(给 onShareAppMessage 用)
|
||||
* - 相对路径:直接返回
|
||||
* - 绝对 URL / H5 URL:提取 recommend_code 参数,拼成小程序标准落地页(/pages_tool/form/formdata?recommend_code=xxx)
|
||||
*/
|
||||
extractMiniProgramPath() {
|
||||
// 直接生成落地页路径,不需要解析后端废弃shareLink
|
||||
if (!this.code) return '/pages_tool/form/formdata';
|
||||
return `/pages_tool/form/formdata?recommend_code=${encodeURIComponent(this.code)}`;
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
_persistRecommendInfo() {
|
||||
try {
|
||||
const sInfo = (this.$store && this.$store.state && this.$store.state.memberInfo) || {};
|
||||
@@ -1231,12 +1192,11 @@ onShareClick() {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
.rc-code-minimal {
|
||||
/* 强制覆盖父级.rc-code-box纵向布局 */
|
||||
display: flex !important;
|
||||
flex-direction: row !important;
|
||||
align-items: center !important;
|
||||
justify-content: space-between !important;
|
||||
flex-wrap: nowrap !important; /* 禁止换行 */
|
||||
flex-wrap: nowrap !important;
|
||||
background: transparent;
|
||||
border-style: dashed;
|
||||
padding: 22rpx 26rpx;
|
||||
@@ -1246,8 +1206,8 @@ onShareClick() {
|
||||
text-align: left;
|
||||
letter-spacing: 4rpx;
|
||||
line-height: 1;
|
||||
flex: 1; /* 文字自适应填充剩余宽度 */
|
||||
white-space: nowrap; /* 文字不换行挤压按钮 */
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@@ -1257,7 +1217,7 @@ onShareClick() {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0 !important; /* 按钮禁止被压缩 */
|
||||
flex-shrink: 0 !important;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
@@ -1296,7 +1256,7 @@ onShareClick() {
|
||||
width: 100%;
|
||||
.rc-header-bookgold {
|
||||
.rc-title {
|
||||
color: #333333; // 白色背景改用深色标题
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
.rc-code-bookgold {
|
||||
|
||||
Reference in New Issue
Block a user