feat(membership): 实现会员系统和购买流程
- 创建 MembershipModalContext 统一管理会员弹窗 - 优化 MembershipModal 产品套餐展示和购买流程 - 集成 RevenueCat SDK 并初始化内购功能 - 在个人中心添加会员 Banner,引导非会员用户订阅 - 修复日志工具的循环引用问题,确保错误信息正确记录 - 版本更新至 1.0.20 新增了完整的会员购买流程,包括套餐选择、购买确认、购买恢复等功能。会员 Banner 仅对非会员用户展示,已是会员的用户不会看到。同时优化了错误日志记录,避免循环引用导致的序列化失败。
This commit is contained in:
@@ -41,26 +41,66 @@ class Logger {
|
||||
}
|
||||
|
||||
private async addLog(level: LogEntry['level'], message: string, data?: any): Promise<void> {
|
||||
// 安全地处理数据,避免循环引用
|
||||
let safeData = data;
|
||||
if (data && typeof data === 'object') {
|
||||
try {
|
||||
// 对于非 ERROR 级别的日志,也进行安全序列化
|
||||
if (data instanceof Error) {
|
||||
safeData = {
|
||||
name: data.name,
|
||||
message: data.message,
|
||||
stack: data.stack
|
||||
};
|
||||
} else {
|
||||
// 使用 JSON.stringify 的 replacer 函数处理循环引用
|
||||
safeData = JSON.parse(JSON.stringify(data, (key, value) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (value.constructor === Object || Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
// 对于其他对象类型,转换为字符串表示
|
||||
return value.toString ? value.toString() : '[Object]';
|
||||
}
|
||||
return value;
|
||||
}));
|
||||
}
|
||||
} catch (serializeError) {
|
||||
// 如果序列化失败,只保存基本信息
|
||||
safeData = {
|
||||
error: 'Failed to serialize data',
|
||||
type: typeof data,
|
||||
toString: data.toString ? data.toString() : 'N/A'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const logEntry: LogEntry = {
|
||||
id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
|
||||
timestamp: Date.now(),
|
||||
level,
|
||||
message,
|
||||
data
|
||||
data: safeData
|
||||
};
|
||||
|
||||
// 同时在控制台输出
|
||||
const logMethod = level === 'ERROR' ? console.error :
|
||||
level === 'WARN' ? console.warn :
|
||||
level === 'INFO' ? console.info : console.log;
|
||||
|
||||
logMethod(`[${level}] ${message}`, data || '');
|
||||
// 同时在控制台输出 - 使用原生 console 方法避免循环调用
|
||||
try {
|
||||
const logMethod = level === 'ERROR' ? console.error :
|
||||
level === 'WARN' ? console.warn :
|
||||
level === 'INFO' ? console.info : console.log;
|
||||
|
||||
logMethod(`[${level}] ${message}`, safeData);
|
||||
} catch (consoleError) {
|
||||
// 如果控制台输出失败,使用最基本的 console.log
|
||||
console.log(`[${level}] ${message}`, typeof safeData === 'string' ? safeData : 'Object data');
|
||||
}
|
||||
|
||||
try {
|
||||
const logs = await this.getLogs();
|
||||
logs.push(logEntry);
|
||||
await this.saveLogs(logs);
|
||||
} catch (error) {
|
||||
// 使用原生 console.error 避免循环调用
|
||||
console.error('Failed to add log:', error);
|
||||
}
|
||||
}
|
||||
@@ -78,6 +118,7 @@ class Logger {
|
||||
}
|
||||
|
||||
async error(message: string, data?: any): Promise<void> {
|
||||
// addLog 方法已经包含了安全的数据处理逻辑
|
||||
await this.addLog('ERROR', message, data);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user