$path) { $source = file_get_contents($path); if (!is_string($source)) { throw new RuntimeException("无法读取 {$name}: {$path}"); } $sources[$name] = $source; } $migration = $sources['migrationPath']; foreach (['qywx_promotion_pool_operator', 'uk_pool_admin', 'granted_by_admin_id'] as $needle) { if (!str_contains($migration, $needle)) { throw new RuntimeException("共享操作人迁移缺少 {$needle}"); } } $logic = $sources['logicPath']; foreach (['batchSetOperators', 'applyPoolAccessScope', 'isPoolOperator', 'can_manage_access', 'operator_options', 'clearOperatorAuthCaches'] as $needle) { if (!str_contains($logic, $needle)) { throw new RuntimeException("获客助手共享权限逻辑缺少 {$needle}"); } } $deleteStart = strpos($logic, 'public static function deletePool('); $deleteEnd = strpos($logic, 'public static function batchSetOperators(', $deleteStart === false ? 0 : $deleteStart); if ($deleteStart === false || $deleteEnd === false) { throw new RuntimeException('无法定位 deletePool/batchSetOperators'); } $deleteMethod = substr($logic, $deleteStart, $deleteEnd - $deleteStart); if (!str_contains($deleteMethod, "assertScopedRow('qywx_promotion_pool', \$id, \$adminId, \$adminInfo, false)")) { throw new RuntimeException('共享操作人不得永久删除分流方案'); } if (!str_contains($deleteMethod, 'assertBasePagePermission($adminId, $adminInfo)') || !str_contains($deleteMethod, 'clearOperatorAuthCaches($operatorAdminIds)')) { throw new RuntimeException('删除方案必须校验基础权限并清理共享账号权限缓存'); } $batchStart = strpos($logic, 'public static function batchSetOperators('); $batchEnd = strpos($logic, 'private static function isRemoteLinkAlreadyMissing(', $batchStart === false ? 0 : $batchStart); if ($batchStart === false || $batchEnd === false) { throw new RuntimeException('无法定位 batchSetOperators'); } $batchMethod = substr($logic, $batchStart, $batchEnd - $batchStart); foreach (['assertBasePagePermission($adminId, $adminInfo)', 'clearOperatorAuthCaches($operatorAdminIds)'] as $needle) { if (!str_contains($batchMethod, $needle)) { throw new RuntimeException("批量授权缺少安全边界 {$needle}"); } } if (str_contains($logic, 'promotionPagePermissionAdminIdSet') || str_contains($batchMethod, '尚未获得企业微信获客助手页面权限') || str_contains($batchMethod, '$operatorAdminId === $ownerAdminId')) { throw new RuntimeException('批量授权仍存在预先页面权限或归属人跳过条件'); } $operatorAccess = $sources['operatorAccessPath']; foreach (['hasBasePagePermission', 'hasSharedPagePermission', 'hasPagePermission', 'visibleAdminIds', 'activePoolIds'] as $needle) { if (!str_contains($operatorAccess, $needle)) { throw new RuntimeException("共享页面权限服务缺少 {$needle}"); } } if (!str_contains($operatorAccess, "join('qywx_promotion_pool p', 'p.id = po.pool_id')") || !str_contains($operatorAccess, "whereNull('p.delete_time')")) { throw new RuntimeException('共享页面权限未排除已删除方案'); } if (!str_contains($sources['authLogicPath'], 'appendSharedPromotionPermission') || !str_contains($sources['menuLogicPath'], 'sharedPromotionMenuIds')) { throw new RuntimeException('共享账号未动态获得页面权限或导航菜单'); } if (!str_contains($sources['authMiddlewarePath'], "str_starts_with(\$accessUri, 'firstvisit.wecompromotion/')") || !str_contains($sources['authMiddlewarePath'], 'isKnownWecomPromotionAction')) { throw new RuntimeException('获客助手子接口未统一纳入页面权限中间件'); } if (!str_contains($sources['customerLogicPath'], 'operatorPoolIds($adminId)') || !str_contains($sources['customerLogicPath'], "whereOr('p.id', 'in', \$operatorPoolIds)") || !str_contains($sources['customerLogicPath'], 'QywxPromotionOperatorAccess::visibleAdminIds')) { throw new RuntimeException('共享操作人尚未接入获客客户统计权限'); } if (!str_contains($sources['controllerPath'], 'public function batchSetOperators()')) { throw new RuntimeException('控制器缺少批量设置操作人接口'); } if (!str_contains($sources['apiPath'], '/firstvisit.wecomPromotion/batchSetOperators')) { throw new RuntimeException('前端 API 缺少批量设置操作人接口'); } foreach (['批量设置访问操作', '添加操作人', '移除操作人', 'selectedPoolIds', 'can_manage_access'] as $needle) { if (!str_contains($sources['viewPath'], $needle)) { throw new RuntimeException("前端共享权限交互缺少 {$needle}"); } } if (str_contains($sources['viewPath'], '无页面权限') || !str_contains($sources['viewPath'], '授权后账号会自动获得本页面入口')) { throw new RuntimeException('前端仍将预先拥有页面权限作为授权条件'); } echo "WECOM_PROMOTION_POOL_OPERATOR_CONTRACT_OK\n";