From 87c852b6a9bd86874a1678d284e1562d01dc571b Mon Sep 17 00:00:00 2001 From: lik Date: Sun, 31 May 2026 19:43:16 +0800 Subject: [PATCH] tmp --- app.js | 34 ++- app.json | 3 +- pages/home/index.js | 9 +- pages/home/index.wxml | 6 +- pages/hospital/contact.wxml | 12 +- pages/hospital/contact.wxss | 48 ++-- pages/hospital/ranking.js | 192 +++++++++++++++ pages/hospital/ranking.json | 6 + pages/hospital/ranking.wxml | 104 +++++++++ pages/hospital/ranking.wxss | 450 ++++++++++++++++++++++++++++++++++++ utils/api.js | 4 +- 11 files changed, 824 insertions(+), 44 deletions(-) create mode 100644 pages/hospital/ranking.js create mode 100644 pages/hospital/ranking.json create mode 100644 pages/hospital/ranking.wxml create mode 100644 pages/hospital/ranking.wxss diff --git a/app.js b/app.js index 6875b6e..0e7e691 100644 --- a/app.js +++ b/app.js @@ -30,15 +30,35 @@ App({ }) }) - this.globalData.hospitalContactReady = new Promise((resolve) => { - API.resource.getHospitalContact().then((data) => { - this.globalData.hospitalContact = data.data.hospitalContact - resolve(data.data.hospitalContact) + this.globalData.hospitalInfoReady = new Promise((resolve) => { + API.resource.getHospitalInfo().then((data) => { + this.globalData.hospitalInfo = data.data.hospitalInfo + resolve(data.data.hospitalInfo) }).catch((err) => { - console.error('获取医院联系电话失败', err) + console.error('获取医院信息失败', err) resolve([]) }) }) + + this.globalData.hospitalRankingReady = new Promise((resolve) => { + API.resource.getHospitalRanking().then((data) => { + this.globalData.hospitalRanking = data.data.hospitalRanking + resolve(data.data.hospitalRanking) + }).catch((err) => { + console.error('获取医院排名失败', err) + resolve([]) + }) + }) + + this.globalData.departmentRankingsReady = new Promise((resolve) => { + API.resource.getDepartmentRankings().then((data) => { + this.globalData.departmentRankings = data.data.departmentRankings + resolve(data.data.departmentRankings) + }).catch((err) => { + console.error('获取科室排名失败', err) + resolve([]) + }) + }) }, onShow(options) { @@ -96,6 +116,8 @@ App({ chatSocket: null, services: [], agreement: null, - hospitalContact: [], + hospitalInfo: [], + hospitalRanking: [], + departmentRankings: [], } }) \ No newline at end of file diff --git a/app.json b/app.json index 72d6707..69a96c1 100644 --- a/app.json +++ b/app.json @@ -8,7 +8,8 @@ "pages/escort/agreement", "pages/mine/mine", "pages/mine/about", - "pages/hospital/contact" + "pages/hospital/contact", + "pages/hospital/ranking" ], "window": { "backgroundTextStyle": "light", diff --git a/pages/home/index.js b/pages/home/index.js index 7cec0a2..008e2d6 100644 --- a/pages/home/index.js +++ b/pages/home/index.js @@ -14,9 +14,9 @@ Page({ ], tools: [ { id: 1, name: '医院电话', icon: 'call', url: 'pages/hospital/contact', type: 'page' }, - { id: 2, name: '科室排行', icon: 'ai-coordinate-system', url: '', type: '' }, - { id: 3, name: '医保备案', icon: 'system-code', url: '', type: '' }, - { id: 4, name: '医疗影像', icon: 'film-1', url: '', type: '' } + { id: 2, name: '科室排行', icon: 'ai-coordinate-system', url: 'pages/hospital/ranking', type: 'page' }, + { id: 3, name: '医保备案', icon: 'system-code', url: '#小程序://异地备案/FfXUvTLmNptZx5E', type: 'wxapp' }, + { id: 4, name: '医疗影像', icon: 'film-1', url: 'https://www.114yygh.com/', type: 'website' } ] }, @@ -67,6 +67,9 @@ Page({ case 'website': wx.navigateTo({ url: '/pages/webview/index?url=' + encodeURIComponent(item.url) }); break; + case 'wxapp': + wx.navigateToMiniProgram({ shortLink: item.url, env: 'release' }) + break; default: wx.showToast({ title: '建设中, 请电话联系!', diff --git a/pages/home/index.wxml b/pages/home/index.wxml index 109d7e2..a1a2e06 100644 --- a/pages/home/index.wxml +++ b/pages/home/index.wxml @@ -49,7 +49,7 @@ - + {{ item.name }} @@ -67,7 +67,7 @@ - + {{ item.name }} @@ -85,7 +85,7 @@ - + {{ item.name }} diff --git a/pages/hospital/contact.wxml b/pages/hospital/contact.wxml index 2c3a680..73b1676 100644 --- a/pages/hospital/contact.wxml +++ b/pages/hospital/contact.wxml @@ -1,6 +1,6 @@ - 北京主要医院联系电话 + 主要医院联系电话 持续更新中, 仅供参考 @@ -8,14 +8,14 @@ 加载中... - - 暂无医院联系信息 + + 暂无医院信息 @@ -26,10 +26,10 @@ wx:for="{{item.phone}}" wx:for-item="phone" wx:key="*this" - data-phone="{{phone}}" + data-phone="{{phone.number}}" bindtap="onCallPhone" > - {{phone}} + {{phone.number}} diff --git a/pages/hospital/contact.wxss b/pages/hospital/contact.wxss index 53019ac..e52ddc5 100644 --- a/pages/hospital/contact.wxss +++ b/pages/hospital/contact.wxss @@ -39,36 +39,36 @@ page { /* Header区域 */ .header { background: #FFFFFF; - padding: 24rpx 32rpx 40rpx 32rpx; - margin-bottom: 20rpx; + padding: 16rpx 24rpx 20rpx 24rpx; + margin-bottom: 12rpx; } .title { display: block; - font-size: 40rpx; + font-size: 32rpx; font-weight: 700; color: #1F2937; } .subtitle { display: block; - font-size: 26rpx; + font-size: 24rpx; color: #9CA3AF; - margin-top: 12rpx; + margin-top: 6rpx; } /* 加载和空状态 */ .loading, .empty { text-align: center; - padding: 120rpx 32rpx; + padding: 80rpx 24rpx; color: #9CA3AF; - font-size: 28rpx; + font-size: 26rpx; } /* 列表区域 */ .list { - padding: 0 32rpx; + padding: 0 24rpx; } .item { @@ -76,11 +76,11 @@ page { align-items: center; justify-content: space-between; background: #FFFFFF; - border-radius: 24rpx; - padding: 32rpx; - margin-bottom: 20rpx; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06); - border: 2rpx solid #F0F0F0; + border-radius: 16rpx; + padding: 20rpx 24rpx; + margin-bottom: 12rpx; + box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.04); + border: 1rpx solid #F0F0F0; } .info { @@ -92,10 +92,10 @@ page { .name { font-size: 30rpx; - font-weight: 700; + font-weight: 600; color: #1F2937; - line-height: 1.4; - margin-bottom: 16rpx; + line-height: 1.3; + margin-bottom: 10rpx; word-wrap: break-word; } @@ -103,31 +103,31 @@ page { display: flex; flex-direction: row; flex-wrap: wrap; - gap: 12rpx; + gap: 8rpx; } .phone-wrap { display: flex; align-items: center; - gap: 12rpx; - padding: 12rpx 20rpx; + gap: 8rpx; + padding: 8rpx 14rpx; background: #F5F7F6; - border-radius: 12rpx; + border-radius: 8rpx; width: fit-content; } .phone { - font-size: 28rpx; + font-size: 26rpx; color: #2D6A4F; - line-height: 1.4; + line-height: 1.3; font-weight: 500; } .action { - margin-left: 24rpx; + margin-left: 16rpx; flex-shrink: 0; } .icon { - font-size: 40rpx; + font-size: 36rpx; } diff --git a/pages/hospital/ranking.js b/pages/hospital/ranking.js new file mode 100644 index 0000000..6d94656 --- /dev/null +++ b/pages/hospital/ranking.js @@ -0,0 +1,192 @@ +// pages/hospital/ranking.js +const app = getApp() + +Page({ + data: { + activeTab: 'overall', + searchKeyword: '', + selectedDepartment: '', + rankingYear: '', + rankingNote: '', + departmentList: [], + allHospitals: [], + filteredHospitals: [], + currentDepartmentRanking: { + top10: [], + nominated: [] + }, + hospitalRankingData: null, + departmentRankingsData: null + }, + + onLoad(options) { + this.loadData() + }, + + onShow() { + if (!this.data.hospitalRankingData || !this.data.departmentRankingsData) { + this.loadData() + } + }, + + async loadData() { + try { + const appData = app.globalData + + let hospitalRanking = appData.hospitalRanking + let departmentRankings = appData.departmentRankings + + if (!hospitalRanking) { + hospitalRanking = await appData.hospitalRankingReady + } + if (!departmentRankings) { + departmentRankings = await appData.departmentRankingsReady + } + + this.setData({ + hospitalRankingData: hospitalRanking, + departmentRankingsData: departmentRankings + }) + + this.processHospitalRanking(hospitalRanking) + this.processDepartmentRankings(departmentRankings) + } catch (err) { + console.error('加载排行榜数据失败', err) + wx.showToast({ + title: '数据加载失败', + icon: 'none' + }) + } + }, + + processHospitalRanking(data) { + if (!data || !data.rankings) return + + const gradeClassMap = { + 'A+++++': 'grade-a5', + 'A++++': 'grade-a4', + 'A+++': 'grade-a3', + 'A++': 'grade-a2', + 'A+': 'grade-a1' + } + + const hospitals = data.rankings.map(item => { + const allDeps = (item.depart || []) + .sort((a, b) => a.rank - b.rank) + return { + ...item, + gradeClass: gradeClassMap[item.grade] || 'grade-a1', + topDepartments: allDeps, + expanded: false + } + }) + + this.setData({ + rankingYear: data.year || '', + rankingNote: data.note || '', + allHospitals: hospitals, + filteredHospitals: hospitals + }) + }, + + processDepartmentRankings(data) { + if (!data || !data.departments) return + + const departments = Object.keys(data.departments) + const firstDept = departments[0] || '' + + this.setData({ + departmentList: departments, + selectedDepartment: firstDept + }) + + if (firstDept) { + this.updateCurrentDepartmentRanking(firstDept) + } + }, + + updateCurrentDepartmentRanking(deptName) { + const data = this.data.departmentRankingsData + if (!data || !data.departments || !data.departments[deptName]) { + this.setData({ + currentDepartmentRanking: { top10: [], nominated: [] } + }) + return + } + + const deptData = data.departments[deptName] + this.setData({ + currentDepartmentRanking: { + top10: deptData.top10 || [], + nominated: deptData.nominated || [] + } + }) + }, + + switchTab(e) { + const tab = e.currentTarget.dataset.tab + if (tab === this.data.activeTab) return + this.setData({ activeTab: tab }) + }, + + selectDepartment(e) { + const dept = e.currentTarget.dataset.dept + this.setData({ selectedDepartment: dept }) + this.updateCurrentDepartmentRanking(dept) + }, + + onSearchInput(e) { + const keyword = e.detail.value + this.setData({ searchKeyword: keyword }) + this.filterHospitals(keyword) + }, + + onSearch(e) { + const keyword = e.detail.value + this.filterHospitals(keyword) + }, + + clearSearch() { + this.setData({ searchKeyword: '' }) + this.filterHospitals('') + }, + + filterHospitals(keyword) { + let result = this.data.allHospitals + + if (keyword && keyword.trim()) { + const lowerKeyword = keyword.trim().toLowerCase() + result = result.filter(item => { + const nameMatch = item.name && item.name.toLowerCase().includes(lowerKeyword) + const deptMatch = item.depart && item.depart.some(d => d.name && d.name.toLowerCase().includes(lowerKeyword)) + return nameMatch || deptMatch + }) + } + + this.setData({ filteredHospitals: result }) + }, + + toggleHospital(e) { + const name = e.currentTarget.dataset.name + const hospitals = this.data.filteredHospitals.map(item => { + if (item.name === name) { + return { ...item, expanded: !item.expanded } + } + return item + }) + this.setData({ filteredHospitals: hospitals }) + }, + + onPullDownRefresh() { + this.loadData().finally(() => { + wx.stopPullDownRefresh() + }) + }, + + onShareAppMessage() { + return { + title: '复旦中国医院排行榜', + path: '/pages/hospital/ranking' + } + } +}) diff --git a/pages/hospital/ranking.json b/pages/hospital/ranking.json new file mode 100644 index 0000000..45d0ecc --- /dev/null +++ b/pages/hospital/ranking.json @@ -0,0 +1,6 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true, + "backgroundTextStyle": "dark", + "navigationBarTitleText": "医院排行榜" +} diff --git a/pages/hospital/ranking.wxml b/pages/hospital/ranking.wxml new file mode 100644 index 0000000..b32064e --- /dev/null +++ b/pages/hospital/ranking.wxml @@ -0,0 +1,104 @@ + + + + + {{rankingYear}}复旦中国医院排行榜 + {{rankingNote}} + + + + + + 综合榜 + + + + 专科榜 + + + + + + + + + + + {{item.grade}} + + + + {{item.name}} + + {{dep.name}} + + + + + + + + + 专科排名详情 + + + {{dep.name}} + + 第{{dep.rank}}名 + {{dep.score}}分 + + + + + + + + + + + + + + + {{item}} + + + + + + + + {{selectedDepartment}} + {{rankingYear}}年度专科声誉排名 + + + + + + + {{item.rank}} + {{item.rank}} + + + {{item.name}} + {{item.score}}分 + + + + + + + 获提名医院 + + {{item}} + + + + + + + + + 未找到匹配的医院 + + diff --git a/pages/hospital/ranking.wxss b/pages/hospital/ranking.wxss new file mode 100644 index 0000000..8ff8551 --- /dev/null +++ b/pages/hospital/ranking.wxss @@ -0,0 +1,450 @@ +/* pages/hospital/ranking.wxss */ +page { + background: linear-gradient(180deg, #E8F5E9 0%, #F1F8F2 30%, #F5FAF6 100%); + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; +} + +.container { + min-height: 100vh; + padding-bottom: 60rpx; +} + +/* ========== 顶部标题 ========== */ +.header { + padding: 32rpx 32rpx 16rpx 32rpx; + text-align: center; +} + +.header-title { + font-size: 36rpx; + font-weight: 700; + color: #1F2937; + display: block; +} + +.header-note { + font-size: 24rpx; + color: #9CA3AF; + margin-top: 8rpx; + display: block; +} + +/* ========== 搜索栏 ========== */ +.search-bar { + padding: 16rpx 32rpx; +} + +.search-input-wrap { + display: flex; + align-items: center; + background: #FFFFFF; + border-radius: 40rpx; + padding: 16rpx 24rpx; + box-shadow: 0 2rpx 12rpx rgba(45, 106, 79, 0.08); +} + +.search-input { + flex: 1; + font-size: 28rpx; + color: #1F2937; + margin-left: 16rpx; + margin-right: 16rpx; +} + +.search-input::placeholder { + color: #9CA3AF; +} + +.search-clear { + padding: 4rpx; +} + +/* ========== Tab 切换 ========== */ +.tab-bar { + display: flex; + justify-content: center; + padding: 0 32rpx; + margin-top: 8rpx; + border-bottom: 1rpx solid rgba(45, 106, 79, 0.08); +} + +.tab-item { + position: relative; + padding: 24rpx 48rpx; + cursor: pointer; +} + +.tab-text { + font-size: 30rpx; + color: #6B7280; + font-weight: 500; +} + +.tab-item.active .tab-text { + color: #2D6A4F; + font-weight: 700; +} + +.tab-line { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: 48rpx; + height: 4rpx; + background: linear-gradient(90deg, #2D6A4F 0%, #40916C 100%); + border-radius: 2rpx; +} + +/* ========== 综合榜内容 ========== */ +.content { + padding: 0 24rpx; +} + +/* 医院列表 */ +.hospital-list { + margin-top: 16rpx; +} + +.hospital-card { + position: relative; + background: #FFFFFF; + border-radius: 20rpx; + margin-bottom: 16rpx; + box-shadow: 0 4rpx 16rpx rgba(45, 106, 79, 0.08); + overflow: hidden; +} + +.hospital-rank-badge { + position: absolute; + top: 0; + right: 0; + z-index: 10; +} + +.hospital-rank-badge .rank-grade { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8rpx 16rpx; + border-radius: 0 20rpx 0 12rpx; + font-size: 22rpx; + font-weight: 700; + min-width: 80rpx; + text-align: center; +} + +.hospital-header { + display: flex; + align-items: center; + padding: 24rpx 100rpx 24rpx 24rpx; +} + +.rank-grade { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8rpx 16rpx; + border-radius: 12rpx; + font-size: 24rpx; + font-weight: 700; + min-width: 80rpx; + text-align: center; +} + +.rank-grade.grade-a5 { + background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%); + color: #92400E; +} + +.rank-grade.grade-a4 { + background: linear-gradient(135deg, #DBEAFE 0%, #BFDBFE 100%); + color: #1E40AF; +} + +.rank-grade.grade-a3 { + background: linear-gradient(135deg, #D1FAE5 0%, #A7F3D0 100%); + color: #065F46; +} + +.rank-grade.grade-a2 { + background: linear-gradient(135deg, #E0E7FF 0%, #C7D2FE 100%); + color: #3730A3; +} + +.rank-grade.grade-a1 { + background: linear-gradient(135deg, #F3E8FF 0%, #E9D5FF 100%); + color: #6B21A8; +} + +.hospital-info { + flex: 1; + min-width: 0; +} + +.hospital-name { + font-size: 32rpx; + font-weight: 600; + color: #1F2937; + display: block; +} + +.hospital-tags { + display: flex; + flex-wrap: wrap; + margin-top: 8rpx; + gap: 8rpx; +} + +.tag { + font-size: 24rpx; + color: #2D6A4F; + background: rgba(45, 106, 79, 0.08); + padding: 4rpx 12rpx; + border-radius: 8rpx; +} + +.hospital-arrow { + margin-left: 16rpx; + transition: transform 0.3s; +} + +.arrow-up { + transform: rotate(180deg); +} + +/* 医院详情展开 */ +.hospital-detail { + padding: 0 24rpx 24rpx 24rpx; + border-top: 1rpx solid rgba(45, 106, 79, 0.06); +} + +.detail-title { + font-size: 26rpx; + font-weight: 600; + color: #374151; + padding: 16rpx 0 12rpx 0; +} + +.dept-grid { + display: flex; + flex-wrap: wrap; + gap: 12rpx; +} + +.dept-item { + background: #F9FAFB; + border-radius: 12rpx; + padding: 12rpx 16rpx; + flex: 1; + min-width: 200rpx; + max-width: calc(50% - 6rpx); +} + +.dept-name { + font-size: 24rpx; + color: #4B5563; + display: block; +} + +.dept-rank { + display: flex; + justify-content: space-between; + margin-top: 4rpx; +} + +.rank-num { + font-size: 22rpx; + color: #2D6A4F; + font-weight: 600; +} + +.rank-score { + font-size: 22rpx; + color: #9CA3AF; +} + +/* ========== 专科榜内容 ========== */ +.content:has(.dept-filter) { + display: flex; + padding: 0; +} + +.dept-filter { + width: 200rpx; + background: #FFFFFF; + border-right: 1rpx solid rgba(45, 106, 79, 0.06); +} + +.dept-sidebar { + padding: 8rpx 0; +} + +.sidebar-item { + padding: 24rpx 16rpx; + text-align: center; + border-left: 4rpx solid transparent; + transition: all 0.2s; +} + +.sidebar-item.active { + background: #F0FDF4; + border-left-color: #2D6A4F; +} + +.sidebar-text { + font-size: 26rpx; + color: #4B5563; +} + +.sidebar-item.active .sidebar-text { + color: #2D6A4F; + font-weight: 600; +} + +.dept-ranking-content { + flex: 1; + padding: 16rpx 24rpx 24rpx 24rpx; + overflow-y: auto; +} + +.dept-ranking-header { + margin-bottom: 16rpx; +} + +.dept-ranking-title { + font-size: 32rpx; + font-weight: 700; + color: #1F2937; + display: block; +} + +.dept-ranking-subtitle { + font-size: 24rpx; + color: #9CA3AF; + margin-top: 4rpx; + display: block; +} + +/* Top10 列表 */ +.top10-list { + background: #FFFFFF; + border-radius: 20rpx; + box-shadow: 0 4rpx 16rpx rgba(45, 106, 79, 0.08); + overflow: hidden; +} + +.top10-item { + display: flex; + align-items: center; + padding: 20rpx 24rpx; + border-bottom: 1rpx solid rgba(45, 106, 79, 0.04); +} + +.top10-item:last-child { + border-bottom: none; +} + +.top10-item.top3 { + background: linear-gradient(90deg, rgba(254, 243, 199, 0.3) 0%, rgba(255, 255, 255, 0) 100%); +} + +.top10-rank { + margin-right: 20rpx; + min-width: 56rpx; + text-align: center; +} + +.rank-badge { + display: inline-flex; + align-items: center; + justify-content: center; + width: 48rpx; + height: 48rpx; + border-radius: 50%; + font-size: 26rpx; + font-weight: 700; + color: #FFFFFF; +} + +.top10-item:nth-child(1) .rank-badge { + background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%); +} + +.top10-item:nth-child(2) .rank-badge { + background: linear-gradient(135deg, #9CA3AF 0%, #6B7280 100%); +} + +.top10-item:nth-child(3) .rank-badge { + background: linear-gradient(135deg, #B45309 0%, #92400E 100%); +} + +.rank-num { + font-size: 28rpx; + font-weight: 600; + color: #6B7280; +} + +.top10-info { + flex: 1; + min-width: 0; +} + +.top10-name { + font-size: 28rpx; + color: #1F2937; + font-weight: 500; + display: block; +} + +.top10-score { + font-size: 24rpx; + color: #9CA3AF; + margin-top: 4rpx; + display: block; +} + +/* 获提名医院 */ +.nominated-section { + margin-top: 24rpx; + background: #FFFFFF; + border-radius: 20rpx; + padding: 20rpx 24rpx; + box-shadow: 0 4rpx 16rpx rgba(45, 106, 79, 0.08); +} + +.nominated-title { + font-size: 26rpx; + font-weight: 600; + color: #374151; + margin-bottom: 12rpx; +} + +.nominated-list { + display: flex; + flex-wrap: wrap; + gap: 12rpx; +} + +.nominated-item { + font-size: 24rpx; + color: #4B5563; + background: #F9FAFB; + padding: 8rpx 16rpx; + border-radius: 8rpx; +} + +/* ========== 空状态 ========== */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 120rpx 32rpx; +} + +.empty-text { + font-size: 28rpx; + color: #9CA3AF; + margin-top: 24rpx; +} diff --git a/utils/api.js b/utils/api.js index 61774df..2679c08 100644 --- a/utils/api.js +++ b/utils/api.js @@ -20,7 +20,9 @@ const API = { resource: { getServices: (params) => request.get('/health/service', params), getAgreement: (params) => request.get('/health/agreement', params), - getHospitalContact: (params) => request.get('/health/hospital-contact', params), + getHospitalInfo: (params) => request.get('/health/hospital-info', params), + getHospitalRanking: (params) => request.get('/health/hospital-ranking', params), + getDepartmentRankings: (params) => request.get('/health/department-rankings', params), }, ai: {