chore:待跟进和已完成页面正常
This commit is contained in:
@@ -63,9 +63,20 @@
|
|||||||
<text v-else class="load-end">— 没有更多了 —</text>
|
<text v-else class="load-end">— 没有更多了 —</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 空态: 建卡申请 / 申请状态(2.11.15) -->
|
<!-- 首次加载占位: 首屏请求结束前用它顶住, 避免先闪空态再跳成列表 -->
|
||||||
<view v-if="!isLoading && list.length === 0" class="card-empty">
|
<view class="first-loading" v-if="!booted">
|
||||||
<block v-if="apply && apply.status === 0">
|
<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-icon">⏳</view>
|
||||||
<view class="empty-title">申请审核中</view>
|
<view class="empty-title">申请审核中</view>
|
||||||
<view class="empty-sub">您的建卡申请正在等待商家审批</view>
|
<view class="empty-sub">您的建卡申请正在等待商家审批</view>
|
||||||
@@ -144,9 +155,34 @@ export default {
|
|||||||
apply: null, // { status, status_text, note, has_card }
|
apply: null, // { status, status_text, note, has_card }
|
||||||
applyName: '',
|
applyName: '',
|
||||||
applyMobile: '',
|
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) {
|
onLoad(options) {
|
||||||
// 扫码带参预填(文档 §5): 二维码/链接带 claim_code 或 card_id 直接进入认领
|
// 扫码带参预填(文档 §5): 二维码/链接带 claim_code 或 card_id 直接进入认领
|
||||||
if (options && (options.claim_code || options.card_id)) {
|
if (options && (options.claim_code || options.card_id)) {
|
||||||
@@ -154,7 +190,12 @@ export default {
|
|||||||
.toUpperCase().replace(/\s+/g, '');
|
.toUpperCase().replace(/\s+/g, '');
|
||||||
this.claimMode = options.claim_code ? 'code' : 'id';
|
this.claimMode = options.claim_code ? 'code' : 'id';
|
||||||
}
|
}
|
||||||
this.refresh();
|
this.bootstrap();
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
// 首次 onShow 紧跟 onLoad(由 bootstrap 负责首屏加载), 这里只处理"返回本页"的刷新
|
||||||
|
if (this._entered) this.refresh();
|
||||||
|
this._entered = true;
|
||||||
},
|
},
|
||||||
onPullDownRefresh() {
|
onPullDownRefresh() {
|
||||||
this.refresh(() => uni.stopPullDownRefresh());
|
this.refresh(() => uni.stopPullDownRefresh());
|
||||||
@@ -165,6 +206,45 @@ export default {
|
|||||||
this.loadPage(this.page + 1);
|
this.loadPage(this.page + 1);
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
avatarText(name) {
|
||||||
return (name || '?').trim().charAt(0).toUpperCase();
|
return (name || '?').trim().charAt(0).toUpperCase();
|
||||||
},
|
},
|
||||||
@@ -310,7 +390,8 @@ export default {
|
|||||||
this.page = pageNo;
|
this.page = pageNo;
|
||||||
this.list = pageNo === 1 ? rows : this.list.concat(rows);
|
this.list = pageNo === 1 ? rows : this.list.concat(rows);
|
||||||
// 空态(首页无卡): 拉取建卡申请状态, 驱动空态申请 UI(2.11.15)
|
// 空态(首页无卡): 拉取建卡申请状态, 驱动空态申请 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()
|
this.emptyText = this.keyword.trim()
|
||||||
? '未找到匹配的名片'
|
? '未找到匹配的名片'
|
||||||
: '暂无名片,可点击右上角「新建」或「认领」添加';
|
: '暂无名片,可点击右上角「新建」或「认领」添加';
|
||||||
@@ -318,10 +399,13 @@ export default {
|
|||||||
this.handleApiError(res);
|
this.handleApiError(res);
|
||||||
}
|
}
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
// 首次请求结束(无论成功/失败)才允许渲染空态
|
||||||
|
this.booted = true;
|
||||||
typeof done === 'function' && done();
|
typeof done === 'function' && done();
|
||||||
},
|
},
|
||||||
fail: () => {
|
fail: () => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
this.booted = true;
|
||||||
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
|
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
|
||||||
typeof done === 'function' && done();
|
typeof done === 'function' && done();
|
||||||
}
|
}
|
||||||
@@ -666,6 +750,14 @@ export default {
|
|||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 首屏加载占位(替代"先闪空态") */
|
||||||
|
.first-loading {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 26rpx;
|
||||||
|
padding: 160rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 空态: 建卡申请 */
|
/* 空态: 建卡申请 */
|
||||||
.card-empty {
|
.card-empty {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user