从零搭建 AIU 协会招新小程序:微信云开发 + Dify AI 实战
技术#微信小程序#云开发

从零搭建 AIU 协会招新小程序:微信云开发 + Dify AI 实战

>
~5 min read

#从零搭建 AIU 协会招新小程序:微信云开发 + Dify AI 实战

本文记录了为 AIU(人工智能联盟)协会开发招新报名小程序的完整过程,涵盖技术选型、架构设计、核心功能实现和踩坑经验。

##项目背景

每年开学季,学生社团都需要处理大量招新报名工作——收集信息、筛选面试、通知结果。传统做法是纸质表格 +微信群 +Excel 手动管理,效率低且容易出错。

作为第六届 AIU 创智部部长,我决定用技术解决这个问题:开发一个微信小程序,将整个招新流程线上化。学生在线报名,管理员在线审核,录取结果实时可查,还顺手接入了一个 AI 助手来回答新生关于协会的常见问题。

##技术选型

维度方案理由
前端框架微信小程序原生无需额外学习成本,性能最优
后端服务微信云开发免服务器运维,天然集成微信生态
数据库云数据库(文档型)无需建表,灵活应对字段变化
文件存储云存储头像图片直传,无需搭建 OSS
AI 能力Dify 聊天机器人低代码搭建知识库,SSE 流式响应

这套方案的核心理念是:用最少的运维成本,交付最多的功能。云开发免去了服务器采购、域名备案、SSL 证书等繁琐步骤,让我能把精力集中在业务逻辑上。

##架构设计

┌─────────────────────────────────────────────┐ │ 微信小程序(前端) │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────────┐ │ │ │了解协会│ │ 在线 │ │ 录取 │ │ AI 助手 │ │ │ │ │ │ 报名 │ │ 查询 │ │(Dify) │ │ │ └──────┘ └──────┘ └──────┘ └──────────┘ │ │ │ │ │ ┌───────┴───────┐ │ │ │ 管理员后台 │ │ │ │ (隐藏入口) │ │ │ └───────────────┘ │ └────────────────────┬────────────────────────┘ │ 云调用 / HTTP ┌────────────────────┴────────────────────────┐ │ 云函数(统一入口) │ │ getOpenId · signupSubmit · signupGetStatus │ │ adminUpsertAdmission · difyChat │ └──────┬─────────────┬───────────────┬────────┘ │ │ │ ┌────▼────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ 云数据库 │ │ 云存储 │ │ Dify API │ │ signup │ │ 头像图片 │ │ 聊天机器人 │ │ admissions│ │ │ │ │ └─────────┘ └───────────┘ └───────────┘ click to copy

所有云函数走 quickstartFunctionsclick to copy 统一入口,通过 actionclick to copy 字段路由到不同处理逻辑。这样做的好处是只部署一个云函数,减少冷启动开销。

##核心功能实现

###1. 报名系统:多页表单 + 草稿自动保存

报名表单字段较多(基本信息、学业信息、志愿选择、个人材料),全部塞在一个页面体验很差。我采用了左右滑动分页的方式:

第1页:姓名、手机、微信、出生日期、性别、政治面貌 第2页:学院、年级、专业班级 第3页:第一志愿、第二志愿、是否服从调剂、个人简介、头像 click to copy

草稿自动保存是刚需——用户填到一半退出小程序,回来数据不能丢。实现很简单,每次字段变化都写入本地 Storage:

>hljs javascript.0 lines
// 表单数据变化时自动保存草稿
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(有则更新,无则新增),防止重复报名:

>hljs javascript.0 lines
// 云函数端:基于 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. 录取查询:三阶段进度条

录取状态分三个阶段:未报名 → 面试中 → 已录取/已拒绝。前端用进度条直观展示:

┌──────────┐ ┌──────────┐ ┌──────────┐ │ 未报名 │───▶│ 面试中 │───▶│ 已录取 │ │ (灰色) │ │ (蓝色) │ │ (绿色) │ └──────────┘ └──────────┘ └──────────┘ 或 ┌──────────┐ │ 已拒绝 │ │ (红色) │ └──────────┘ click to copy

查询逻辑很简单:根据用户 openid 去 signupclick to copyadmissionsclick to copy 两个集合联合查询,返回最新状态。

###3. AI 助手:Dify 流式对话

这是整个项目最有意思的部分。通过 Dify 平台搭建了一个协会知识库机器人,新生可以直接问"协会有哪些部门"、"面试流程是什么"之类的问题。

小程序端通过云函数代理调用 Dify API,实现 SSE 流式响应:

>hljs javascript.0 lines
// 云函数端:代理 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-viewclick to copy 组件实现消息列表自动滚动到底部,支持多轮对话,聊天记录缓存到本地。

###4. 管理员后台:隐藏入口设计

管理后台不适合暴露给普通用户,但又需要方便管理员访问。我设计了一个小彩蛋:

>hljs javascript.0 lines
// 在 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 认证) click to copy

这样官网和小程序共享同一套数据,学生通过任一渠道报名都能统一管理。

##踩坑记录

###云函数冷启动

云函数首次调用有明显的冷启动延迟(1-3秒)。解决方案是在用户进入小程序时预调用一次 getOpenIdclick to copy,把云函数"热"起来,后续操作就不会卡了。

###小程序域名白名单

Dify API 域名 api.dify.aiclick to copy 需要在微信小程序后台的"服务器域名"中添加为合法域名,否则正式版无法请求。开发阶段可以在开发者工具中勾选"不校验合法域名"来绕过。

###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 click to copy

##后续规划

  1. 完善管理员界面:增加批量操作、数据导出等功能
  2. 内嵌协会官网:等官网升级 HTTPS 后通过 web-view 组件嵌入
  3. 企业认证上线:目前小程序还在体验版阶段,完成企业认证后才能正式发布

##总结

这个项目让我深刻体会到云开发对个人开发者和小团队的效率提升——不用折腾服务器,不用操心部署,写完代码直接上传就能用。Dify 的接入也让协会咨询这个痛点变得简单,不用人工重复回答相同的问题。

如果你也在做类似的社团/组织管理系统,微信云开发 + Dify 的组合值得一试。

// EOF

本文为项目实战记录,源码仅供 AIU 协会内部使用。如有技术问题欢迎交流。

> tags
#微信小程序#云开发#Dify AI#全栈开发#项目实战
> related_posts
>cd /blog_