# WXAPP 云函数接口迁移矩阵 ## 口径 - 基线来自旧 uni-app 源码静态扫描生成的 `SOURCE_API_ACTIONS`,共 91 个唯一 action。 - 统一新入口为 `POST /api/functions/xiaoshu/app/gateway`。 - 请求体统一使用 `{ "token": "", "params": { "action": "...", ... } }`;执行器会占用顶层 `id`,业务参数不得放在顶层。公开接口可省略 `token`,但仍必须保留 `params`。 - 源码清单内已有云函数映射 28 个,另有 63 个以 HTTP 501 和 `migration_blocked: <原因>` 显式拒绝。动态调用的兼容 action `content_add_zt` 也已映射;`product_add`、`product_upd` 仍为兼容阻塞项,因此线上共 29 个已实现、65 个阻塞项。矩阵不存在未覆盖的源码 action。 - “已映射”表示已有云函数代码与权限边界;完成 H5 切换前仍需逐页响应字段回归。 ## 已映射 action | 领域 | action | |---|---| | 版本 | `app_update` | | 内容 | `content_add`, `content_get`, `content_list`, `content_list_llk`, `content_update`, `content_uphis`, `node_get`, `node_list` | | 账号/团队 | `user_get`, `user_info_name`, `user_list`, `user_dept`, `user_login_passwd`, `user_register`, `user_update`, `e_user_list` | | 学习/预约 | `content_add_zt`, `e_add_words`, `e_ck_list`, `e_get_21list`, `e_order_detail`, `e_order_tongji`, `e_order_update_v2`, `e_record_detail`, `e_words_list`, `stu_record_update_v2`, `user_point_list` | | 反馈 | `guestbook_add` | 已实测 `content_list` 在公司帐套下返回 92,435 条,`modelId=56` 返回 108 条。读取用 Psql 并强制 `company=7pIbDBJmKx`,所有客户端输入均使用参数化查询。 `content_list` 已按 `CommonModel.itemId = addon.id` 重建下列规范化联表: | ModelID | 旧表 | 规范化类 | 已核验数量 | |---:|---|---|---:| | 52 | `ZL_C_ck` | `VocabularyWord` | 89,620 | | 53 | `ZL_C_lxjl` | `PracticeRecord` | 816 | | 54 | `ZL_C_order` | `CourseAppointment` | 345 | | 56 | `ZL_C_ss` | `DailyStudyRecord` | 108 | | 58 | `ZL_C_kcbd` | `CourseBinding` | 55 | | 59 | `ZL_C_skjl` | `LessonRecord` | 82 | | 60 | `ZL_C_gywjl` | `MemoryPracticeRecord` | 1,380 | | 61 | `ZL_C_cpda` | `AssessmentProfile` | 14 | `myfield`/`myfield2` 只允许白名单字段和参数化等值过滤,`orders` 只允许已映射字段的 `ASC`/`DESC` 或旧 `NEWID()` 随机排序。Model 53/54/56/58/59/60/61 的列表与详情禁止匿名读取,非管理员仅能访问本人或指派给自己的学员记录。 学习专用只读接口已按旧页面的真实响应形状重建: - `e_record_detail`:由 Model 56 学习记录解析 `xxqs`,再按其中的 `GeneralID` 联查 Model 52 与 `VocabularyWord`,保持原顺序并为每项返回旧页面要求的 `detail[0]`。 - `e_words_list`:只返回指定用户 `PracticeRecord.jrscb=1` 的生词,按 `scid -> CommonModel.generalId -> VocabularyWord.id` 联查词库详情,不再误返回 89,620 条全量词库。 - `e_ck_list`:按一个或多个词库单元返回 Model 52 词条,并按 `用户 + 单词 GeneralID` 联查 `PracticeRecord.xxcs/jrscb`,恢复旧页面的 `w_learned` 与生词状态。 - `e_add_words`:验证词库 ID 与用户归属后批量更新 `PracticeRecord`;`save=1` 递增学习次数,`ifnew=1/0` 加入/移出生词,首次学习会创建带云端来源标识的进度记录。 - `stu_record_update_v2`:按 `预约 GeneralID + 学员 ID` 幂等新增或更新 Model 56;校验预约归属和词库 ID,根据 `xxqs.check` 重算 `learned/ygg/djq`。线上运行时实际未暴露文档中的 `Psql.transaction`,因此新记录采用安全整数范围内的高熵数字 ID,并顺序写入 `DailyStudyRecord` 与 `CommonModel`;任一步失败都会补偿删除已创建记录,避免孤立数据。 - `content_add_zt`:恢复旧源码专用于 Model 56 的学习记录创建逻辑,按北京时间当天生成 `+1/+2/+3/+5/+7/+9/+11/+14/+17/+21/+30/+40/+50/+60/+90` 共 15 个 `fxrl` 日期;验证用户归属和词库 ID 后补偿式双写 `DailyStudyRecord + CommonModel`,不把缺 Schema 的其他内容模型混入该接口。 - `content_update`:按 `GeneralID` 解析现有 Model 53/54/56/58/59/60/61 的规范化副表,先以副表原有学员/陪练字段鉴权,再按实际 Parse Schema 转换类型并批量更新主副表;拒绝变更所属用户,失败时恢复更新前字段。Model 59 仅开放已有 `ZL_C_skjl` 对应的 Node 296,缺独立 Schema 的 Node 77 继续返回 501。 - `content_add`:对 Model 53/54/56/58/59/60/61 按目标 Schema 白名单转换 addon 字段,验证所属学员与业务操作人后补偿式新增副表和 `CommonModel`,返回旧契约字符串 `GeneralID`。Model 55、57 及 Model 59/Node 77 因目标库没有对应副表而逐请求返回 501,不把数据错写到相似模型。 - `e_order_detail`:以预约内容 `GeneralID` 联查 `CourseAppointment`,返回数组契约、旧字段别名和可恢复的课程名称。 - `e_order_tongji`:按交付包 `Pages/API/WXAPP.cshtml` 原公式恢复六个字符串字段。陪练按 `LessonRecord.jsmz` 统计课型 1/2/3,佣金分别为 20/40/40、时长分别为 0.5/1/1 小时;学员按 `CourseAppointment.szyh` 且 `dszt>10` 统计课型和时长,`t_total` 继续按旧逻辑统计 `PracticeRecord.yhid`。 - `e_order_update_v2`:恢复 `0→10→11→20→30` 角色状态机。状态 11 以单条 PostgreSQL CTE 原子写入课时账本并更新 `_User.legacyUserData`:类型 1/2/3/4 分别扣 `Purse/SilverCoin/UserExp/UserPoint`,类型 1/2 同步扣 0.5/1 `UserPoint`;账本 `sourceKey` 作为幂等声明。随后按学习记录 `fxrl` 补齐最多 15 组 `MemoryPracticeRecord + CommonModel`,中断重试会修复缺失主记录,当前调用失败则补偿余额、账本及本次新增复习记录。 - `e_get_21list`:以 `MemoryPracticeRecord` 为主记录,联查 Model 60、原学习记录和课程节点;学员按 `yhid`、教练收入列表按 `plid` 隔离。 - `user_get`:从 `_User.legacyUserData` 恢复 `VIP/ParentUserID/GroupID/RegTime` 与余额字段,返回旧页面同时使用的 camelCase/PascalCase 别名;不返回 `UserPwd`、支付密码、哈希或会话字段。 - `user_register`:恢复旧页 6–18 位密码契约,在公司范围内原子分配 `legacyUserId`,写入默认 `GroupID=1`、邀请人 `ParentUserID` 及六类账户初始值,返回可立即使用的 Parse `sessionToken`。 - `user_update`:兼容旧设置页 `mu` JSON 与 Angular 扁平字段,同步昵称、头像、姓名、性别、生日、手机、邮箱、头衔等保留字段;邀请人只允许首次完善,并拒绝自指和循环关系。 - `user_list`、`user_dept`:按迁移保留的 `legacyUserData.ParentUserID` 重建直属团队分页和 `v0-v5` 会员等级统计,并只允许本人纵向团队链或管理员查看。 - `e_user_list`:按旧源码的 Model 54、`status=99`、`CourseAppointment.pl` 分组预约学员,不再依赖目标库中仅有 2 条的通用 `agent` 指针。 - `user_point_list`:按旧接口 `stype=1..6` 分别查询 `UserExpDomP/UserSIcon/UserExpHis/UserUserPoint/UserDummyPoint/UserCredit`,恢复 `ExpHisID/HisTime/Detail` 别名;迁移资料没有提现费率,余额日志的 `purse_fee` 明确返回 `null` 并标记规则不可用。 - `guestbook_add`:兼容旧页的 `model` JSON(`UserID/Title/TContent/Cateid`)和 Angular 表单的扁平字段,限制 800 字并阻止普通用户冒用他人 `UserID`。 - `content_get`:恢复旧页面依赖的单元素数组 `result[0]` 契约;私有 Model 详情继续要求真实 Parse 会话并校验本人、直属学员或管理员范围。 - `content_uphis`:文章浏览量允许匿名原子 `+1`,忽略客户端自定义增量;私有 Model 仍要求会话和记录归属权限。 - `node_list`:普通栏目按旧 `OrderID/NodeID` 升序;`ifunit=1` 分支使用真实 Parse 会话,按 Model 52 词库和 `PracticeRecord.xxcs` 返回每单元 `total/yx_word/process`。 - `node_get`:除通用栏目别名外,补齐连连看页实际读取的 `ConsumePoint/ConsumeDeposit` 及相关消费字段 PascalCase 别名。 - `app_update`:从目标 `App.index/version/changelog/downUrl` 恢复 `ver/nver/intro/path`;迁移资料没有 APK 字节大小,因此 `size=null` 并显式标记 `sizeUnavailable=true`。目标记录中的安装包地址已保留,但其文件域名在 2026-08-18 检查时 TLS 证书已过期,实际下载仍属于外部环境阻塞。 `user_info_name` 仅用于匿名用户名存在性查重,不复制旧微信页“只凭手机号查询结果直接建立本地登录态”的无凭证登录语义;手机号登录必须在 `mcode_send/user_login_mobile` 具备新短信校验链路后恢复,微信登录必须在 `user_sync2` 具备新版容器授权后恢复。 迁移数据没有保存复习收入金额,也没有提供可验证的计价公式,因此 `e_get_21list_tj` 改为显式 501;收入列表仍返回复习事实,但用 `incomeRuleUnavailable=true` 标记金额不可恢复,不伪造收入。 ## 因目标 Schema/历史数据缺失而阻塞 | 能力 | action | 缺失项 | |---|---|---| | 购物车 | `cart_list` | 无购物车类 | | 优惠券 | `coupon_list`, `coupon_usrgot_add`, `coupon_usrgot_list` | 无优惠券实例和用户领取关系类 | | 订单/物流 | `order_delivery`, `order_get`, `order_list`, `order_signfor`, `user_shop_order`, `user_shop_sales` | 无订单、商品明细、销售和物流类 | | 订单评价 | `order_comment_add`, `order_comment_list` | 无评价类 | | 支付 | `payment_cart`, `payment_cart_again`, `payment_success` | 无订单/支付明细类 | | 发票 | `invoice_add`, `invoice_del`, `invoice_get`, `invoice_list`, `invoice_upd` | 无发票类 | | 收货地址 | `receaddr_add`, `receaddr_del`, `receaddr_get`, `receaddr_list`, `receaddr_upd` | 无地址类 | | 提现账户 | `user_bank_add`, `user_bank_del`, `user_bank_get`, `user_bank_list` | 无提现账户类 | | 收藏 | `user_star_add`, `user_star_del`, `user_star_is` | 无用户收藏关系类 | | 会员订单 | `user_group_usr_supply`, `user_group_usr_upgrade` | 无会员购买/续费订单类 | | 投票 | `vote_add`, `vote_ask`, `vote_question` | 无可证明的投票记录类 | | 商品读取 | `product_get`, `product_list` | 目标 `Product` 仅迁入 `ZL_P_Product` 附表的 `id/pics/size/color/nums/isChu`;缺 `ZL_Commodities` 主表的商品名、价格、正文、所有者、销售状态和库存 | | 库存流水 | `product_stock_list` | 无旧 `ZL_Shop_Stock` 对应类,不能用商品附表伪装库存流水 | 上述接口要恢复 1:1 能力,必须先补建 Schema,并取得可迁移的旧数据;仅有空表或空成功响应不能算迁移完成。 ## 因外部服务、安全或合规而阻塞 | 能力 | action | 需要的前置条件 | |---|---|---| | 短信验证码 | `mcode_send`, `user_login_mobile`, `user_register_mobile` | 新短信服务商凭据、验证码存储和限流 | | 微信授权 | `user_sync2` | 新微信容器流程和凭据 | | 资金/积分 | `user_cash_add`, `user_cash_list`, `user_coin_recharge`, `user_exp_transfer`, `user_money_recharge`, `user_money_transfer` | 支付凭据、不可变事务账本和业务规则 | | 复习收入 | `e_get_21list_tj` | 旧迁移数据中的收入金额字段或经业务方确认的计价公式 | | 支付密码 | `user_update_paypwd` | 独立哈希服务和重置流程 | | 密码安全 | `user_update_pwd`, `user_update_pwdall` | 前者缺新短信验证码服务;后者还依赖独立支付密码哈希存储 | | 实名认证 | `user_rnauth_add`, `user_rnauth_get`, `user_rnauth_upd` | 合规审核、加密存储和访问审计 | ## 有数据但尚未能证明 1:1 语义 | 能力 | action | 待确认/待实现 | |---|---|---| | 缺失内容副表 | `content_add` 的 Model 55、57 与 Model 59/Node 77 分支 | 数据库迁移未提供生词集合、单元聚合与连连看成绩目标类;接口逐请求返回 501 | | 商品写入 | `product_del`, `product_sale_change`, `product_stock_change` | 缺 `ZL_Commodities` 主表、`UserID/Sales/Stock` 字段及 `ZL_Shop_Stock` 库存流水;兼容动作 `product_add/product_upd` 同样缺主副表事务目标 | | 单元进度 | `unit_record_update` | 旧源码在接口调用前无条件 `return`;需业务方确认废弃或提供新的聚合规则 | | 发布 | `pub_add`, `pub_list` | 旧前端实际依赖 Pub 7–13(注销、供应商、商户邀请、退货、换货、结算),目标库只迁入 Pub 2–6 以及 Pub 3/4/5 对应的 `PubZXDC/PubTw/PubWTHD`;缺失业务配置、副表和历史记录,不能错写到现有问答/调查表 | ## 前端切换决策 Angular H5 已启用混合迁移路由: - `user_login_passwd` 已优先调用云函数:已完成 Parse 密码迁移的账号保存真实 `sessionToken` 并用该会话读取 `user_get`;尚未完成密码重置的旧账号在云函数返回 401/403 时自动回退旧登录,不中断存量用户。`user_info_name` 查重和 `user_register` 经典注册已直接切换云函数。 - `app_update`、`node_list`、`node_get` 已切换至云函数;匿名公开内容及持有真实 Parse 会话的 `content_get/content_uphis` 已切换,旧会话继续留在旧端点,避免私有学习详情在密码迁移完成前丢失鉴权。 - 持有真实 Parse 会话时,`content_add`、`content_add_zt`、`content_update`、`e_add_words`、`e_ck_list`、`e_order_detail`、`e_order_tongji`、`e_order_update_v2`、`e_record_detail`、`e_user_list`、`e_words_list`、`e_get_21list`、`guestbook_add`、`stu_record_update_v2`、`user_get`、`user_list`、`user_dept`、`user_point_list`、`user_update` 已切换至云函数;旧会话继续留在旧端点,避免存量账号在密码重置前中断。 - 不含 addon 条件的 `content_list` 和 Model 52 公开词库已切换;已持有 Parse 会话的用户会把字段白名单内的 Model 53/54/56/58/59/60/61 addon 查询切到云函数,仍使用旧会话的存量账号自动保留旧端点。 - 云函数返回同时提供规范化 camelCase 与旧系统 `GeneralID`/`NodeID`/`Title` 等字段别名。 - `product_list/product_get/product_stock_list` 已从“部分映射”纠正为显式 501:当前 `Product` 只是附表,不能满足旧商品或库存流水契约。 在线 65 个阻塞 action 中仍包含订单、支付、商品和退换货等主流程时,直接全量切换会导致页面大面积中断。剩余切换条件是: 1. 先对齐缺失 Schema/数据和第三方凭据。 2. 完成剩余 action 的云函数事务、权限和字段回归。 3. 将 H5 会话改为 Parse `sessionToken`,再一次性切换到 `/api/functions/xiaoshu/app/gateway`。