|
|
@@ -175,6 +175,7 @@ import TaskCard from '@/pages/ai/components/AITaskCard.vue'
|
|
|
import QuotaProgressBar from '@/pages/ai/components/QuotaProgressBar.vue'
|
|
|
import UpgradeGuideModal from '@/pages/ai/components/UpgradeGuideModal.vue'
|
|
|
import config from '@/config.js'
|
|
|
+import { parseDate } from '../../utils/format.js'
|
|
|
import fontScaleMixin from '@/mixins/font-scale.js'
|
|
|
|
|
|
export default {
|
|
|
@@ -257,13 +258,14 @@ export default {
|
|
|
if (!this.memberGate) return ''
|
|
|
if (this.gateStatus === 'MEMBER_EXPIRED') {
|
|
|
var end = this.memberGate.memberExpireTime || this.memberGate.endDate
|
|
|
- var day = end ? String(end).slice(0, 10) : ''
|
|
|
+ var day = this.formatGateDate(end)
|
|
|
return day ? ('会员已于 ' + day + ' 到期') : '会员已到期'
|
|
|
}
|
|
|
if (this.gateStatus === 'ALLOW' && this.memberGate.isActive) {
|
|
|
var remain = this.memberGate.daysRemaining
|
|
|
if (typeof remain === 'number' && remain >= 0 && remain <= this.nearExpiryDays) {
|
|
|
- return '会员即将到期(剩余 ' + remain + ' 天)'
|
|
|
+ // 后端可能返回小数(按毫秒折算),展示向上取整,避免「剩余 0 天」却仍可用
|
|
|
+ return '会员即将到期(剩余 ' + Math.ceil(remain) + ' 天)'
|
|
|
}
|
|
|
}
|
|
|
return ''
|
|
|
@@ -319,6 +321,8 @@ export default {
|
|
|
},
|
|
|
|
|
|
// /api/ai/gate 不可用时的旧会员接口降级映射
|
|
|
+ // 注意:旧接口不区分「从未付费 / 曾付费已过期」,也不能给出剩余天数,
|
|
|
+ // 因此 daysRemaining / isActive 置空(状态条据此跳过临期提醒),避免展示假数据。
|
|
|
buildLegacyGate(membership) {
|
|
|
var level = membership.memberLevel || 'FREE'
|
|
|
var allowed = level !== 'FREE'
|
|
|
@@ -328,15 +332,22 @@ export default {
|
|
|
canUse: allowed,
|
|
|
canViewHistory: false,
|
|
|
memberLevel: level,
|
|
|
- isActive: allowed,
|
|
|
+ isActive: null,
|
|
|
memberExpireTime: membership.memberExpireTime || null,
|
|
|
endDate: membership.endDate || membership.memberExpireTime || null,
|
|
|
- daysRemaining: 0
|
|
|
+ daysRemaining: null
|
|
|
}
|
|
|
},
|
|
|
|
|
|
applyMemberGate(gate, autoPrompt) {
|
|
|
- var status = gate.status || (gate.canUse === false ? 'UPGRADE_REQUIRED' : 'ALLOW')
|
|
|
+ // status 缺失(gate 接口返回空 data / 5001 无家庭兜底)时 fail-closed:
|
|
|
+ // 不默认放行,沿用上一次已知状态;首次遇到则按未开通处理(不主动弹窗,避免误伤)。
|
|
|
+ var status = gate.status
|
|
|
+ if (!status) {
|
|
|
+ if (gate.canUse === true) status = 'ALLOW'
|
|
|
+ else if (gate.canUse === false) status = 'UPGRADE_REQUIRED'
|
|
|
+ else status = this.gateStatus || 'UPGRADE_REQUIRED'
|
|
|
+ }
|
|
|
this.memberGate = gate
|
|
|
this.gateStatus = status
|
|
|
this.gateBlocked = status !== 'ALLOW'
|
|
|
@@ -394,6 +405,15 @@ export default {
|
|
|
uni.navigateTo({ url: '/pages/membership/upgrade' })
|
|
|
},
|
|
|
|
|
|
+ // 门禁日期展示:yyyy-MM-dd(iOS 安全解析走 parseDate,兼容时间戳/ISO/Java 格式)
|
|
|
+ formatGateDate(value) {
|
|
|
+ var d = parseDate(value)
|
|
|
+ if (!d) return ''
|
|
|
+ var m = d.getMonth() + 1
|
|
|
+ var day = d.getDate()
|
|
|
+ return d.getFullYear() + '-' + (m < 10 ? '0' + m : m) + '-' + (day < 10 ? '0' + day : day)
|
|
|
+ },
|
|
|
+
|
|
|
startVoiceRecord() {
|
|
|
if (this.isRecording) return
|
|
|
if (this.gateBlocked) {
|
|
|
@@ -568,27 +588,33 @@ export default {
|
|
|
} catch (e) {
|
|
|
var errCode = e && e.code
|
|
|
if (errCode === 46003 || errCode === 46004) {
|
|
|
- // 会员门禁:撤掉未落库的乐观消息,改为弹专用引导弹窗(不显示通用失败文案)
|
|
|
+ // 会员门禁:撤掉未落库的乐观消息,把输入还给用户,改为弹专用引导弹窗
|
|
|
const lastMsg = this.messages[this.messages.length - 1]
|
|
|
if (lastMsg && String(lastMsg.id).indexOf('temp_') === 0) {
|
|
|
this.messages.pop()
|
|
|
}
|
|
|
+ if (!this.inputText) this.inputText = text
|
|
|
if (errCode === 46004) {
|
|
|
this.gateStatus = 'MEMBER_EXPIRED'
|
|
|
- this.gateBlocked = true
|
|
|
- this.showGateModal('expired')
|
|
|
} else {
|
|
|
this.gateStatus = 'UPGRADE_REQUIRED'
|
|
|
- this.gateBlocked = true
|
|
|
- this.showGateModal('hard')
|
|
|
}
|
|
|
+ this.gateBlocked = true
|
|
|
+ // 保证状态条依赖的 memberGate 不为空(会话中途降级时也能显示续费入口)
|
|
|
+ // 用新对象覆盖,避免直接改写接口返回体(可能被 3 秒去重缓存共享)
|
|
|
+ this.memberGate = Object.assign({}, this.memberGate || {}, {
|
|
|
+ status: this.gateStatus,
|
|
|
+ canUse: false
|
|
|
+ })
|
|
|
+ this.showGateModal(errCode === 46004 ? 'expired' : 'hard')
|
|
|
return
|
|
|
}
|
|
|
- // 显示错误
|
|
|
+ // 显示错误(发送类走 _noToast,这里补回后端原话,避免只剩通用兜底)
|
|
|
const lastMsg = this.messages[this.messages.length - 1]
|
|
|
if (lastMsg) {
|
|
|
lastMsg.answer = '抱歉,我暂时无法回答,请稍后再试。'
|
|
|
}
|
|
|
+ uni.showToast({ title: (e && e.message) || '发送失败,请稍后再试', icon: 'none' })
|
|
|
} finally {
|
|
|
this.sending = false
|
|
|
this.$nextTick(() => {
|