fix:修复团队加载失败的bug

This commit is contained in:
Jafeng 2026-02-10 13:40:49 +08:00
parent ba1200a650
commit 49c9aca0e6

View File

@ -2,7 +2,19 @@
<view class="container"> <view class="container">
<!-- Header --> <!-- Header -->
<view class="header"> <view class="header">
<view class="team-selector" @click="toggleTeamPopup"> <picker
v-if="useTeamPicker"
mode="selector"
:range="teamNameRange"
:value="teamPickerIndex"
@change="onTeamPickerChange"
>
<view class="team-selector">
<text class="team-name">{{ teamDisplay }}</text>
<text class="team-icon"></text>
</view>
</picker>
<view v-else class="team-selector" @click="toggleTeamPopup">
<text class="team-name">{{ teamDisplay }}</text> <text class="team-name">{{ teamDisplay }}</text>
<text class="team-icon"></text> <text class="team-icon"></text>
</view> </view>
@ -139,6 +151,10 @@ const currentTeam = ref(null);
const currentTabKey = ref('all'); const currentTabKey = ref('all');
const scrollIntoId = ref(''); const scrollIntoId = ref('');
const teamGroups = ref([]); const teamGroups = ref([]);
const useTeamPicker = computed(() => (Array.isArray(teams.value) ? teams.value.length : 0) > 6);
const teamNameRange = computed(() => (Array.isArray(teams.value) ? teams.value.map((t) => t?.name || '') : []));
const teamPickerIndex = ref(0);
const suppressTabReload = ref(false);
const tabs = computed(() => { const tabs = computed(() => {
const base = [ const base = [
{ key: 'all', label: '全部', kind: 'all' }, { key: 'all', label: '全部', kind: 'all' },
@ -184,12 +200,18 @@ const BATCH_CUSTOMER_IDS_KEY = 'ykt_case_batch_customer_ids';
const page = ref(1); const page = ref(1);
const pages = ref(0); const pages = ref(0);
const pageSize = ref(50); const pageSize = ref(200);
const totalFromApi = ref(0); const totalFromApi = ref(0);
const loading = ref(false); const loading = ref(false);
const rawPatients = ref([]); const rawPatients = ref([]);
const more = computed(() => page.value < pages.value); const more = computed(() => page.value < pages.value);
const currentTab = computed(() => tabs.value.find((t) => t.key === currentTabKey.value) || tabs.value[0]); const currentTab = computed(() => tabs.value.find((t) => t.key === currentTabKey.value) || tabs.value[0]);
const lastTeamsLoadOk = ref(true);
const lastGroupsLoadOk = ref(true);
const lastPatientsLoadOk = ref(true);
const loadedGroupsTeamId = ref('');
let enterRefreshInflight = null;
const hasEnteredOnce = ref(false);
const accountStore = useAccountStore(); const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore); const { account, doctorInfo } = storeToRefs(accountStore);
@ -198,10 +220,92 @@ const { withInfo } = useInfoCheck();
const teamDisplay = computed(() => `${currentTeam.value?.name || ''}`); const teamDisplay = computed(() => `${currentTeam.value?.name || ''}`);
watch(
[teams, currentTeam],
() => {
const list = Array.isArray(teams.value) ? teams.value : [];
const tid = currentTeam.value?.teamId ? String(currentTeam.value.teamId) : '';
const idx = tid ? list.findIndex((t) => String(t?.teamId || '') === tid) : -1;
teamPickerIndex.value = idx >= 0 ? idx : 0;
},
{ immediate: true }
);
function asArray(value) { function asArray(value) {
return Array.isArray(value) ? value : []; return Array.isArray(value) ? value : [];
} }
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function getNetworkTypeSafe() {
try {
return await new Promise((resolve) => {
let done = false;
const timer = setTimeout(() => {
if (done) return;
done = true;
resolve('unknown');
}, 800);
uni.getNetworkType({
success: (res) => {
if (done) return;
done = true;
clearTimeout(timer);
resolve(String(res?.networkType || 'unknown'));
},
fail: () => {
if (done) return;
done = true;
clearTimeout(timer);
resolve('unknown');
},
});
});
} catch {
return 'unknown';
}
}
function pickPageSizeByNetwork(type) {
const t = String(type || '').toLowerCase();
if (t === '2g') return 100;
if (t === '3g') return 150;
if (t === '4g') return 250;
if (t === '5g' || t === 'wifi') return 300;
return 200;
}
async function apiWithRetry(urlId, data, showLoading = true, opts = {}) {
const retries = Number(opts?.retries ?? 1);
const baseDelay = Number(opts?.baseDelay ?? 350);
const shouldRetryMessage = (msg) =>
/timeout|timed out|超时|网络|network|fail|connect|ECONN|ENOTFOUND/i.test(String(msg || ''));
for (let i = 0; i <= retries; i += 1) {
try {
const res = await api(urlId, data, showLoading);
if (res?.success) return res;
const message = String(res?.message || '');
if (i < retries && shouldRetryMessage(message)) {
await sleep(Math.min(baseDelay * Math.pow(2, i), 1500));
continue;
}
return res;
} catch (e) {
if (i < retries) {
await sleep(Math.min(baseDelay * Math.pow(2, i), 1500));
continue;
}
throw e;
}
}
return { success: false, message: '请求失败' };
}
function normalizeUserId(value) { function normalizeUserId(value) {
if (value === null || value === undefined) return ''; if (value === null || value === undefined) return '';
if (typeof value === 'object') { if (typeof value === 'object') {
@ -661,11 +765,24 @@ async function loadGroups() {
const teamId = getTeamId(); const teamId = getTeamId();
if (!corpId || !teamId) return; if (!corpId || !teamId) return;
const projection = { _id: 1, groupName: 1, parentGroupId: 1, sortOrder: 1 }; const projection = { _id: 1, groupName: 1, parentGroupId: 1, sortOrder: 1 };
const res = await api('getGroups', { corpId, teamId, page: 1, pageSize: 1000, projection, countGroupMember: false }); let res;
try {
res = await apiWithRetry(
'getGroups',
{ corpId, teamId, page: 1, pageSize: 1000, projection, countGroupMember: false },
false,
{ retries: 1 }
);
} catch {
res = null;
}
if (!res?.success) { if (!res?.success) {
teamGroups.value = []; lastGroupsLoadOk.value = false;
if (!loadedGroupsTeamId.value || loadedGroupsTeamId.value !== teamId) teamGroups.value = [];
return; return;
} }
lastGroupsLoadOk.value = true;
loadedGroupsTeamId.value = teamId;
const list = Array.isArray(res.data) ? res.data : Array.isArray(res.data?.data) ? res.data.data : []; const list = Array.isArray(res.data) ? res.data : Array.isArray(res.data?.data) ? res.data.data : [];
teamGroups.value = sortGroupList(list); teamGroups.value = sortGroupList(list);
@ -1012,7 +1129,7 @@ function groupByLetter(list) {
return letters.map((letter) => ({ letter, data: map.get(letter) || [] })); return letters.map((letter) => ({ letter, data: map.get(letter) || [] }));
} }
async function loadTeams() { async function loadTeams(opts = {}) {
if (!doctorInfo.value && account.value?.openid) { if (!doctorInfo.value && account.value?.openid) {
try { try {
await getDoctorInfo(); await getDoctorInfo();
@ -1029,15 +1146,22 @@ async function loadTeams() {
return; return;
} }
const res = await api('getTeamBymember', { corpId, corpUserId: userId }); let res;
try {
res = await apiWithRetry('getTeamBymember', { corpId, corpUserId: userId }, !opts?.silent, { retries: 2 });
} catch {
res = null;
}
if (!res?.success) { if (!res?.success) {
toast(res?.message || '获取团队失败'); lastTeamsLoadOk.value = false;
if (!opts?.silent) toast(res?.message || '获取团队失败');
return; return;
} }
const list = Array.isArray(res?.data) ? res.data : Array.isArray(res?.data?.data) ? res.data.data : []; const list = Array.isArray(res?.data) ? res.data : Array.isArray(res?.data?.data) ? res.data.data : [];
const normalized = list.map(normalizeTeam).filter(Boolean); const normalized = list.map(normalizeTeam).filter(Boolean);
teams.value = normalized; teams.value = normalized;
lastTeamsLoadOk.value = true;
const saved = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY); const saved = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY);
const savedTeamId = saved?.teamId ? String(saved.teamId) : ''; const savedTeamId = saved?.teamId ? String(saved.teamId) : '';
@ -1045,9 +1169,9 @@ async function loadTeams() {
if (currentTeam.value) uni.setStorageSync(CURRENT_TEAM_STORAGE_KEY, currentTeam.value); if (currentTeam.value) uni.setStorageSync(CURRENT_TEAM_STORAGE_KEY, currentTeam.value);
} }
async function reload(reset = true) { async function reload(reset = true, opts = {}) {
if (!currentTeam.value) return; if (!currentTeam.value) return false;
if (loading.value) return; if (loading.value) return false;
await ensureDoctorForQuery(); await ensureDoctorForQuery();
const userId = getUserId(); const userId = getUserId();
@ -1058,19 +1182,27 @@ async function reload(reset = true) {
return; return;
} }
if (reset) { const keepOnFail = Boolean(opts?.keepOnFail);
const targetPage = reset ? 1 : page.value;
if (reset && !keepOnFail) {
page.value = 1; page.value = 1;
rawPatients.value = []; rawPatients.value = [];
pages.value = 0; pages.value = 0;
totalFromApi.value = 0; totalFromApi.value = 0;
} }
if (reset) {
const net = await getNetworkTypeSafe();
pageSize.value = pickPageSizeByNetwork(net);
}
const query = { const query = {
corpId, corpId,
userId, userId,
teamId, teamId,
page: page.value, page: targetPage,
pageSize: 1000, // pageSize: pageSize.value, //
sortByFirstLetter: true, // sortByFirstLetter: true, //
}; };
@ -1086,14 +1218,24 @@ async function reload(reset = true) {
} }
loading.value = true; loading.value = true;
const res = await api('searchCorpCustomerForCaseList', query); let res;
loading.value = false; try {
res = await apiWithRetry('searchCorpCustomerForCaseList', query, !opts?.silent, { retries: 1 });
} catch {
res = null;
} finally {
loading.value = false;
}
if (!res?.success) { if (!res?.success) {
toast(res?.message || '获取患者列表失败'); lastPatientsLoadOk.value = false;
return; if (!opts?.silent || (rawPatients.value || []).length === 0) toast(res?.message || '获取患者列表失败');
return false;
} }
if (reset) page.value = 1;
lastPatientsLoadOk.value = true;
const payload = const payload =
res && typeof res === 'object' res && typeof res === 'object'
? res.data && typeof res.data === 'object' && !Array.isArray(res.data) ? res.data && typeof res.data === 'object' && !Array.isArray(res.data)
@ -1102,7 +1244,7 @@ async function reload(reset = true) {
: {}; : {};
const list = Array.isArray(payload.list) ? payload.list : Array.isArray(payload.data) ? payload.data : []; const list = Array.isArray(payload.list) ? payload.list : Array.isArray(payload.data) ? payload.data : [];
const next = list.map(formatPatient); const next = list.map(formatPatient);
rawPatients.value = page.value === 1 ? next : [...rawPatients.value, ...next]; rawPatients.value = targetPage === 1 ? next : [...rawPatients.value, ...next];
// / // /
void prefetchUserNamesFromPatients(next).catch(() => {}); void prefetchUserNamesFromPatients(next).catch(() => {});
pages.value = Number(payload.pages || 0) || 0; pages.value = Number(payload.pages || 0) || 0;
@ -1116,6 +1258,8 @@ async function reload(reset = true) {
totalFromApi.value || totalFromApi.value ||
0 0
) || (totalFromApi.value || 0); ) || (totalFromApi.value || 0);
return true;
} }
const handlePatientClick = (patient) => { const handlePatientClick = (patient) => {
@ -1191,8 +1335,40 @@ const scrollToLetter = (letter) => {
scrollIntoId.value = letterToDomId(letter); scrollIntoId.value = letterToDomId(letter);
}; };
async function applyTeamSelection(nextTeam) {
if (!nextTeam) return;
const nextId = String(nextTeam?.teamId || '');
if (nextId && nextId === getTeamId()) return;
suppressTabReload.value = true;
try {
currentTeam.value = nextTeam;
if (currentTeam.value) uni.setStorageSync(CURRENT_TEAM_STORAGE_KEY, currentTeam.value);
currentTabKey.value = 'all';
await loadGroups();
await loadTeamMembers();
await reload(true);
} finally {
suppressTabReload.value = false;
}
}
async function onTeamPickerChange(e) {
const prev = teamPickerIndex.value;
if (checkBatchMode()) {
teamPickerIndex.value = prev;
return;
}
const idx = Number(e?.detail?.value ?? prev);
if (!Number.isFinite(idx)) return;
teamPickerIndex.value = idx;
await applyTeamSelection((Array.isArray(teams.value) ? teams.value : [])[idx]);
}
const toggleTeamPopup = () => { const toggleTeamPopup = () => {
if (checkBatchMode()) return; if (checkBatchMode()) return;
if (useTeamPicker.value) return;
if (!teams.value.length) { if (!teams.value.length) {
toast('暂无可选团队'); toast('暂无可选团队');
return; return;
@ -1200,12 +1376,7 @@ const toggleTeamPopup = () => {
uni.showActionSheet({ uni.showActionSheet({
itemList: teams.value.map((i) => i.name), itemList: teams.value.map((i) => i.name),
success: async (res) => { success: async (res) => {
currentTeam.value = teams.value[res.tapIndex] || teams.value[0] || null; await applyTeamSelection(teams.value[res.tapIndex] || teams.value[0] || null);
if (currentTeam.value) uni.setStorageSync(CURRENT_TEAM_STORAGE_KEY, currentTeam.value);
currentTabKey.value = 'all';
await loadGroups();
await loadTeamMembers();
await reload(true);
} }
}); });
}; };
@ -1432,7 +1603,6 @@ async function transferToCustomerPool(customerIds) {
} }
toast('操作成功'); toast('操作成功');
cancelBatch(); cancelBatch();
await reload(true);
} catch (e) { } catch (e) {
toast('操作失败'); toast('操作失败');
} finally { } finally {
@ -1495,7 +1665,6 @@ async function transferToOtherTeam(customerIds) {
} }
toast('操作成功'); toast('操作成功');
cancelBatch(); cancelBatch();
await reload(true);
} catch (e) { } catch (e) {
toast('操作失败'); toast('操作失败');
} finally { } finally {
@ -1536,10 +1705,12 @@ const handleShare = () => {
uni.navigateTo({ url: '/pages/case/batch-share' }); uni.navigateTo({ url: '/pages/case/batch-share' });
}; };
function loadMore() { async function loadMore() {
if (!more.value || loading.value) return; if (!more.value || loading.value) return;
page.value += 1; const nextPage = page.value + 1;
reload(false); page.value = nextPage;
const ok = await reload(false, { silent: true });
if (!ok) page.value = nextPage - 1;
} }
watch(currentTeam, (t) => { watch(currentTeam, (t) => {
@ -1549,6 +1720,7 @@ watch(currentTeam, (t) => {
watch(currentTabKey, () => { watch(currentTabKey, () => {
if (!currentTeam.value) return; if (!currentTeam.value) return;
if (suppressTabReload.value) return;
loadTeamMembers(); loadTeamMembers();
reload(true); reload(true);
}); });
@ -1562,36 +1734,53 @@ function onTabClick(tab) {
currentTabKey.value = tab.key; currentTabKey.value = tab.key;
} }
async function refreshOnEnter() {
if (enterRefreshInflight) return enterRefreshInflight;
enterRefreshInflight = (async () => {
const silent = hasEnteredOnce.value;
let didLoadSomething = false;
// /线
if (!currentTeam.value) {
const saved = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY);
if (saved && saved.teamId) currentTeam.value = saved;
}
await loadTeams({ silent });
if (lastTeamsLoadOk.value) didLoadSomething = true;
if (currentTeam.value) {
await loadGroups();
await loadTeamMembers();
const ok = await reload(true, { silent, keepOnFail: true });
if (ok) didLoadSomething = true;
}
await refreshVerifyStatus();
if (didLoadSomething) hasEnteredOnce.value = true;
})().finally(() => {
enterRefreshInflight = null;
});
return enterRefreshInflight;
}
onLoad(async () => { onLoad(async () => {
await loadTeams(); await refreshOnEnter();
if (currentTeam.value) {
await loadGroups();
await loadTeamMembers();
await reload(true);
}
await refreshVerifyStatus();
}); });
onShow(async () => { onShow(async () => {
const need = uni.getStorageSync(NEED_RELOAD_STORAGE_KEY); const need = uni.getStorageSync(NEED_RELOAD_STORAGE_KEY);
if (need) { if (need) {
uni.removeStorageSync(NEED_RELOAD_STORAGE_KEY); uni.removeStorageSync(NEED_RELOAD_STORAGE_KEY);
await reload(true);
// 退 // 退
isBatchMode.value = false; isBatchMode.value = false;
selectedItems.value = []; selectedItems.value = [];
} }
const needGroups = uni.getStorageSync(GROUPS_RELOAD_KEY); const needGroups = uni.getStorageSync(GROUPS_RELOAD_KEY);
if (needGroups) { if (needGroups) uni.removeStorageSync(GROUPS_RELOAD_KEY);
uni.removeStorageSync(GROUPS_RELOAD_KEY);
await loadGroups(); await refreshOnEnter();
await reload(true);
} else {
await loadGroups();
}
await loadTeamMembers();
await refreshVerifyStatus();
}); });
</script> </script>