diff --git a/hooks/useInfoCheck.js b/hooks/useInfoCheck.js index d741127..d5989ee 100644 --- a/hooks/useInfoCheck.js +++ b/hooks/useInfoCheck.js @@ -9,11 +9,15 @@ export default function useInfoCheck() { function withInfo(fn) { return async (...args) => { if (!doctorInfo.value || !doctorInfo.value.anotherName) { - await confirm('请先完善您的个人信息,方可使用该功能!', { cancelText: '再等等', confirmText: '去完善' }) + try { + await confirm('请先完善您的个人信息,方可使用该功能!', { cancelText: '再等等', confirmText: '去完善' }) + } catch { + return; + } return uni.navigateTo({ url: '/pages/work/profile' }); } return fn(...args); } } return { withInfo } -} \ No newline at end of file +} diff --git a/pages/case/search.vue b/pages/case/search.vue index e4bad94..e8ffbe6 100644 --- a/pages/case/search.vue +++ b/pages/case/search.vue @@ -6,7 +6,7 @@ - 输入患者名称、手机号或院内ID号进行搜索 + 输入患者名称、手机号或病案号进行搜索 @@ -73,6 +73,7 @@ import { toast } from '@/utils/widget'; const searchQuery = ref(''); const searchResultsRaw = ref([]); const searching = ref(false); +const searchSeq = ref(0); const CURRENT_TEAM_STORAGE_KEY = 'ykt_case_current_team'; const DETAIL_STORAGE_KEY = 'ykt_case_archive_detail'; @@ -111,11 +112,29 @@ function formatPatient(raw) { const mobiles = asArray(raw?.mobiles).map(String).filter(Boolean); const mobile = raw?.mobile ? String(raw.mobile) : (mobiles[0] || ''); + const customerNumber = raw?.customerNumber || raw?.hospitalId || ''; + const customerProfileNo2 = raw?.customerProfileNo2 || ''; + const customerProfileNo3 = raw?.customerProfileNo3 || ''; + + function normalizeRecordTypeLabel(value) { + const s = String(value || '').trim(); + if (!s) return ''; + const lower = s.toLowerCase(); + const base = lower.endsWith('record') && s.length > 6 ? s.slice(0, -6) : s; + const baseLower = String(base).toLowerCase(); + if (baseLower === 'outpatient' || baseLower === 'out_patient' || baseLower === 'out-patient') return '门诊记录'; + if (baseLower === 'inhospital' || baseLower === 'in_hospital' || baseLower === 'in-hospital' || baseLower === 'inpatient') return '住院记录'; + if (baseLower === 'preconsultation' || baseLower === 'pre_consultation' || baseLower === 'pre-consultation' || baseLower === 'preconsultationtemplate') return '预问诊记录'; + if (baseLower === 'physicalexaminationtemplate' || baseLower === 'physicalexamination' || baseLower === 'physical_examination') return '体检记录'; + // 如果已经是中文(或后端已给展示名),直接返回 + return s; + } + // 解析病历信息 let record = null; if (raw?.latestRecord && typeof raw.latestRecord === 'object') { const lr = raw.latestRecord; - const type = lr.type || ''; + const type = normalizeRecordTypeLabel(lr.type || lr.medicalTypeName || lr.medicalType || ''); const date = lr.date || ''; const diagnosis = lr.diagnosis || ''; if (type || date || diagnosis) { @@ -139,10 +158,79 @@ function formatPatient(raw) { record, createTime: raw?.createTime || '', creator: raw?.creatorName || raw?.creator || '', - hospitalId: raw?.customerNumber || raw?.hospitalId || '', + hospitalId: customerNumber, + customerNumber, + customerProfileNo2, + customerProfileNo3, }; } +function normalizeText(value) { + return String(value || '').trim(); +} + +function normalizeDigits(value) { + const s = normalizeText(value); + return s.replace(/\D/g, ''); +} + +function isChinaMobile(value) { + const digits = normalizeDigits(value); + return /^1[3-9]\d{9}$/.test(digits); +} + +function isLikelyArchiveNo(value) { + const s = normalizeText(value); + if (!s) return false; + if (/[\u4e00-\u9fa5]/.test(s)) return false; // 中文一般是姓名 + if (isChinaMobile(s)) return false; + // 病案号一般为数字/字母组合(或纯数字) + return /^[0-9A-Za-z-]{3,}$/.test(s); +} + +function matchesAnyArchiveNo(patient, q) { + const needle = normalizeText(q).toLowerCase(); + if (!needle) return false; + const values = [ + patient?.customerNumber, + patient?.customerProfileNo2, + patient?.customerProfileNo3, + patient?.hospitalId, + ].map((v) => normalizeText(v).toLowerCase()).filter(Boolean); + + // 优先精确匹配 + if (values.some((v) => v === needle)) return true; + // 兜底:包含匹配(部分医院病案号前后可能带前缀/后缀) + return values.some((v) => v.includes(needle)); +} + +function matchesAnyMobile(patient, q) { + const needle = normalizeDigits(q); + if (!needle) return false; + const mobiles = [ + patient?.mobile, + ...(Array.isArray(patient?.mobiles) ? patient.mobiles : []), + patient?.phone, + patient?.phone1, + ].map(normalizeDigits).filter(Boolean); + return mobiles.some((m) => m === needle); +} + +async function fetchList(params) { + const res = await api('searchCorpCustomerForCaseList', params); + if (!res?.success) { + throw new Error(res?.message || '搜索失败'); + } + const payload = + res && typeof res === 'object' + ? res.data && typeof res.data === 'object' && !Array.isArray(res.data) + ? res.data + : res + : {}; + const list = Array.isArray(payload.list) ? payload.list : Array.isArray(payload.data) ? payload.data : []; + return list.map(formatPatient); +} + // Computed const searchResults = computed(() => { return searchResultsRaw.value || []; @@ -163,29 +251,58 @@ const doSearch = useDebounce(async () => { return; } + const seq = (searchSeq.value += 1); searching.value = true; - const res = await api('searchCorpCustomerForCaseList', { - corpId, - userId, - teamId, - name: q, - page: 1, - pageSize: 50, - }); - searching.value = false; + try { + if (isChinaMobile(q)) { + const digits = normalizeDigits(q); + const list = await fetchList({ + corpId, + userId, + teamId, + page: 1, + pageSize: 50, + mobile: digits, + }); + if (seq !== searchSeq.value) return; - if (!res?.success) { - toast(res?.message || '搜索失败'); - return; + // 后端为包含匹配,这里做一次精确过滤,避免“部分号段”带来误命中 + searchResultsRaw.value = list.filter((p) => matchesAnyMobile(p, digits)); + return; + } + + if (isLikelyArchiveNo(q)) { + const list = await fetchList({ + corpId, + userId, + teamId, + page: 1, + pageSize: 50, + archiveNo: q, + }); + if (seq !== searchSeq.value) return; + + // 兜底:后端字段不全时,仍然做一次本地匹配(包含 customerNumber/2/3) + searchResultsRaw.value = list.filter((p) => matchesAnyArchiveNo(p, q)); + return; + } + + const list = await fetchList({ + corpId, + userId, + teamId, + name: q, + page: 1, + pageSize: 50, + }); + if (seq !== searchSeq.value) return; + searchResultsRaw.value = list; + } catch (e) { + if (seq !== searchSeq.value) return; + toast(e?.message || '搜索失败'); + } finally { + if (seq === searchSeq.value) searching.value = false; } - const payload = - res && typeof res === 'object' - ? res.data && typeof res.data === 'object' && !Array.isArray(res.data) - ? res.data - : res - : {}; - const list = Array.isArray(payload.list) ? payload.list : Array.isArray(payload.data) ? payload.data : []; - searchResultsRaw.value = list.map(formatPatient); }, 600); const handleSearch = () => doSearch(); diff --git a/pages/home/case-home.vue b/pages/home/case-home.vue index 983638b..6febbee 100644 --- a/pages/home/case-home.vue +++ b/pages/home/case-home.vue @@ -130,6 +130,7 @@ import dayjs from 'dayjs'; import api from '@/utils/api'; import useAccountStore from '@/store/account'; +import useInfoCheck from '@/hooks/useInfoCheck'; import { confirm as uniConfirm, hideLoading, loading as showLoading, toast } from '@/utils/widget'; // State @@ -193,6 +194,7 @@ const currentTab = computed(() => tabs.value.find((t) => t.key === currentTabKey const accountStore = useAccountStore(); const { account, doctorInfo } = storeToRefs(accountStore); const { getDoctorInfo } = accountStore; +const { withInfo } = useInfoCheck(); const teamDisplay = computed(() => `${currentTeam.value?.name || ''}`); @@ -726,6 +728,10 @@ function normalizeMedicalType(raw) { const s = String(raw || '').trim(); if (!s) return ''; const lower = s.toLowerCase(); + // 常见后缀:xxxRecord(后端/历史数据可能返回此形式) + if (lower.endsWith('record') && s.length > 6) { + return normalizeMedicalType(s.slice(0, -6)); + } // 中文兜底(部分接口返回展示名) if (s.includes('门诊')) return 'outpatient'; if (s.includes('住院') || s.includes('入院')) return 'inhospital'; @@ -1211,15 +1217,14 @@ const goToSearch = () => { }); }; -const goToGroupManage = () => { +const goToGroupManage = withInfo(() => { if (checkBatchMode()) return; - if (!ensureUserInfoForFeature()) return; uni.navigateTo({ url: '/pages/case/group-manage' }); -}; +}); -const toggleBatchMode = () => { +const toggleBatchMode = withInfo(() => { if (isBatchMode.value) { // Already in batch mode, do nothing or prompt? // Prompt says "click Other operations... prompt please finish". @@ -1229,9 +1234,9 @@ const toggleBatchMode = () => { } isBatchMode.value = true; selectedItems.value = []; -}; +}); -const handleCreate = () => { +const handleCreate = withInfo(() => { if (checkBatchMode()) return; const rawMax = doctorInfo.value?.maxCustomerArchive; const hasMaxField = rawMax !== undefined && rawMax !== null && String(rawMax).trim() !== ''; @@ -1303,7 +1308,7 @@ const handleCreate = () => { } } }); -}; +}); // 新增流程:认证分支 const startVerifyFlow = () => {