fix feat 一大堆关羽扫雷的
This commit is contained in:
parent
237d785a4f
commit
5691d0601d
@ -442,6 +442,27 @@
|
|||||||
margin-bottom: $spacing-xs;
|
margin-bottom: $spacing-xs;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: $spacing-sm;
|
gap: $spacing-sm;
|
||||||
|
|
||||||
|
// 最新日志高亮动画(第一个元素是最新的)
|
||||||
|
&:first-child {
|
||||||
|
animation: logHighlight 1s ease-out;
|
||||||
|
background: rgba($brand-primary, 0.1);
|
||||||
|
padding: 4rpx 8rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
margin-left: -8rpx;
|
||||||
|
margin-right: -8rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes logHighlight {
|
||||||
|
0% {
|
||||||
|
background: rgba($brand-primary, 0.3);
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background: rgba($brand-primary, 0.1);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-time {
|
.log-time {
|
||||||
@ -969,6 +990,16 @@
|
|||||||
border: 1px solid $border-dark;
|
border: 1px solid $border-dark;
|
||||||
// 确保格子始终保持正方形
|
// 确保格子始终保持正方形
|
||||||
aspect-ratio: 1 / 1;
|
aspect-ratio: 1 / 1;
|
||||||
|
// 阻止长按缩放
|
||||||
|
touch-action: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
// 额外的防护
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
outline: none;
|
||||||
|
// 禁用任何手势
|
||||||
|
overscroll-behavior: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-cell {
|
.grid-cell {
|
||||||
@ -983,6 +1014,16 @@
|
|||||||
aspect-ratio: 1 / 1;
|
aspect-ratio: 1 / 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
// 阻止长按弹出菜单和缩放
|
||||||
|
touch-action: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
// 额外的防护
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
outline: none;
|
||||||
|
// 禁用任何手势
|
||||||
|
overscroll-behavior: none;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
@ -1000,6 +1041,12 @@
|
|||||||
border: 2rpx dashed rgba($accent-cyan, 0.5);
|
border: 2rpx dashed rgba($accent-cyan, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 观察者旗帜标记样式
|
||||||
|
&.has-flag {
|
||||||
|
border: 2rpx solid rgba($color-warning, 0.6);
|
||||||
|
background: rgba($color-warning, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
// --- 新增特效样式 ---
|
// --- 新增特效样式 ---
|
||||||
&.explosion {
|
&.explosion {
|
||||||
animation: explode 0.5s ease-out;
|
animation: explode 0.5s ease-out;
|
||||||
@ -1184,6 +1231,33 @@
|
|||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 观察者旗帜图标
|
||||||
|
.spectator-flag {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
animation: flagWave 2s ease-in-out infinite;
|
||||||
|
|
||||||
|
.flag-icon {
|
||||||
|
font-size: 36rpx;
|
||||||
|
filter: drop-shadow(0 2rpx 4rpx rgba(0, 0, 0, 0.3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flagWave {
|
||||||
|
0%, 100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(5deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(-5deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.magnifier-mark {
|
.magnifier-mark {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -1281,6 +1355,15 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
// 最新日志高亮动画(第一个元素是最新的)
|
||||||
|
&:first-child {
|
||||||
|
animation: gameLogHighlight 0.8s ease-out;
|
||||||
|
background: rgba($brand-primary, 0.15);
|
||||||
|
padding: 2rpx 6rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
&.log-system {
|
&.log-system {
|
||||||
color: $accent-cyan;
|
color: $accent-cyan;
|
||||||
}
|
}
|
||||||
@ -1290,6 +1373,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes gameLogHighlight {
|
||||||
|
0% {
|
||||||
|
background: rgba($brand-primary, 0.4);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background: rgba($brand-primary, 0.15);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// =====================================
|
// =====================================
|
||||||
// 弹窗 (全屏遮罩)
|
// 弹窗 (全屏遮罩)
|
||||||
|
|||||||
@ -157,18 +157,22 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="grid-board" :style="{ gridTemplateColumns: 'repeat(' + gameState.gridSize + ', 1fr)' }">
|
<view class="grid-board" :style="{ gridTemplateColumns: 'repeat(' + gameState.gridSize + ', 1fr)' }">
|
||||||
<view
|
<view
|
||||||
v-for="(cell, i) in gameState.grid"
|
v-for="(cell, i) in gameState.grid"
|
||||||
:key="i"
|
:key="i"
|
||||||
class="grid-cell"
|
class="grid-cell"
|
||||||
:class="[
|
:class="[
|
||||||
cell.revealed ? (cell.type === 'bomb' ? 'type-bomb explosion' : (cell.type === 'item' ? 'type-item item-' + (cell.itemId || 'generic') : 'type-empty')) : 'bg-slate-800',
|
cell.revealed ? (cell.type === 'bomb' ? 'type-bomb explosion' : (cell.type === 'item' ? 'type-item item-' + (cell.itemId || 'generic') : 'type-empty')) : 'bg-slate-800',
|
||||||
{
|
{
|
||||||
'revealed': cell.revealed,
|
'revealed': cell.revealed,
|
||||||
'has-magnifier': myPlayer && myPlayer.revealedCells && myPlayer.revealedCells[i]
|
'has-magnifier': myPlayer && myPlayer.revealedCells && myPlayer.revealedCells[i],
|
||||||
|
'has-flag': isSpectator && spectatorFlags[i] // 观察者旗帜标记
|
||||||
}
|
}
|
||||||
]"
|
]"
|
||||||
@tap="handleCellClick(i)"
|
@tap="handleCellClick(i)"
|
||||||
|
@touchstart="handleCellTouchStart(i, $event)"
|
||||||
|
@touchend="handleCellTouchEnd($event)"
|
||||||
|
@touchmove="handleCellTouchMove($event)"
|
||||||
>
|
>
|
||||||
<view v-if="cell.revealed">
|
<view v-if="cell.revealed">
|
||||||
<text v-if="cell.type === 'bomb'" class="cell-icon">💣</text>
|
<text v-if="cell.type === 'bomb'" class="cell-icon">💣</text>
|
||||||
@ -188,6 +192,11 @@
|
|||||||
<text class="magnifier-badge">🔍</text>
|
<text class="magnifier-badge">🔍</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 观察者旗帜标记 -->
|
||||||
|
<view v-else-if="isSpectator && spectatorFlags[i]" class="spectator-flag">
|
||||||
|
<text class="flag-icon">🚩</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 格子上的飘字 -->
|
<!-- 格子上的飘字 -->
|
||||||
<view v-for="l in getCellLabels(i)" :key="l.id" class="float-label" :class="'text-' + l.type">
|
<view v-for="l in getCellLabels(i)" :key="l.id" class="float-label" :class="'text-' + l.type">
|
||||||
{{ l.text }}
|
{{ l.text }}
|
||||||
@ -335,6 +344,8 @@ export default {
|
|||||||
showResultModal: false,
|
showResultModal: false,
|
||||||
onlineCount: 0,
|
onlineCount: 0,
|
||||||
onlineCountInterval: null,
|
onlineCountInterval: null,
|
||||||
|
spectatorFlags: {}, // 观察者模式的旗帜标记 { cellIndex: true }
|
||||||
|
longPressTimer: null, // 长按定时器
|
||||||
// Timers
|
// Timers
|
||||||
matchInterval: null,
|
matchInterval: null,
|
||||||
turnInterval: null,
|
turnInterval: null,
|
||||||
@ -407,11 +418,6 @@ export default {
|
|||||||
this.showResultModal = true;
|
this.showResultModal = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
logs() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.logsScrollTop = 99999 + Math.random();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'gameState.currentTurnIndex'() {
|
'gameState.currentTurnIndex'() {
|
||||||
this.resetTurnTimer();
|
this.resetTurnTimer();
|
||||||
},
|
},
|
||||||
@ -422,7 +428,11 @@ export default {
|
|||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
this.fetchGameConfig();
|
this.fetchGameConfig();
|
||||||
const { game_token, nakama_server, nakama_key, match_id, is_spectator, uid } = options;
|
const { game_token, nakama_server, nakama_key, match_id, is_spectator, uid } = options;
|
||||||
if (is_spectator) this.isSpectator = true;
|
if (is_spectator) {
|
||||||
|
this.isSpectator = true;
|
||||||
|
// 观察者模式:禁用页面缩放
|
||||||
|
this.disablePageZoom();
|
||||||
|
}
|
||||||
if (match_id) this.matchId = match_id;
|
if (match_id) this.matchId = match_id;
|
||||||
if (uid) this.stableUserId = uid;
|
if (uid) this.stableUserId = uid;
|
||||||
|
|
||||||
@ -436,6 +446,33 @@ export default {
|
|||||||
this.cleanup();
|
this.cleanup();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
disablePageZoom() {
|
||||||
|
// 观察者模式:禁用页面缩放和长按菜单
|
||||||
|
// 注意:这些操作在 H5 环境下有效
|
||||||
|
// #ifdef H5
|
||||||
|
document.addEventListener('contextmenu', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 禁用双指缩放
|
||||||
|
document.addEventListener('gesturestart', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('gesturechange', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('gestureend', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 微信小程序环境下,通过页面配置禁用缩放
|
||||||
|
// 这些需要在 pages.json 中配置
|
||||||
|
},
|
||||||
async fetchGameConfig() {
|
async fetchGameConfig() {
|
||||||
try {
|
try {
|
||||||
const res = await new Promise((resolve, reject) => {
|
const res = await new Promise((resolve, reject) => {
|
||||||
@ -464,10 +501,19 @@ export default {
|
|||||||
},
|
},
|
||||||
addLog(type, content) {
|
addLog(type, content) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const timeStr = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0');
|
const timeStr = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0') + ':' + now.getSeconds().toString().padStart(2, '0');
|
||||||
const id = Date.now() + Math.random().toString();
|
const id = Date.now() + Math.random().toString();
|
||||||
this.logs.push({ id, type, content, time: timeStr });
|
|
||||||
if (this.logs.length > 50) this.logs.shift();
|
// 插入到数组头部,最新的在最上面
|
||||||
|
this.logs.unshift({ id, type, content, time: timeStr });
|
||||||
|
|
||||||
|
// 增加日志存储限制到 100 条,让用户能看到更多历史
|
||||||
|
if (this.logs.length > 100) this.logs.pop();
|
||||||
|
|
||||||
|
// 确保滚动到顶部显示最新日志
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.logsScrollTop = 0;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
spawnLabel(x, y, text, type, cellIndex, targetUserId) {
|
spawnLabel(x, y, text, type, cellIndex, targetUserId) {
|
||||||
const id = Date.now() + Math.random().toString();
|
const id = Date.now() + Math.random().toString();
|
||||||
@ -839,7 +885,10 @@ export default {
|
|||||||
},
|
},
|
||||||
handleCellClick(idx) {
|
handleCellClick(idx) {
|
||||||
// 前置条件检查
|
// 前置条件检查
|
||||||
if (this.isSpectator) return;
|
if (this.isSpectator) {
|
||||||
|
// 观察者模式:不处理普通点击,只处理长按
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!this.gameState?.gameStarted) {
|
if (!this.gameState?.gameStarted) {
|
||||||
uni.showToast({ title: '游戏尚未开始', icon: 'none' });
|
uni.showToast({ title: '游戏尚未开始', icon: 'none' });
|
||||||
return;
|
return;
|
||||||
@ -850,10 +899,73 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.gameState.grid[idx].revealed) return;
|
if (this.gameState.grid[idx].revealed) return;
|
||||||
|
|
||||||
// 发送移动指令
|
// 发送移动指令
|
||||||
nakamaManager.sendMatchState(this.matchId, 3, JSON.stringify({ index: idx }));
|
nakamaManager.sendMatchState(this.matchId, 3, JSON.stringify({ index: idx }));
|
||||||
},
|
},
|
||||||
|
// 观察者模式:长按插旗
|
||||||
|
handleCellLongPress(idx) {
|
||||||
|
// 只有观察者才能长按插旗
|
||||||
|
if (!this.isSpectator) return;
|
||||||
|
if (!this.gameState?.grid) return;
|
||||||
|
if (this.gameState.grid[idx].revealed) return;
|
||||||
|
|
||||||
|
// 切换旗帜状态
|
||||||
|
if (this.spectatorFlags[idx]) {
|
||||||
|
this.$delete(this.spectatorFlags, idx);
|
||||||
|
this.addLog('system', `🚩 移除了位置 ${idx} 的旗帜`);
|
||||||
|
} else {
|
||||||
|
this.$set(this.spectatorFlags, idx, true);
|
||||||
|
this.addLog('system', `🚩 在位置 ${idx} 插上了旗帜`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 触摸开始 - 用于检测长按
|
||||||
|
handleCellTouchStart(idx, event) {
|
||||||
|
// 只有观察者才处理长按插旗
|
||||||
|
if (!this.isSpectator) return;
|
||||||
|
|
||||||
|
// 阻止默认行为,防止长按弹出菜单(仅观察者)
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置长按定时器(800ms)
|
||||||
|
this.longPressTimer = setTimeout(() => {
|
||||||
|
// 添加震动反馈
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
|
uni.vibrateShort();
|
||||||
|
// #endif
|
||||||
|
this.handleCellLongPress(idx);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}, 800);
|
||||||
|
},
|
||||||
|
// 触摸结束 - 取消长按
|
||||||
|
handleCellTouchEnd(event) {
|
||||||
|
// 只有观察者需要处理
|
||||||
|
if (!this.isSpectator) return;
|
||||||
|
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 触摸移动 - 取消长按
|
||||||
|
handleCellTouchMove(event) {
|
||||||
|
// 只有观察者需要处理
|
||||||
|
if (!this.isSpectator) return;
|
||||||
|
|
||||||
|
// 如果手指移动了,取消长按
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
refreshAndPlayAgain() {
|
refreshAndPlayAgain() {
|
||||||
uni.removeStorageSync('minesweeper_last_match_id');
|
uni.removeStorageSync('minesweeper_last_match_id');
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
@ -873,6 +985,13 @@ export default {
|
|||||||
clearInterval(this.matchInterval);
|
clearInterval(this.matchInterval);
|
||||||
clearInterval(this.turnInterval);
|
clearInterval(this.turnInterval);
|
||||||
clearInterval(this.onlineCountInterval);
|
clearInterval(this.onlineCountInterval);
|
||||||
|
|
||||||
|
// 清理长按定时器
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
nakamaManager.disconnect();
|
nakamaManager.disconnect();
|
||||||
},
|
},
|
||||||
async fetchOnlineCount() {
|
async fetchOnlineCount() {
|
||||||
|
|||||||
@ -79,7 +79,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<text class="coupon-rules">{{ item.rules || '全场通用' }}</text>
|
<text class="coupon-rules">{{ formatRules(item.rules) }}</text>
|
||||||
|
|
||||||
<!-- 使用进度条 -->
|
<!-- 使用进度条 -->
|
||||||
<view class="coupon-progress" v-if="item.amount && item.remaining !== undefined && item.remaining < item.amount">
|
<view class="coupon-progress" v-if="item.amount && item.remaining !== undefined && item.remaining < item.amount">
|
||||||
@ -164,6 +164,18 @@ function formatValue(val) {
|
|||||||
return (Number(val) / 100).toFixed(0)
|
return (Number(val) / 100).toFixed(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 格式化优惠券规则描述中的分转为元
|
||||||
|
function formatRules(rules) {
|
||||||
|
if (!rules) return '全场通用'
|
||||||
|
// 将"XXX分"替换为"¥X.XX元"格式
|
||||||
|
return rules.replace(/(\d+)分/g, (match, p1) => {
|
||||||
|
const yuan = (Number(p1) / 100).toFixed(2)
|
||||||
|
// 去掉末尾的.00
|
||||||
|
const formatted = yuan.endsWith('.00') ? yuan.slice(0, -3) : yuan
|
||||||
|
return `¥${formatted}元`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 格式化有效期
|
// 格式化有效期
|
||||||
function formatExpiry(item) {
|
function formatExpiry(item) {
|
||||||
// 后端返回的字段是 valid_end
|
// 后端返回的字段是 valid_end
|
||||||
|
|||||||
@ -184,6 +184,12 @@
|
|||||||
"navigationStyle": "default",
|
"navigationStyle": "default",
|
||||||
"navigationBarTitleText": "扫雷对战",
|
"navigationBarTitleText": "扫雷对战",
|
||||||
"disableScroll": true,
|
"disableScroll": true,
|
||||||
|
"mp-weixin": {
|
||||||
|
"disableSwipeBack": true
|
||||||
|
},
|
||||||
|
"h5": {
|
||||||
|
"titleNView": false
|
||||||
|
},
|
||||||
"app-plus": {
|
"app-plus": {
|
||||||
"bounce": "none"
|
"bounce": "none"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -268,7 +268,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<text class="coupon-rules">{{ item.rules || '全场通用' }}</text>
|
<text class="coupon-rules">{{ formatCouponRules(item.rules) }}</text>
|
||||||
|
|
||||||
<!-- 使用进度条 (仅当有使用记录时显示) -->
|
<!-- 使用进度条 (仅当有使用记录时显示) -->
|
||||||
<view class="coupon-progress-wrap" v-if="item.amount && item.remaining !== undefined && item.remaining < item.amount">
|
<view class="coupon-progress-wrap" v-if="item.amount && item.remaining !== undefined && item.remaining < item.amount">
|
||||||
@ -1135,6 +1135,16 @@ export default {
|
|||||||
formatCouponValue(val) {
|
formatCouponValue(val) {
|
||||||
return (Number(val) / 100).toFixed(0)
|
return (Number(val) / 100).toFixed(0)
|
||||||
},
|
},
|
||||||
|
formatCouponRules(rules) {
|
||||||
|
if (!rules) return '全场通用'
|
||||||
|
// 将"XXX分"替换为"¥X.XX元"格式
|
||||||
|
return rules.replace(/(\d+)分/g, (match, p1) => {
|
||||||
|
const yuan = (Number(p1) / 100).toFixed(2)
|
||||||
|
// 去掉末尾的.00
|
||||||
|
const formatted = yuan.endsWith('.00') ? yuan.slice(0, -3) : yuan
|
||||||
|
return `¥${formatted}元`
|
||||||
|
})
|
||||||
|
},
|
||||||
formatCouponExpiry(item) {
|
formatCouponExpiry(item) {
|
||||||
if (!item.end_time) return '长期有效'
|
if (!item.end_time) return '长期有效'
|
||||||
return `有效期至 ${this.formatDate(item.end_time)}`
|
return `有效期至 ${this.formatDate(item.end_time)}`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user