fix(theme): 修复门票页导航栏主题脱节与个人中心双身份卡片流光动画,加固活动参与人画像与大神隐私

这个提交包含在:
xcbyy
2026-10-23 09:05:32 +08:00
父节点 001f81eaca
当前提交 f082ae8276
共有 14 个文件被更改,包括 147 次插入 和 40 次删除

查看文件

@@ -38,7 +38,8 @@ export function formatActivityData(raw) {
startTime: raw.startTime || '',
location: raw.location || '',
creatorId: raw.creatorId != null ? Number(raw.creatorId) : (raw.creator_id != null ? Number(raw.creator_id) : 0),
creatorNickname: raw.creatorNickname || '',
// 创建人已被删除时给出真实状态,避免列表显示空白局长
creatorNickname: raw.creatorNickname || '局长已注销',
creatorAvatar: raw.creatorAvatar || '',
status: raw.status || (joinedCount >= (raw.maxParticipants || 4) ? 'FULL' : 'RECRUITING'),
allowDynamicPrice: Boolean(raw.allowDynamicPrice),
@@ -236,7 +237,7 @@ export async function getCompanions(keyword) {
price: Number(c.hourlyRate) || 0,
rating: Number(c.rating) || 0,
orderCount: Number(c.orderCount) || 0,
isOnline: c.status === '接单中',
isOnline: c.isOnline !== undefined ? Boolean(c.isOnline) : c.status === '接单中',
voiceDuration: Number(c.voiceDuration) || 0,
voiceType: 'voice',
voiceTitle: c.voiceTitle || '',
@@ -267,7 +268,6 @@ export async function matchCompanions(options = {}) {
const list = Array.isArray(res) ? res : (res && Array.isArray(res.list) ? res.list : []);
return list.map((c) => ({
id: String(c.id),
userId: Number(c.userId) || 0,
nickname: c.nickname || '',
avatar: c.avatar || '',
gender: c.gender === '男' ? 'male' : (c.gender === '女' ? 'female' : ''),

查看文件

@@ -72,7 +72,10 @@
<text class="sec-title">组局阵地与发起人</text>
</view>
<view class="creator-box">
<image class="creator-avatar btn-active" :src="activity.creatorAvatar" mode="aspectFill" @click="openHostProfile" />
<image v-if="activity.creatorAvatar" class="creator-avatar btn-active" :src="activity.creatorAvatar" mode="aspectFill" @click="openHostProfile" />
<view v-else class="creator-avatar creator-avatar-empty btn-active" @click="openHostProfile">
<text class="creator-avatar-placeholder">?</text>
</view>
<view class="creator-info btn-active" @click="openHostProfile">
<view class="creator-name-row">
<text class="creator-name">{{ activity.creatorNickname }}</text>
@@ -1147,6 +1150,21 @@ const handleJoin = () => {
height: 80rpx;
border-radius: 40rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.creator-avatar-empty {
display: flex;
align-items: center;
justify-content: center;
background: rgba(148, 163, 184, 0.18);
border: 1px solid rgba(148, 163, 184, 0.3);
.creator-avatar-placeholder {
font-size: 30rpx;
color: #94A3B8;
font-weight: 700;
}
}
.creator-info {

查看文件

@@ -140,7 +140,10 @@
<!-- 底部房主与价格 -->
<view class="card-footer">
<view class="creator-info">
<image class="creator-avatar" :src="act.creatorAvatar" mode="aspectFill" />
<image v-if="act.creatorAvatar" class="creator-avatar" :src="act.creatorAvatar" mode="aspectFill" />
<view v-else class="creator-avatar creator-avatar-empty">
<text class="creator-avatar-placeholder">?</text>
</view>
<text class="creator-name">局长:{{ act.creatorNickname }}</text>
</view>
@@ -346,9 +349,9 @@ onUnmounted(() => {
});
const getCategoryTagClass = (game) => {
if (game === '美食陪吃') return 'tag-meal';
if (game === '同城陪唱') return 'tag-sing';
if (game === '下午茶陪喝' || game === '同城微醺') return 'tag-drink';
if (game === '美食陪吃' || game === '美食探店') return 'tag-meal';
if (game === '同城陪唱' || game === 'KTV嗨唱') return 'tag-sing';
if (game === '下午茶陪喝' || game === '下午茶歇' || game === '同城微醺') return 'tag-drink';
return '';
};
@@ -802,6 +805,20 @@ const createActivity = () => {
height: 48rpx;
border-radius: 24rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.creator-avatar-empty {
display: flex;
align-items: center;
justify-content: center;
background: rgba(148, 163, 184, 0.18);
border: 1px solid rgba(148, 163, 184, 0.3);
.creator-avatar-placeholder {
font-size: 22rpx;
color: #94A3B8;
font-weight: 700;
}
}
.creator-name {
font-size: 22rpx;

查看文件

@@ -251,7 +251,7 @@ import AppTabBar from '@/components/CustomTabBar.vue';
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
import { isExpertCertified } from '@/common/role.js';
import { claimOrder, getOrdersPool, getExpertStats, updateCompanionProfile, getUserProfile, getActivities, normalizeUserId } from '@/common/api.js';
import { claimOrder, getOrdersPool, getExpertStats, updateCompanionProfile, getUserProfile, getActivities, getMyExpertProfile, normalizeUserId } from '@/common/api.js';
import { getUserLocation } from '@/common/location.js';
import { startHeartbeat, stopHeartbeat } from '@/common/expert-heartbeat.js';
import { getNavBarInfo } from '@/common/nav.js';
@@ -363,6 +363,15 @@ const loadHallData = async () => {
}
}).catch(() => {}),
getMyExpertProfile().then((profile) => {
if (profile && profile.status) {
isOnline.value = profile.status === '接单中';
uni.setStorageSync('EXPERT_RECEIVING_STATUS', isOnline.value ? '1' : '0');
if (isOnline.value) startHeartbeat();
else stopHeartbeat();
}
}).catch(() => {}),
getOrdersPool(myCoords).then((pool) => {
if (Array.isArray(pool)) {
orders.value = pool.map(p => {
@@ -475,26 +484,37 @@ const filteredOrders = computed(() => {
});
const toggleOnlineStatus = async () => {
isOnline.value = !isOnline.value;
uni.setStorageSync('EXPERT_RECEIVING_STATUS', isOnline.value ? '1' : '0');
const eid = Number(expert.value.id) || normalizeUserId();
if (!eid) {
uni.showToast({ title: '请先登录后再操作', icon: 'none' });
return;
}
const next = !isOnline.value;
isOnline.value = next;
uni.setStorageSync('EXPERT_RECEIVING_STATUS', next ? '1' : '0');
try {
await updateCompanionProfile(eid, {
status: isOnline.value ? '接单中' : '休息中'
status: next ? '接单中' : '休息中'
});
} catch (_) {}
if (isOnline.value) {
} catch (err) {
// 服务端失败必须回滚本地状态,避免界面显示在线但实际不接单
isOnline.value = !next;
uni.setStorageSync('EXPERT_RECEIVING_STATUS', !next ? '1' : '0');
stopHeartbeat();
uni.showToast({
title: (err && err.message) || '接单状态切换失败,请稍后重试',
icon: 'none'
});
return;
}
if (next) {
startHeartbeat();
} else {
stopHeartbeat();
}
uni.showToast({
title: isOnline.value ? '已开启在线接单' : '已设置为打烊休息',
icon: isOnline.value ? 'success' : 'none',
title: next ? '已开启在线接单' : '已设置为打烊休息',
icon: next ? 'success' : 'none',
duration: 1500
});
};

查看文件

@@ -562,6 +562,13 @@ const loadExpertProfile = async () => {
voiceIntroUrl: profile.voiceIntroUrl || '',
voiceDuration: Number(profile.voiceDuration) || 0
};
// 以服务端接单状态为准,避免本地缓存显示在线但实际已休息
if (profile.status) {
isReceivingOrders.value = profile.status === '接单中';
uni.setStorageSync('EXPERT_RECEIVING_STATUS', isReceivingOrders.value ? '1' : '0');
if (isReceivingOrders.value) startHeartbeat();
else stopHeartbeat();
}
}
} catch (_) {}
};

查看文件

@@ -70,7 +70,7 @@
<view class="section-title-wrap">
<view class="section-title">
<view class="title-line"></view>
<text>精选在线大神</text>
<text>精选大神</text>
</view>
<view class="section-more btn-active" @click="startInstantMatch">
<view class="pulse-point"></view>