chore:待跟进和已完成页面正常
This commit is contained in:
@@ -63,9 +63,20 @@
|
||||
<text v-else class="load-end">— 没有更多了 —</text>
|
||||
</view>
|
||||
|
||||
<!-- 空态: 建卡申请 / 申请状态(2.11.15) -->
|
||||
<view v-if="!isLoading && list.length === 0" class="card-empty">
|
||||
<block v-if="apply && apply.status === 0">
|
||||
<!-- 首次加载占位: 首屏请求结束前用它顶住, 避免先闪空态再跳成列表 -->
|
||||
<view class="first-loading" v-if="!booted">
|
||||
<text>加载中…</text>
|
||||
</view>
|
||||
|
||||
<!-- 空态: 建卡申请 / 申请状态(2.11.15); booted 未置位说明还没拿到数据, 不展示空态 -->
|
||||
<view v-if="booted && !isLoading && list.length === 0" class="card-empty">
|
||||
<!-- 分组/搜索/收藏筛选为空: 只是当下没有符合条件的名片, 不能当成"还没建卡"去引导申请 -->
|
||||
<block v-if="emptyScene">
|
||||
<view class="empty-icon">{{ emptyScene.icon }}</view>
|
||||
<view class="empty-title">{{ emptyScene.title }}</view>
|
||||
<view class="empty-sub">{{ emptyScene.sub }}</view>
|
||||
</block>
|
||||
<block v-else-if="apply && apply.status === 0">
|
||||
<view class="empty-icon">⏳</view>
|
||||
<view class="empty-title">申请审核中</view>
|
||||
<view class="empty-sub">您的建卡申请正在等待商家审批</view>
|
||||
@@ -144,9 +155,34 @@ export default {
|
||||
apply: null, // { status, status_text, note, has_card }
|
||||
applyName: '',
|
||||
applyMobile: '',
|
||||
applying: false
|
||||
applying: false,
|
||||
// 首次数据请求是否已结束: 未结束前不渲染空态,
|
||||
// 否则重新编译/刷新时会先闪一下「还没有名片 + 申请表单」(列表其实有数据)
|
||||
booted: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* 筛选态下的空态文案。
|
||||
* 重要: 只有「全部 + 无搜索 + 无收藏筛选」才代表"用户还没有名片"(这时才引导建卡申请);
|
||||
* 待跟进/已完成/搜索/收藏 只是当下没有符合条件的卡, 不能弹申请表单。
|
||||
*/
|
||||
emptyScene() {
|
||||
if (this.followTab === 'due') {
|
||||
return { icon: '📇', title: '暂无待跟进名片', sub: '有跟进中的名片会出现在这里' };
|
||||
}
|
||||
if (this.followTab === 'done') {
|
||||
return { icon: '📇', title: '暂无已完成名片', sub: '标记完成的名片会出现在这里' };
|
||||
}
|
||||
if (this.onlyFav) {
|
||||
return { icon: '☆', title: '暂无收藏的名片', sub: '点名片右侧的星标即可收藏' };
|
||||
}
|
||||
if (this.keyword.trim()) {
|
||||
return { icon: '🔍', title: '未找到匹配的名片', sub: '换个关键词试试' };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
// 扫码带参预填(文档 §5): 二维码/链接带 claim_code 或 card_id 直接进入认领
|
||||
if (options && (options.claim_code || options.card_id)) {
|
||||
@@ -154,7 +190,12 @@ export default {
|
||||
.toUpperCase().replace(/\s+/g, '');
|
||||
this.claimMode = options.claim_code ? 'code' : 'id';
|
||||
}
|
||||
this.refresh();
|
||||
this.bootstrap();
|
||||
},
|
||||
onShow() {
|
||||
// 首次 onShow 紧跟 onLoad(由 bootstrap 负责首屏加载), 这里只处理"返回本页"的刷新
|
||||
if (this._entered) this.refresh();
|
||||
this._entered = true;
|
||||
},
|
||||
onPullDownRefresh() {
|
||||
this.refresh(() => uni.stopPullDownRefresh());
|
||||
@@ -165,6 +206,45 @@ export default {
|
||||
this.loadPage(this.page + 1);
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 首屏加载: 等 member token 就绪后再请求。
|
||||
*
|
||||
* 背景(为什么需要): App.vue 的 onLaunch 是 async, token 在多个 await
|
||||
* (i18n / 主题 / 远端配置 / 隐私弹窗) 之后才从 storage 恢复到 store。
|
||||
* 页面 onLoad 在 onLaunch 第一次 await 让出后就执行, 此时 store.state.token
|
||||
* 仍是 null → card/lists 以未登录身份请求, 后端返回空列表;
|
||||
* 本页原本又没有 onShow 重拉, 于是表现为「刷新/重新编译后没有名片,
|
||||
* 必须退出页面重新进入才看得到」。
|
||||
*/
|
||||
bootstrap() {
|
||||
// 等 token 期间也处于"加载中", 否则首屏会先渲染空态
|
||||
this.isLoading = true;
|
||||
this.waitTokenReady().then(() => this.refresh());
|
||||
},
|
||||
/**
|
||||
* 等 token 就绪:
|
||||
* - store 已有 token → 直接放行;
|
||||
* - storage 有 token 但 store 还没有 → onLaunch 还在跑, 轮询等待(最多 timeout);
|
||||
* - storage 也没有 → 未登录/游客, 不等, 用空 token 请求(由后端决定返回)。
|
||||
*/
|
||||
waitTokenReady(timeout = 3000) {
|
||||
if (this.$store.state.token) return Promise.resolve(true);
|
||||
let stored = '';
|
||||
try { stored = uni.getStorageSync('token') || ''; } catch (e) { stored = ''; }
|
||||
if (!stored) return Promise.resolve(false);
|
||||
return new Promise(resolve => {
|
||||
const start = Date.now();
|
||||
const timer = setInterval(() => {
|
||||
if (this.$store.state.token) {
|
||||
clearInterval(timer);
|
||||
resolve(true);
|
||||
} else if (Date.now() - start >= timeout) {
|
||||
clearInterval(timer);
|
||||
resolve(false);
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
},
|
||||
avatarText(name) {
|
||||
return (name || '?').trim().charAt(0).toUpperCase();
|
||||
},
|
||||
@@ -310,7 +390,8 @@ export default {
|
||||
this.page = pageNo;
|
||||
this.list = pageNo === 1 ? rows : this.list.concat(rows);
|
||||
// 空态(首页无卡): 拉取建卡申请状态, 驱动空态申请 UI(2.11.15)
|
||||
if (pageNo === 1 && rows.length === 0) this.loadApplyStatus();
|
||||
// 仅「全部 + 无搜索 + 无收藏筛选」时才需要(其余筛选为空不代表用户没卡)
|
||||
if (pageNo === 1 && rows.length === 0 && !this.emptyScene) this.loadApplyStatus();
|
||||
this.emptyText = this.keyword.trim()
|
||||
? '未找到匹配的名片'
|
||||
: '暂无名片,可点击右上角「新建」或「认领」添加';
|
||||
@@ -318,10 +399,13 @@ export default {
|
||||
this.handleApiError(res);
|
||||
}
|
||||
this.isLoading = false;
|
||||
// 首次请求结束(无论成功/失败)才允许渲染空态
|
||||
this.booted = true;
|
||||
typeof done === 'function' && done();
|
||||
},
|
||||
fail: () => {
|
||||
this.isLoading = false;
|
||||
this.booted = true;
|
||||
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
|
||||
typeof done === 'function' && done();
|
||||
}
|
||||
@@ -666,6 +750,14 @@ export default {
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
/* 首屏加载占位(替代"先闪空态") */
|
||||
.first-loading {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 26rpx;
|
||||
padding: 160rpx 0;
|
||||
}
|
||||
|
||||
/* 空态: 建卡申请 */
|
||||
.card-empty {
|
||||
text-align: center;
|
||||
|
||||
Reference in New Issue
Block a user