从零搭建招新小程序:微信云开发 + Dify AI 实战
从零搭建招新小程序:微信云开发 + Dify AI 实战
本文记录了为 AIU(人工智能联盟)协会开发招新报名小程序的完整过程,涵盖技术选型、架构设计、核心功能实现和踩坑经验。
项目背景
每年开学季,学生社团都需要处理大量招新报名工作——收集信息、筛选面试、通知结果。传统做法是纸质表格 +微信群 +Excel 手动管理,效率低且容易出错。
作为某组织技术部部长,我决定用技术解决这个问题:开发一个微信小程序,将整个招新流程线上化。学生在线报名,管理员在线审核,录取结果实时可查,还顺手接入了一个 AI 助手来回答新生关于协会的常见问题。
源码:https://github.com/Linmoqian/AIU_Registration_Mini_Program
技术选型
| 维度 | 方案 | 理由 |
|---|---|---|
| 前端框架 | 微信小程序原生 | 无需额外学习成本,性能最优 |
| 后端服务 | 微信云开发 | 免服务器运维,天然集成微信生态 |
| 数据库 | 云数据库(文档型) | 无需建表,灵活应对字段变化 |
| 文件存储 | 云存储 | 头像图片直传,无需搭建 OSS |
| AI 能力 | Dify 聊天机器人 | 低代码搭建知识库,SSE 流式响应 |
这套方案的核心理念是:用最少的运维成本,交付最多的功能。云开发免去了服务器采购、域名备案、SSL 证书等繁琐步骤,让我能把精力集中在业务逻辑上。
架构设计
┌─────────────────────────────────────────────┐
│ 微信小程序(前端) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────────┐ │
│ │了解协会│ │ 在线 │ │ 录取 │ │ AI 助手 │ │
│ │ │ │ 报名 │ │ 查询 │ │(Dify) │ │
│ └──────┘ └──────┘ └──────┘ └──────────┘ │
│ │ │
│ ┌───────┴───────┐ │
│ │ 管理员后台 │ │
│ │ (隐藏入口) │ │
│ └───────────────┘ │
└────────────────────┬────────────────────────┘
│ 云调用 / HTTP
┌────────────────────┴────────────────────────┐
│ 云函数(统一入口) │
│ getOpenId · signupSubmit · signupGetStatus │
│ adminUpsertAdmission · difyChat │
└──────┬─────────────┬───────────────┬────────┘
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ 云数据库 │ │ 云存储 │ │ Dify API │
│ signup │ │ 头像图片 │ │ 聊天机器人 │
│ admissions│ │ │ │ │
└─────────┘ └───────────┘ └───────────┘
所有云函数走 quickstartFunctions 统一入口,通过 action 字段路由到不同处理逻辑。这样做的好处是只部署一个云函数,减少冷启动开销。
核心功能实现
1. 报名系统:多页表单 + 草稿自动保存

报名表单字段较多(基本信息、学业信息、志愿选择、个人材料),全部塞在一个页面体验很差。我采用了左右滑动分页的方式:
第1页:姓名、手机、微信、出生日期、性别、政治面貌
第2页:学院、年级、专业班级
第3页:第一志愿、第二志愿、是否服从调剂、个人简介、头像
草稿自动保存是刚需——用户填到一半退出小程序,回来数据不能丢。实现很简单,每次字段变化都写入本地 Storage:
// 表单数据变化时自动保存草稿
onFieldChange(e) {
const { field, value } = e.detail;
this.setData({ [`formData.${field}`]: value });
wx.setStorageSync('signupDraft', this.data.formData);
},
// 页面加载时恢复草稿
onLoad() {
const draft = wx.getStorageSync('signupDraft');
if (draft) {
this.setData({ formData: draft });
}
}
提交时通过 openid 做 upsert(有则更新,无则新增),防止重复报名:
// 云函数端:基于 openid 的 upsert
const db = cloud.database();
const existing = await db.collection('signup')
.where({ openid })
.get();
if (existing.data.length > 0) {
await db.collection('signup')
.doc(existing.data[0]._id)
.update({ data: formData });
} else {
await db.collection('signup')
.add({ data: { ...formData, openid } });
}
2. 录取查询:三阶段进度条
录取状态分三个阶段:未报名 → 面试中 → 已录取/已拒绝。前端用进度条直观展示:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 未报名 │───▶│ 面试中 │───▶│ 已录取 │
│ (灰色) │ │ (蓝色) │ │ (绿色) │
└──────────┘ └──────────┘ └──────────┘
或
┌──────────┐
│ 已拒绝 │
│ (红色) │
└──────────┘
查询逻辑很简单:根据用户 openid 去 signup 和 admissions 两个集合联合查询,返回最新状态。
3. AI 助手:Dify 流式对话
这是整个项目最有意思的部分。通过 Dify 平台搭建了一个协会知识库机器人,新生可以直接问"协会有哪些部门"、"面试流程是什么"之类的问题。

小程序端通过云函数代理调用 Dify API,实现 SSE 流式响应:
// 云函数端:代理 Dify 聊天请求
const axios = require('axios');
exports.difyChat = async (event) => {
const { message, conversationId } = event;
const response = await axios({
method: 'post',
url: `${DIFY_API_BASE}/v1/chat-messages`,
headers: {
'Authorization': `Bearer ${DIFY_API_KEY}`,
'Content-Type': 'application/json',
},
data: {
inputs: {},
query: message,
response_mode: 'blocking',
conversation_id: conversationId || undefined,
user: event.openid,
},
});
return response.data;
};
聊天界面用了 scroll-view 组件实现消息列表自动滚动到底部,支持多轮对话,聊天记录缓存到本地。
4. 管理员后台:隐藏入口设计
管理后台不适合暴露给普通用户,但又需要方便管理员访问。我设计了一个小彩蛋:
// 在 Logo 上监听连续点击
onLogoTap() {
this.tapCount = (this.tapCount || 0) + 1;
if (this.tapCount >= 8) {
this.tapCount = 0;
wx.navigateTo({ url: '/pages/admin/login' });
}
// 3秒内未达到8次则重置
clearTimeout(this.tapTimer);
this.tapTimer = setTimeout(() => {
this.tapCount = 0;
}, 3000);
}
管理员登录后可以:
- 查看所有报名学生列表
- 按部门/状态筛选
- 按姓名/手机号搜索
- 查看学生详情(含头像)
- 执行录取/拒绝操作并指定录取部门
5. HTTP 接口:打通外部系统
除了小程序端,还暴露了 HTTP 接口供协会官网调用:
POST /api/signup → 网站报名(手机号去重)
GET /api/status?mobile= → 查询录取状态
POST /api/admissions → 录取操作(Token 认证)
这样官网和小程序共享同一套数据,学生通过任一渠道报名都能统一管理。
踩坑记录
云函数冷启动
云函数首次调用有明显的冷启动延迟(1-3秒)。解决方案是在用户进入小程序时预调用一次 getOpenId,把云函数"热"起来,后续操作就不会卡了。
小程序域名白名单
Dify API 域名 api.dify.ai 需要在微信小程序后台的"服务器域名"中添加为合法域名,否则正式版无法请求。开发阶段可以在开发者工具中勾选"不校验合法域名"来绕过。
openid 的安全性
openid 是用户的唯一标识,但不能直接暴露给前端做权限判断。管理员的 openid 列表存储在云函数环境变量中,前端只知道"我是谁",后端才决定"我能做什么"。
项目结构
AIU报名小程序/
├── cloudfunctions/
│ └── quickstartFunctions/ # 统一云函数入口
│ ├── index.js # 主逻辑(路由到不同 action)
│ └── package.json
├── miniprogram/
│ ├── app.js # 全局配置(云环境、Dify Key)
│ ├── app.json # 路由、TabBar
│ ├── pages/
│ │ ├── about/ # 了解协会(首页)
│ │ ├── apply/ # 在线报名(多页表单)
│ │ ├── query/ # 录取查询(进度条)
│ │ ├── chat/ # AI 助手(Dify)
│ │ └── admin/ # 管理员后台
│ │ ├── login # 密码登录
│ │ ├── index # 学生列表(筛选/搜索)
│ │ └── detail # 学生详情 + 录取操作
│ └── images/
└── project.config.json
后续规划
- 完善管理员界面:增加批量操作、数据导出等功能
- 内嵌协会官网:等官网升级 HTTPS 后通过 web-view 组件嵌入
- 企业认证上线:目前小程序还在体验版阶段,完成企业认证后才能正式发布
总结
这个项目让我深刻体会到云开发对个人开发者和小团队的效率提升——不用折腾服务器,不用操心部署,写完代码直接上传就能用。Dify 的接入也让协会咨询这个痛点变得简单,不用人工重复回答相同的问题。
如果你也在做类似的社团/组织管理系统,微信云开发 + Dify 的组合值得一试。
本文为项目实战记录,源码仅供 AIU 协会内部使用。如有技术问题欢迎交流。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)