Просмотр исходного кода

chore: classify legacy printer migration

彭峰 1 месяц назад
Родитель
Сommit
e7bfd5544a

+ 1 - 0
docs/migration/admin-migration-status.md

@@ -36,6 +36,7 @@
 - Office/OA 中字段完全匹配的 `MisType` 已迁为 Angular“OA 流程类型”页与 `misTypes/saveMisType/misTypeBatch`,支持帐套隔离、搜索、防重、原子旧 ID 和 `MisProcedure.typeId` 引用保护删除;用户选择与邮件通讯录复用现有用户管理,模型选择为部分迁移。其余旧 `OA_AuditFlow/OA_AuditFlowItem/Mis_Model/OA_Sign/OA_Document` 主表及套红文件运行时未迁入;目标空的 `MisProcedure/MisProLevel/MisSign/DocModel` 是不同版本结构,不被强行冒充,21 个动作由 `legacyOABlocker` 逐项说明。
 - `Page` 控制器中与旧字段完全匹配的 `PageStyle` 已迁为 Angular“黄页样式”页与 `pageStyles/savePageStyle/pageStyleBatch`:支持帐套隔离、名称搜索与防重、路径和状态校验、原子分配旧 `PageNodeid`、单一默认样式及 `PageTemplate.userGroup` 引用保护删除。目标 `PageTemplate` 虽保留旧字段但为空,且没有 `PageReg` 用户黄页申请主表或 `SiteOption` 黄页配置层;内容管理仅部分复用现有 `CommonModel`,其余 15 个旧入口由 `legacyPageBlocker` 返回逐项数据或基础设施原因。
 - `Office/Plat` 的 `PlatComp` 与折叠在 `_User.legacyUserPlat` 的旧 `User_Plat` 数据已迁为 Angular“协同办公企业”页面以及 `platformCompanies/savePlatformCompany/platformCompanyMembers/platformCompanyMemberBatch/platformCompanyBatch`:兼容失真的 count,支持企业资料防重、原子旧 ID、同帐套创建人、成员查看/加入/移动/移出,并保护仍有成员或 `PlatUserRole` 角色的企业删除;`legacyUserPlat` 已从通用用户编辑锁定。旧 `Common_UserApply/Blog_Msg/Plat_Topic/Plat_Group` 主表均不存在,申请审核、动态消息、话题和企业群组入口由 `legacyPlatBlocker` 逐项返回原因;旧 Razor `CreateComp/WordTlp` 视图也没有可恢复的交互基线。
+- `Printer/Index` 的控制器本身只是返回已丢失的 Razor 视图;旧程序集可确认其候选业务依赖 `ZL_Shop_PrintDevice/ZL_Shop_PrintTlp/ZL_Shop_PrintMessage` 和飞印客户端,但签约文档与线上 110 个 Schema 均没有这些设备、模板和消息数据,旧客户端还向 `my.feyin.net` 发送明文 HTTP 请求。无法在不知道页面、历史设备密钥和第三方协议可用性的情况下安全伪造 1:1 打印后台,已由 `legacyPrinterBlocker` 明确登记为基础设施阻塞。
 - 旧 `NodeAdd_Submit`、`Node_API` 与 `UnionNode_Move` 的核心栏目生命周期已迁为专用 `saveNode/nodeBatch`:新增栏目以临时来源键完成 Parse 初始写入,再使用 PostgreSQL 事务锁原子分配 `nodeId/orderId` 并替换为旧 `sourceKey`;保存会校验同级名称/目录重复、父栏目帐套和回收状态,移动会阻断自身/下级循环并递归修正所有后代深度。回收、恢复和每批 1–100 个栏目迁移已接入 Angular;永久删除仅在没有内容、下级栏目、节点权限和模型模板引用时开放,通用保存与删除不能绕过。
 - 旧 `SpecialAdd_Save` 与 `UnionSpecial_Move` 已迁为专用 `saveSpecial/specialBatch`:新增专题使用临时来源键和 PostgreSQL 事务锁原子分配 `specId/orderId`,保存时校验全帐套名称/目录唯一、父专题归属与层级循环;删除会拒绝仍有下级专题的记录。旧 `UnionSpecial_Merge` 被明确列为数据阻塞:`CommonModel.specialId` 只存在于 Parse Schema、PostgreSQL 物理列缺失,商品主表也未迁移,无法安全改写内容/商品专题关系。
 - 旧 `ModelManage/Field/Order_Submit` 的安全部分已迁为 `saveModelMetadata/saveModelFieldMetadata/modelFieldOrder`:现有模型可编辑名称、条目文案、图标、说明和内容模板元数据,现有字段可编辑别名、提示、显示/搜索配置,并可在同模型内批量排序;`modelId/modelType/tableName/fieldId/modelId/fieldName/fieldType/sourceKey` 等结构字段通用只读。新增、复制、删除模型或字段会显式返回 501,因为旧实现同时执行 PostgreSQL 建表/改列、标签生成和模板文件写入,目标托管环境没有该 DDL/旧模板运行时。

+ 5 - 0
scripts/deploy-admin-functions.mjs

@@ -1425,6 +1425,11 @@ async function handler(request, response) {
     if (operation === 'legacyPlatBlocker') {
       const action = String(input.action || ''); const blockers = { Default:'旧默认页跳转到已缺失 Blog_Msg 动态管理,目标没有可进入的信息首页', AuditApply:'目标 Schema 缺少旧 Common_UserApply 协同办公申请主表', AuditApply_Agree:'目标没有可批量通过并改为状态 99 的协同办公申请', AuditApply_Reject:'目标没有可批量拒绝并改为状态 -1 的协同办公申请', CreateComp:'旧动作仅剩已丢失的 Razor 企业创建向导;Angular 企业表单已覆盖主表生命周期,但未知向导交互无法 1:1 恢复', PlatInfoDeail:'目标 Schema 缺少旧 Blog_Msg 动态消息主表', PlatInfoDetail_Submit:'目标没有可编辑正文与日期的旧协同办公动态消息', PlatInfoManage:'目标没有 Blog_Msg 顶级动态、回收状态和关键词数据', TopicList:'目标 Schema 缺少旧 Plat_Topic 话题主表与星标状态', WordTlp:'旧文字模板仅剩已丢失的 Razor 视图,目标没有模板数据或渲染协议', Crud:'目标 Schema 缺少旧 Plat_Group 企业部门/群组树', CrudAdd:'目标没有可编辑的企业群组、上级和成员管理员关系', CrudAdd_Submit:'目标缺少 Plat_Group 的 FirstID/Depth/ManageIDS/MemberIDS 持久层', GroupAdmin_API:'目标没有可删除的 Plat_Group 企业群组记录', API_msg_topic:'目标缺少 Blog_Msg 与 Plat_Topic,不能执行动态删除/恢复/清空或话题删除/星标' }; if (!Object.prototype.hasOwnProperty.call(blockers, action)) fail(400, '不支持的旧协同办公动作'); fail(501, 'migration_blocked: ' + blockers[action]);
     }
+    if (operation === 'legacyPrinterBlocker') {
+      const action = String(input.action || '');
+      if (action !== 'Index') fail(400, '不支持的旧打印动作');
+      fail(501, 'migration_blocked: 旧 PrinterController.Index 只返回已丢失的 Razor 视图;目标 110 个 Schema 中没有旧 ZL_Shop_PrintDevice、ZL_Shop_PrintTlp、ZL_Shop_PrintMessage 数据,旧客户端还依赖 my.feyin.net 的明文 HTTP 设备协议,无法安全等价恢复');
+    }
     if (operation === 'pageStyles') {
       const page = Math.max(1, Number(input.page) || 1); const pageSize = Math.min(100, Math.max(1, Number(input.pageSize) || 20)); const search = String(input.search || '').trim(); if (search.length > 100) fail(400, '黄页样式搜索词不能超过 100 个字符'); const fields = await schemaFor('PageStyle'); const query = new Parse.Query('PageStyle'); applyTenant(query, fields, context, input.companyId); if (search) query.matches('pageNodeName', escapeRegex(search), 'i'); query.ascending('orderid'); const total = await query.count({ useMasterKey: true }); query.skip((page - 1) * pageSize); query.limit(pageSize); const results = await query.find({ useMasterKey: true }); return response.json({ success: true, data: { className: 'PageStyle', page, pageSize, total, results: results.map(serializeObject) } });
     }

+ 1 - 0
scripts/generate-admin-coverage.mjs

@@ -252,6 +252,7 @@ const explicit = new Map([
   ['Office / Plat/CrudAdd', ['blocked-data', '目标没有可编辑的企业群组、上级和成员管理员关系']],
   ['Office / Plat/CrudAdd_Submit', ['blocked-data', '目标缺少 Plat_Group 的 FirstID/Depth/ManageIDS/MemberIDS 持久层']],
   ['Office / Plat/GroupAdmin_API', ['blocked-data', '目标没有可删除的 Plat_Group 企业群组记录']],
+  ['Printer/Index', ['blocked-infrastructure', '旧控制器只返回已丢失的 Razor 视图;目标 Schema 又缺少 PrintDevice/PrintTlp/PrintMessage,且旧飞印客户端依赖明文 HTTP 第三方协议,无法安全等价恢复']],
   ['Design / Interactive/InteractiveList', ['blocked-data', '目标缺少旧 Design_Pub 交互提交表及 sceneid、uid、fname 数据;DesignAnswer/Pub 不等价']],
   ['Design / Interactive/Interactive_API', ['blocked-data', '目标没有可按旧 Design_Pub ID 删除的交互提交记录']],
   ['Office / iServer/Default', ['blocked-data', '目标 Schema 缺少旧 IServer 服务工单主表与回复表']],

+ 1 - 0
scripts/smoke-admin-functions.mjs

@@ -699,6 +699,7 @@ try {
   for (const action of ['Default','AuditApply','AuditApply_Agree','AuditApply_Reject','CreateComp','PlatInfoDeail','PlatInfoDetail_Submit','PlatInfoManage','TopicList','WordTlp','Crud','CrudAdd','CrudAdd_Submit','GroupAdmin_API','API_msg_topic']) {
     const blocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'legacyPlatBlocker', action }, 501); if (!String(blocked.message).includes('migration_blocked')) throw new Error(`旧协同办公动作 ${action} 未返回明确迁移阻塞`);
   }
+  const printerBlocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'legacyPrinterBlocker', action: 'Index' }, 501); if (!String(printerBlocked.message).includes('ZL_Shop_PrintDevice') || !String(printerBlocked.message).includes('my.feyin.net')) throw new Error('旧打印入口未返回数据与设备协议阻塞原因');
   for (const action of ['Default','FlowInfo','FlowInfo_Submit','Flow_API','SelFlowModel','FlowItem','FlowItemInfo','FlowItemInfo_Submit','FlowItem_API','AddMisModel','AddMisModel_Submit','AddSign','AddSign_Submit','AddSign_Delete','ApplyManage','ApplyManage_Delete','MisModelManage','MisModelManage_Delete','OAConfig','SelModelFieds','SignManage']) {
     const blocked = await callFunctionError('xiaoshu/admin/gateway', login.sessionToken, { operation: 'legacyOABlocker', action }, 501); if (!String(blocked.message).includes('migration_blocked')) throw new Error(`旧 OA 动作 ${action} 未返回明确迁移阻塞`);
   }

+ 2 - 2
src/app/admin/legacy-admin-coverage.generated.ts

@@ -4640,8 +4640,8 @@ export const LEGACY_ADMIN_COVERAGE: readonly LegacyAdminCoverageEntry[] = [
     "module": "Printer",
     "action": "Index",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "旧控制器只返回已丢失的 Razor 视图;目标 Schema 又缺少 PrintDevice/PrintTlp/PrintMessage,且旧飞印客户端依赖明文 HTTP 第三方协议,无法安全等价恢复"
   },
   {
     "module": "User / PrivacyPolicy",