From 49c9aca0e6aeac6c26eeec43cc9e38e3a15445ce Mon Sep 17 00:00:00 2001 From: Jafeng <2998840497@qq.com> Date: Tue, 10 Feb 2026 13:40:49 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=9B=A2=E9=98=9F?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E5=A4=B1=E8=B4=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/case-home.vue | 281 ++++++++++++++++++++++++++++++++------- 1 file changed, 235 insertions(+), 46 deletions(-) diff --git a/pages/home/case-home.vue b/pages/home/case-home.vue index 6febbee..6495142 100644 --- a/pages/home/case-home.vue +++ b/pages/home/case-home.vue @@ -2,7 +2,19 @@ - + + + {{ teamDisplay }} + + + + {{ teamDisplay }} @@ -139,6 +151,10 @@ const currentTeam = ref(null); const currentTabKey = ref('all'); const scrollIntoId = 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 base = [ { key: 'all', label: '全部', kind: 'all' }, @@ -184,12 +200,18 @@ const BATCH_CUSTOMER_IDS_KEY = 'ykt_case_batch_customer_ids'; const page = ref(1); const pages = ref(0); -const pageSize = ref(50); +const pageSize = ref(200); const totalFromApi = ref(0); const loading = ref(false); const rawPatients = ref([]); const more = computed(() => page.value < pages.value); 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 { account, doctorInfo } = storeToRefs(accountStore); @@ -198,10 +220,92 @@ const { withInfo } = useInfoCheck(); 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) { 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) { if (value === null || value === undefined) return ''; if (typeof value === 'object') { @@ -661,11 +765,24 @@ async function loadGroups() { const teamId = getTeamId(); if (!corpId || !teamId) return; 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) { - teamGroups.value = []; + lastGroupsLoadOk.value = false; + if (!loadedGroupsTeamId.value || loadedGroupsTeamId.value !== teamId) teamGroups.value = []; return; } + lastGroupsLoadOk.value = true; + loadedGroupsTeamId.value = teamId; const list = Array.isArray(res.data) ? res.data : Array.isArray(res.data?.data) ? res.data.data : []; teamGroups.value = sortGroupList(list); @@ -1012,7 +1129,7 @@ function groupByLetter(list) { return letters.map((letter) => ({ letter, data: map.get(letter) || [] })); } -async function loadTeams() { +async function loadTeams(opts = {}) { if (!doctorInfo.value && account.value?.openid) { try { await getDoctorInfo(); @@ -1029,15 +1146,22 @@ async function loadTeams() { 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) { - toast(res?.message || '获取团队失败'); + lastTeamsLoadOk.value = false; + if (!opts?.silent) toast(res?.message || '获取团队失败'); return; } const list = Array.isArray(res?.data) ? res.data : Array.isArray(res?.data?.data) ? res.data.data : []; const normalized = list.map(normalizeTeam).filter(Boolean); teams.value = normalized; + lastTeamsLoadOk.value = true; const saved = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY); 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); } -async function reload(reset = true) { - if (!currentTeam.value) return; - if (loading.value) return; +async function reload(reset = true, opts = {}) { + if (!currentTeam.value) return false; + if (loading.value) return false; await ensureDoctorForQuery(); const userId = getUserId(); @@ -1058,19 +1182,27 @@ async function reload(reset = true) { return; } - if (reset) { + const keepOnFail = Boolean(opts?.keepOnFail); + const targetPage = reset ? 1 : page.value; + + if (reset && !keepOnFail) { page.value = 1; rawPatients.value = []; pages.value = 0; totalFromApi.value = 0; } + if (reset) { + const net = await getNetworkTypeSafe(); + pageSize.value = pickPageSizeByNetwork(net); + } + const query = { corpId, userId, teamId, - page: page.value, - pageSize: 1000, // 按首字母排序时,一次加载更多数据以显示完整的字母分组 + page: targetPage, + pageSize: pageSize.value, // 按首字母排序时,按网络自适应加载数量 sortByFirstLetter: true, // 按姓名首字母排序 }; @@ -1086,14 +1218,24 @@ async function reload(reset = true) { } loading.value = true; - const res = await api('searchCorpCustomerForCaseList', query); - loading.value = false; + let res; + try { + res = await apiWithRetry('searchCorpCustomerForCaseList', query, !opts?.silent, { retries: 1 }); + } catch { + res = null; + } finally { + loading.value = false; + } if (!res?.success) { - toast(res?.message || '获取患者列表失败'); - return; + lastPatientsLoadOk.value = false; + if (!opts?.silent || (rawPatients.value || []).length === 0) toast(res?.message || '获取患者列表失败'); + return false; } + if (reset) page.value = 1; + lastPatientsLoadOk.value = true; + const payload = res && typeof res === 'object' ? 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 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(() => {}); pages.value = Number(payload.pages || 0) || 0; @@ -1116,6 +1258,8 @@ async function reload(reset = true) { totalFromApi.value || 0 ) || (totalFromApi.value || 0); + + return true; } const handlePatientClick = (patient) => { @@ -1191,8 +1335,40 @@ const scrollToLetter = (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 = () => { if (checkBatchMode()) return; + if (useTeamPicker.value) return; if (!teams.value.length) { toast('暂无可选团队'); return; @@ -1200,12 +1376,7 @@ const toggleTeamPopup = () => { uni.showActionSheet({ itemList: teams.value.map((i) => i.name), success: async (res) => { - currentTeam.value = 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); + await applyTeamSelection(teams.value[res.tapIndex] || teams.value[0] || null); } }); }; @@ -1432,7 +1603,6 @@ async function transferToCustomerPool(customerIds) { } toast('操作成功'); cancelBatch(); - await reload(true); } catch (e) { toast('操作失败'); } finally { @@ -1495,7 +1665,6 @@ async function transferToOtherTeam(customerIds) { } toast('操作成功'); cancelBatch(); - await reload(true); } catch (e) { toast('操作失败'); } finally { @@ -1536,10 +1705,12 @@ const handleShare = () => { uni.navigateTo({ url: '/pages/case/batch-share' }); }; -function loadMore() { +async function loadMore() { if (!more.value || loading.value) return; - page.value += 1; - reload(false); + const nextPage = page.value + 1; + page.value = nextPage; + const ok = await reload(false, { silent: true }); + if (!ok) page.value = nextPage - 1; } watch(currentTeam, (t) => { @@ -1549,6 +1720,7 @@ watch(currentTeam, (t) => { watch(currentTabKey, () => { if (!currentTeam.value) return; + if (suppressTabReload.value) return; loadTeamMembers(); reload(true); }); @@ -1562,36 +1734,53 @@ function onTabClick(tab) { 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 () => { - await loadTeams(); - if (currentTeam.value) { - await loadGroups(); - await loadTeamMembers(); - await reload(true); - } - await refreshVerifyStatus(); + await refreshOnEnter(); }); onShow(async () => { const need = uni.getStorageSync(NEED_RELOAD_STORAGE_KEY); if (need) { uni.removeStorageSync(NEED_RELOAD_STORAGE_KEY); - await reload(true); // 批量操作完成后回到列表,默认退出批量态 isBatchMode.value = false; selectedItems.value = []; } const needGroups = uni.getStorageSync(GROUPS_RELOAD_KEY); - if (needGroups) { - uni.removeStorageSync(GROUPS_RELOAD_KEY); - await loadGroups(); - await reload(true); - } else { - await loadGroups(); - } - await loadTeamMembers(); - await refreshVerifyStatus(); + if (needGroups) uni.removeStorageSync(GROUPS_RELOAD_KEY); + + await refreshOnEnter(); });