微信小程序「专业查询」功能重构全记录
从一次搜索到完整展开交互,从 500 条数据截断到 180 万全量索引——乐道志愿助理专业查询模块的蜕变过程。
一、起点:一个简单的搜索框
改版前的专业查询页只有基本功能:输入专业名 → 搜到院校列表 → 展开看该院校匹配的几个专业和分数范围。交互到此为止。
问题很明显: - 看不到三年完整数据 — 只能看分数范围 - 看不到院校其他专业 — 只显示搜到的那个 - 看不到专业详情 — 没有概述、就业方向 - 没有导航出口 — 搜完就困住了
二、新设计:一站式院校卡片
目标:用户搜一个专业 → 看到招生院校 → 点开展示全部。
搜索"法学"
→ 院校卡片列表(重庆地区招生院校 × 200+)
→ 展开"西南政法大学":
├─ 🏫 院校简介(可折叠)
├─ ⭐ 法学 ← 搜索专业排第一,高亮
│ ├─ 2023: 559分 | 2024: 587分 | 2025: 582分
│ └─ [专业详情 ▸] 概述 / 男女比例 / 就业方向
├─ 知识产权
│ ├─ 三年分数
│ └─ [专业详情 ▸]
└─ 刑事科学技术 ...
关键技术决策:展开时懒加载,不预取全部数据。点院校才调云函数拉取数据,同一次搜索内缓存。
三、踩坑:西南政法大学怎么搜不到?
用户选了重庆生源地,搜"法学",西南政法大学竟然不在结果里。这是西南政法啊——中国法学的招牌院校。
排查过程
第一层:年份过滤。 前端去掉了年份选择器,queryMajors 默认只查 2025 年。但西南政法每年都有法学——不是这个问题。
第二层:省份匹配。 数据里的省份是"重庆市"(带市),用户选的是"重庆"(不带市)。云函数做的是 === 严格比较。
// ❌ 旧代码
if (entry.p !== province.trim()) continue
// ✅ 修复后
const qProv = province.trim().replace(/市$/, '')
const eProv = (entry.p || '').replace(/市$/, '')
if (qProv !== eProv) continue
修完后多了 4 所学校,但西南政法还是没出现。
第三层:数据截断。 查原始 admission 数据,西南政法 + 法学 + 重庆的记录确实存在(559 分)。但 build_major_index.py 里有一行:
MAX_PER_MAJOR = 500 # 每个专业只保留前 500 条
"法学"是全国最热门的专业之一,全国数百所法学院校 × 30 省份 × 3 年 = 数千条记录。559 分排不进前 500,被直接截掉了。
修复:直接取消截断限制。 180 万条记录全部保留。
四、踩坑:60 秒超时
索引从 48 个 chunk 暴涨到 151 个,原来一次性灌入的方案在 60 秒内跑不完。
修复:链式分批。 每次只处理 15 个 chunk,完成后 fire-and-forget 调用下一步。151 个文件分 11 步自动串行跑完。
// 每步结尾
cloud.callFunction({
name: 'seedMajorIndex',
data: { step: step + 1 }
}).catch(e => console.error('链式调用失败:', e.message))
五、200+ 所学校怎么办?
法学搜出 200+ 所学校,用户需要快速定位。加了两个筛选:
- 院校名称搜索:客户端即时过滤,输入"西南"马上只显示相关学校
- 院校所在省份:选"重庆"只显示重庆的大学,云函数端过滤
后者在 queryMajors 里先查 universities 拿到该省全部院校名,再与专业索引结果取交集。
六、其他细节改进
| 问题 | 解决 |
|---|---|
| 展开院校后滚动位置不对 | _scrollToExpandedCard() 自动滚到卡片顶部 |
| 返回直接退出页面 | onBackPress 拦截,展开时先折叠再退出 |
| 页面销毁后仍在处理数据 | _aborted 标记 + 所有异步回调检查 |
-- 无说明 |
竖排注释"表示该校当年未开设此专业" |
| 在校人数缺少前缀 | 补上"在校生 X 人" |
七、最终架构
pages/major/major.js ───── 搜索入口
├─ queryMajors (云函数) ── major_index 倒排索引
│ ├─ RegExp 匹配专业名
│ ├─ 省份/年份/科类/院校省份 过滤
│ └─ 返回按学校分组的结果
│
└─ 展开院校:
├─ getSchoolAllMajors (云函数)
│ ├─ universities → 院校简介
│ ├─ admission → 全部专业 + 三年分数
│ └─ major_details → 专业百科
│
└─ 懒加载专业详情:
└─ getMajorDetails (已有云函数)
八、改动的文件清单
| 文件 | 改动 |
|---|---|
scripts/build_major_index.py |
取消 500 条截断 |
cloudfunctions/seedMajorIndex/index.js |
链式分批灌入 |
cloudfunctions/queryMajors/index.js |
省份兼容 + year:all + 院校省份筛选 |
cloudfunctions/getSchoolAllMajors/* |
新建,展开院校数据 |
pages/major/major.js |
展开逻辑 + 返回拦截 + 院校筛选 + 退出清理 |
pages/major/major.wxml |
新展开视图 + 院校筛选栏 |
pages/major/major.wxss |
展开视图全套样式 |
九、部署清单
- 部署
seedMajorIndex(已跑完,数据已在库) - 部署
queryMajors - 部署
getSchoolAllMajors(首次)
三个云函数部署完即可上线。
2026-06-25 · 乐道志愿助理 · Claude Code