hailin
5eb4afa2f9
feat(2.0): 为 2.0 部署独立的 presence-service-2
...
- 在 docker-compose.2.0.yml 添加 presence-service-2 (port 3027)
- 使用独立数据库 rwa_mining_presence,隔离 2.0 用户 DAU/在线数据
- Redis DB 17(2.0 其他服务已用 8,10,12,13,14,15,16)
- postgres-2 POSTGRES_MULTIPLE_DATABASES 追加 rwa_mining_presence
- 复用 presence-service 代码,与 auth-service 共享 JWT_SECRET
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 18:39:44 -08:00
hailin
6bca65e434
feat(telemetry): 设备字段提升为顶层结构化列(Amplitude 风格)
...
将 device_brand/device_model/device_os/app_version/locale 从 JSONB properties
提升为 analytics_event_log 表的独立列,并建立索引,支持亿级数据量下的高效
按设备维度查询和分组统计。
前端 (mining-app + mobile-app):
- toServerJson() 从 properties 中提取设备字段,以顶层字段发送给服务端
- 本地存储格式不变(properties 仍保留设备字段,便于离线队列完整性)
后端 (presence-service):
- Prisma schema: EventLog 新增 deviceBrand/deviceModel/deviceOs/appVersion/locale 列
- Migration: ALTER TABLE 添加 5 列 + 2 个索引
- DTO/Command: EventItemDto 接收顶层设备字段
- Entity: EventLog 新增 5 个字段及 getter
- Mapper: toDomain/toPersistence 映射新字段
- Handler: toEventLog 从 DTO 读取设备字段;SessionStartedEvent 优先使用顶层字段
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 09:50:48 -08:00
hailin
9c84be72bc
chore(presence-service): 更新 package-lock.json 以包含 @nestjs/jwt
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 08:59:34 -08:00
hailin
e8d9cb72a9
feat(presence-service): 修复鉴权——用户JWT验证心跳,管理员JWT查询在线/DAU数据
...
- 添加 @nestjs/jwt 依赖,AppModule 注册全局 JwtModule
- 重写 JwtAuthGuard:使用 JwtService.verifyAsync 解析用户 token (type=access)
- 新建 AdminGuard:验证管理员 token (type=admin),与 identity-service 共享 JWT_SECRET
- heartbeat 接口:保持 JwtAuthGuard(用户 JWT)
- online-count / online-history / dau:改用 AdminGuard(管理员 JWT)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 08:52:39 -08:00
hailin
a1d284b6b5
fix(password): 统一登录密码和支付密码状态查询为服务端 API
...
问题:
- isPasswordSet() 读 SecureStorage,重装/换设备后丢失 → 页面误判未设密码
- isPaymentPasswordSet() 读 response.data['isSet'],但实际格式为
{ success, data: { isSet } },取到 null → 始终返回 false
修复:
- 后端新增 GET /user/password-status 接口(isLoginPasswordSet 方法)
- 前端 isPasswordSet() 改为调用服务端 API
- 两个方法均使用正确的 response.data['data']['isSet'] 解包
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 08:14:24 -08:00
hailin
3aa2856770
fix(payment-password): 修复 isActive 字段名错误(应为 status !== ACTIVE)
...
Prisma schema 中 UserAccount 无 isActive 字段,实际为 status VARCHAR(20)。
两处 select 改为 { phoneNumber, status },检查改为 status !== 'ACTIVE'。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 07:05:42 -08:00
hailin
6f912b1232
feat(payment-password): 添加忘记支付密码功能(全栈)
...
后端(identity-service,纯新增):
- user-application.service 添加 2 个方法:
sendResetPaymentPasswordSmsCode(userId) —— 发送验证码到已绑定手机(Redis key 独立)
resetPaymentPassword(userId, smsCode, newPassword) —— 验证码校验 + 格式校验 + bcrypt 更新
- user-account.controller 新增 2 个端点(均为 @ApiBearerAuth):
POST /user/send-reset-payment-password-sms
POST /user/reset-payment-password
前端(mobile-app,纯新增):
- account_service 新增 sendResetPaymentPasswordSmsCode / resetPaymentPassword 两个方法
- 新建 reset_payment_password_page.dart:验证码 + 新6位PIN,重置成功后自动返回
- 路由:RoutePaths / RouteNames / AppRouter 各新增 resetPaymentPassword 条目
- change_payment_password_page:旧密码输入框下方添加「忘记支付密码?」入口链接
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 07:04:20 -08:00
hailin
cad7ebe832
feat(payment-password): 添加支付密码功能(全栈)
...
后端(identity-service):
- Prisma schema 新增 paymentPasswordHash 字段及手动迁移脚本
- user-application.service 添加 4 个方法:isPaymentPasswordSet / setPaymentPassword /
changePaymentPassword / verifyPaymentPassword(纯新增,不修改已有逻辑)
- user-account.controller 新增 4 个端点:
GET /user/payment-password-status
POST /user/set-payment-password
POST /user/change-payment-password
POST /user/verify-payment-password → { valid: bool }
前端(mobile-app):
- account_service 新增 4 个方法对应后端 4 个接口
- 新建 change_payment_password_page.dart:6 位数字支付密码设置/修改页面
- 路由:RoutePaths / RouteNames / AppRouter 注册 /security/payment-password
- profile_page:'修改登录密码' 改为 '修改密码',下方新增 '支付密码' 入口
- PasswordVerifyDialog:新增 title / subtitle / hint 可选参数,支持登录/支付双模式
- planting_location_page:认种确认改为验证支付密码(verifyPaymentPassword)
- pre_planting_purchase_page:预种确认后追加支付密码验证步骤
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 06:18:40 -08:00
hailin
b67dfa0f4c
fix(planting-service+app): 合并列表补充 totalPortions,前端显示实际份数而非订单数
...
- getMerges 批量查来源订单 portionCount,按合并分组求和后返回 totalPortions
- 预种明细合并卡片改用 totalPortions 显示份数,fallback 才用订单数
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 08:58:45 -08:00
hailin
1f5bb62805
fix(contribution-service): 合并完成后写入 synced_adoptions 记录以解除卖出限制
...
swapContributionForMerge 在事务内新增步骤 9f:
- 写入 synced_adoptions(original_adoption_id = 20B + mergeId)
- 供 SellRestrictionService.isRestricted 的 has_real_tree 判断使用
- upsert 保证幂等,contributionDistributed 由调用方置 true
Bug: 合并已完成(contribution_records 正确),但 isRestricted 始终
返回 true,因为 synced_adoptions 中没有 20B+ 记录(virtualAdoption
仅用于计算,未持久化)。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 08:25:15 -08:00
hailin
94792f56ea
fix(contribution-service): 预种算力除数从 5 改为 10,冻结阈值同步更新
...
- PRE_PLANTING_PORTION_DIVISOR: 5 → 10(每份算力 = 1棵树的 1/10)
- 冻结条件:totalPortions < 5 → < 10
- 解冻条件:totalPortions >= 5 → >= 10
- 同步更新所有相关注释和日志文案
注:2026-03-02 前已分配的份额算力记录(按 1/5 计算)不追溯修正。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 08:04:42 -08:00
hailin
979ba379c1
fix(text): 预种合并份数从5份改为10份
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 06:18:12 -08:00
hailin
867d4853ae
fix(trading-service): 补充 CONTRIBUTION_SERVICE_URL 环境变量
...
trading-service 调用 contribution-service 做预种卖出限制检查时,
因缺少 CONTRIBUTION_SERVICE_URL 导致 fallback 到 localhost:3020,
在 Docker 网络中无法连通,造成 fail-open 放行所有卖出。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 06:09:47 -08:00
hailin
ee734fb7b9
feat(trading+app): 预种卖出限制 — 前端 UI 禁用 + 后端查询端点
...
trading-service:
- asset.controller.ts: 新增 GET /asset/sell-restriction,供 mobile app 查询当前用户限制状态
- application.module.ts: 导出 TradingSellRestrictionService
mining-app:
- api_endpoints.dart: 新增 sellRestriction 端点常量
- trading_remote_datasource.dart: 新增 getSellRestriction()(fail-open)
- trading_repository.dart/impl: 新增接口与实现
- trading_providers.dart: 新增 sellRestrictionProvider(2分钟缓存,fail-open)
- trading_page.dart: 卖出限制时显示红色提示文字并禁用"确认交易"按钮
- c2c_publish_page.dart: 发布卖出广告时显示红色提示文字并禁用发布按钮
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 05:51:56 -08:00
hailin
ac3adfc90a
feat(pre-planting): 新增预种积分股卖出限制(方案B纯新增)
...
限制仅有预种份数(未合并成棵)的用户卖出积分股,
直到用户完成首次预种合并后方可卖出。
=== 改动范围(全部 2.0 系统,纯新增)===
contribution-service:
- prisma/pre-planting/schema.prisma: 新增 PrePlantingSellRestrictionOverride 模型
- migrations/20260304000000: 对应建表 SQL
- src/pre-planting/application/services/sell-restriction.service.ts: 核心判断逻辑
isRestricted = has_pre_planting_marker AND !has_real_tree AND !admin_override
- src/api/controllers/pre-planting-restriction.controller.ts: 暴露内部接口
GET /api/v2/pre-planting/sell-restriction/:accountSequence (@Public)
POST /api/v2/pre-planting/sell-restriction/:accountSequence/unlock (@Public)
- src/api/api.module.ts: 注册新 controller 和 SellRestrictionService
trading-service:
- src/application/services/sell-restriction.service.ts: HTTP + Redis 缓存(TTL 60s)
fail-open:contribution-service 不可用时允许卖出,保障业务连续性
- src/application/services/order.service.ts: 卖单前增加限制检查(4行)
- src/application/application.module.ts: 注册 TradingSellRestrictionService
mining-admin-service:
- src/application/services/pre-planting-restriction.service.ts: 代理接口 + 审计日志
每次管理员解除操作均写入 AuditLog,保证严格可追溯性
- src/api/controllers/pre-planting-restriction.controller.ts:
GET /pre-planting-restriction/:accountSequence
POST /pre-planting-restriction/:accountSequence/unlock
- api.module.ts / application.module.ts: 注册新服务和接口
mining-admin-web:
- users.api.ts: 新增 getPrePlantingRestriction / unlockPrePlantingRestriction
- use-users.ts: 新增 usePrePlantingRestriction / useUnlockPrePlantingRestriction hooks
- users/[accountSequence]/page.tsx: 受限时在基本信息卡显示红色警告 + 解除按钮
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 05:04:57 -08:00
hailin
8fcfec9b65
fix(contribution): backfill 强制重算 unlock status,修复预种用户层级卡在5级的问题
...
问题根因:直推用户先买预种导致 directReferralAdoptedCount 已累加到正确值(如5),
但 markAsAdopted() 随后被调用时硬编码 level=5/bonus=1,覆盖了正确的解锁状态。
之后 backfill 因 count 未变(5>5=false)永远不触发重算,level 永久卡死。
修复:updateAccountUnlockStatus 改用 setDirectReferralAdoptedCount() 替代
incrementDirectReferralAdoptedCount 循环,无论 count 是否变化都强制调用
updateUnlockStatus() 重算 unlockedLevelDepth 和 unlockedBonusTiers。
同时为 getDirectReferralAdoptedCount 补充注释,说明常规认种和预种均按人头计。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 23:16:47 -08:00
hailin
728728bee3
fix(admin-service): 个人/团队认种数量改为统计棵数而非订单数
...
【问题】
getUserList 及推荐树节点中「个人认种」「团队认种」显示的是订单条数
(_count: { id }),而非实际认种棵数。一笔订单可认种多棵,导致多棵
合并下单的用户数量严重偏低。
【修复】
将以下方法中的所有 count(orders) 改为 sum(treeCount):
- getPersonalAdoptionCount — 用户详情页个人认种数
- getTeamStats — 用户详情页团队认种数
- getBatchUserStats — 用户列表批量统计(个人/团队/省/市认种数)
- getAncestors — 推荐树祖先节点认种数
- getDirectReferrals — 推荐树直推节点认种数
【影响范围】
仅影响 admin-web 管理后台的展示数据,不涉及业务逻辑和数据存储。
省市认种百分比计算基准同步修正(teamAdoptions 也改为棵数),
比例结果不变,但基数更准确。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 22:29:32 -08:00
hailin
3f4b22b013
docs(contribution): add detailed comments for backfill task and findAccountsWithIncompleteUnlock
...
Explain the starvation root cause, unlock rules, pre-planting user scenario,
and future scalability considerations (cursor-based pagination).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 21:58:52 -08:00
hailin
2565fa8259
fix(contribution): process all incomplete-unlock accounts in backfill (remove 100-limit)
...
Previous 100-account batch caused starvation: accounts at positions 101+
(including recent pre-planting users) were never processed. Remove limit
to process all eligible accounts in each 10-minute run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 21:55:46 -08:00
hailin
551723fe82
fix(contribution): remove redundant snapshotDate from GetBatchRatiosRequest query DTO
...
The date is already read from URL path param @Param('date'), not query string.
Having it as required in the query DTO caused 400 Bad Request on ratios endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:06:53 -08:00
hailin
fb4e52c0de
fix(contribution): add @Public() to getBatchRatios endpoint for service-to-service calls
...
mining-service calls this endpoint without JWT token during DailySnapshot
full sync, causing 401 Unauthorized. Mark it as public since it's internal data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:35:55 -08:00
hailin
a392f708a7
fix(mining): 修复 DailySnapshot API 路径 v1→v2 + deploy-mining.sh 默认 standalone
...
- fetchContributionRatios URL 从 /api/v1/ 改为 /api/v2/ 与 contribution-service 的 globalPrefix 匹配
- deploy-mining.sh 默认部署模式从 shared 改为 standalone
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:27:57 -08:00
hailin
2b2e1efc7a
fix(mining): 修复挖矿分配并发覆盖贡献值同步的 Lost Update 问题
...
挖矿分配每秒运行的 save() 无条件写回所有字段(含 totalContribution),
导致贡献值同步刚更新的正确值被立即覆盖回旧值。
同时修复 DailySnapshot 全量同步一直 synced 0 accounts 的安全网失效问题。
- repository save() 增加 skipContributionUpdate 选项
- 挖矿分配路径传入 skipContributionUpdate: true
- contribution-service DailySnapshot 事件 payload 补全字段
- mining-service 适配字段名差异并修复 API 解析 bug
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:24:52 -08:00
hailin
532be9a561
fix(pre-planting): 合并详情显示实际份数和金额,不再硬编码
...
问题:合并详情页"合并份数"显示订单条数(7)而非实际份数(10),
"总价值"硬编码 订单数×1887,每笔订单金额也硬编码 1,887。
修复:
后端 getMergeDetail:
- 新增 sourceOrders[] 含每笔订单的 portionCount + totalAmount
- 新增 totalPortions(总份数)和 totalAmount(总金额)
前端 PrePlantingMerge model:
- 新增 MergeSourceOrder 类
- 新增 sourceOrders/totalPortions/totalAmount 字段
前端合并详情页:
- "合并份数"用 totalPortions 替代 sourceOrderNos.length
- "总价值"用 totalAmount 替代硬编码计算
- 来源订单列表显示每笔实际金额和份数(多份时显示"N份"前缀)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 02:58:34 -08:00
hailin
a8e06e2eda
fix(pre-planting): 合并逻辑改为按份数累计,支持多份订单合并
...
问题:用户一笔订单可购买多份(portionCount>1),但 performMerge
按订单条数校验是否够 10 条,导致 6 笔订单共 10 份却报错
"不足 10 笔已支付订单进行合并"。
修复:
- performMerge: 遍历 PAID 订单累加 portionCount 直到凑满 10 份
- findPaidOrdersByUserId: 去掉 limit 参数,获取所有 PAID 订单
- PrePlantingMerge.create: 去掉 sourceOrderNos.length === 10 校验
改为 length > 0(份数校验已在 performMerge 完成)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 02:44:35 -08:00
hailin
d7f7d7082d
fix(pricing): 预种定价API常量同步 — 3566→1887, /5→/10, 正式认种15831不变
...
admin-service tree-pricing.service.ts:
- BASE_PORTION_PRICE: 3566 → 1887
- supplement 除数: /5 → /PORTIONS_PER_TREE(10)
- BASE_PRICE 保持 15831(正式认种价格不变)
- 移除 updateSupplement 中重复声明的 BASE_PRICE 局部变量
planting-service tree-pricing-admin.client.ts:
- fallback basePortionPrice/totalPortionPrice: 3566 → 1887
mobile-app tree_pricing_service.dart:
- 修正上次commit误改的 basePrice/totalPrice fallback: 18870 → 15831
- basePortionPrice/totalPortionPrice 保持 1887
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 01:56:21 -08:00
hailin
a801a46e76
fix(admin): 修复授权照片代理未解包全局响应拦截器的问题
...
authorization-service 全局拦截器将响应包装为 {success, data, timestamp},
代理服务需要从 response.data.data 取实际数据,而非 response.data。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:50:52 -08:00
hailin
1621b75a47
feat(admin): 引荐关系树节点增加个人/团队预种份数展示
...
后端:
- ReferralNodeDto 新增 selfPrePlantingPortions, teamPrePlantingPortions
- user-detail.controller: getReferralTree 中并行调用
ReferralProxyService 批量获取所有节点的预种统计
(当前用户用 getPrePlantingStats,祖先+下级用 batchGetPrePlantingStats)
前端:
- ReferralNode 类型新增两个预种字段
- 引荐关系树节点(祖先链 + 递归展开节点)在"本人认种/团队认种"
下方新增一行"个人预种: X份 / 团队预种: Y份"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:16:02 -08:00
hailin
eb425b0f92
fix(referral): 团队预种总量排除自己的预种份数
...
TeamStatistics.teamPrePlantingPortions 包含用户自身的预种量,
但"团队预种"应只统计伞下成员。返回时减去 selfPrePlantingPortions。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:03:08 -08:00
hailin
5e05e336f7
fix(mining-admin): add @map for targetType column in Notification schema
...
Missing @map("target_type") caused Prisma to look for camelCase column
name instead of the snake_case column created in migration SQL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:55:00 -08:00
hailin
e68b5aa3d9
feat(mining-admin): add Prisma migration for notification tables
...
Create notifications, notification_reads, notification_user_targets
tables with indexes and unique constraints.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:48:17 -08:00
hailin
5ee94b3672
fix(notifications): NotificationPriority 类型从 string 改为 Prisma 枚举
...
修复后端编译错误: priority 字段类型应使用 @prisma/client 的
NotificationPriority 枚举而非 string。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:38:25 -08:00
hailin
7c781c7d62
feat(notifications): 2.0系统通知弹窗功能(后端+管理端+APP端)
...
复制1.0通知系统架构到2.0系统,实现完整的通知推送功能:
后端 (mining-admin-service):
- Prisma Schema: 添加 Notification/NotificationRead/NotificationUserTarget 表
- NotificationService: 完整 CRUD + 移动端通知查询/已读标记
- AdminNotificationController: 管理端通知 CRUD API
- MobileNotificationController: 移动端通知列表/未读数/标记已读 API
管理端 (mining-admin-web):
- 通知管理页面: 列表/筛选/新建/编辑/删除 Dialog
- 支持类型/优先级/目标用户/强制弹窗/发布时间等完整配置
- 侧边栏添加"通知管理"入口
APP端 (mining-app):
- NotificationService: 通知API服务(经Kong网关路由)
- NotificationBadgeProvider: 30秒轮询未读数量+生命周期监听
- ForceReadNotificationDialog: 强制阅读弹窗(橙色主题,逐条查看+确认)
- NotificationInboxPage: 通知收件箱(支持dark/light主题)
- MainShell: 添加强制弹窗检查(启动+前台恢复,60秒冷却)
- ProfilePage: 用户头部添加通知图标+未读角标
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:35:16 -08:00
hailin
59f7bdc137
feat(admin): 功能8修正 — 自助申请照片独立展示页(纯新增方案)
...
用户在 App 自助申请社区/市团队/省团队授权时上传的办公室照片,
之前错误放在授权管理页且因 CDC 未同步导致全显示"-"。
本次采用纯新增方案:绕过 CDC,通过内部 HTTP API 直连
authorization-service 源头数据库读取照片,保证数据 100% 准确。
=== 数据流 ===
admin-web 新页面 → admin-service 新 Controller
→ authorization-service 新 Internal API
→ authorization_roles 表 (源头, officePhotoUrls 字段)
=== 后端 — authorization-service ===
- 新建 internal-self-apply-photos.controller.ts
GET /authorization/self-apply-photos?page=1&limit=20&roleType=COMMUNITY
使用 $queryRaw 查询 office_photo_urls != '{}' 的记录
支持 roleType 筛选 + 分页
- index.ts 新增 export, app.module.ts 注册 controller
=== 后端 — admin-service ===
- 新建 authorization/authorization-proxy.service.ts
axios 代理调用 authorization-service 内部 API
批量查 user_query_view 补充 nickname + avatarUrl
- 新建 api/controllers/authorization-photos.controller.ts
GET /admin/authorization-photos (admin-web 调用)
- app.module.ts 注册 controller + provider
- docker-compose.yml 追加 AUTHORIZATION_SERVICE_URL 环境变量
=== 前端 — admin-web ===
- 新建 authorization-photos/ 页面 (page.tsx + SCSS)
表格展示:头像、昵称、账户序列号、授权类型、地区、照片数、申请时间
点击照片弹出 Modal 网格 → 点击单张弹出全屏 Lightbox
支持 roleType 筛选 + 分页
- Sidebar.tsx 追加"申请照片"菜单项 (紧随"授权管理"之后)
- endpoints.ts 追加 SELF_APPLY_PHOTOS 端点
- authorization/page.tsx 移除"申请照片"列、photo modal、lightbox
- authorization.module.scss 清理照片相关样式
=== 风险 ===
- CDC 链路: 零修改
- 现有 API: 零冲突 (新 controller 独立文件)
- 2.0 系统: 零影响
- 所有操作均为只读查询
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:08:32 -08:00
hailin
41818eb8e2
feat(mining-admin-web): 添加全局兑换记录页面
...
后端(trading-service):
- OrderRepository 新增 findAllOrders/findAllTrades 全局查询方法
- AdminController 新增 GET /admin/orders 和 GET /admin/trades 端点
支持 type/status/source/search/日期范围筛选 + 分页
前端(mining-admin-web):
- 新增 /exchange-records 页面,包含「订单记录」和「成交明细」两个 Tab
- 订单 Tab: 支持按类型/状态/来源筛选,显示订单号/账号/价格/数量等
- 成交 Tab: 支持按来源筛选,显示买卖双方/价格/数量/销毁量/手续费等
- 侧边栏添加「兑换记录」菜单项
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:38:46 -08:00
hailin
a55201b3b3
feat(referral+mobile): 功能6 — App 团队预种数量展示
...
纯新增实现,不修改任何现有业务逻辑,对现有系统零风险。
## 后端 — referral-service
新建 TeamPrePlantingController(JWT 认证),2 个公开端点:
1. GET /referral/me/team-pre-planting
- 返回当前用户的个人预种份数、团队预种总量
- 返回直推成员列表及每人的预种份数
- 从 TeamStatistics 表读取(CDC 事件维护的数据)
2. GET /referral/me/team-pre-planting/members?limit=20&offset=0
- 分页返回全部团队成员的预种明细(仅有预种份数 > 0 的成员)
- 使用 ancestor_path 数组查询所有下级用户
- JOIN team_statistics 获取每人的 selfPrePlantingPortions
Kong 网关无需修改(/api/v1/referral/* 已覆盖)。
## 前端 — Flutter mobile-app
新建 TeamPrePlantingPage 页面:
- 顶部统计卡片:个人预种 + 团队预种总量
- 直推预种明细列表(所有用户可见)
- 全部团队成员预种明细(仅市/省公司管理者可见,分页加载更多)
- 普通用户看到锁定提示"仅市公司/省公司管理者可查看"
入口:个人中心页预种按钮行新增绿色「团队预种」按钮。
## 文件清单
新建文件:
- backend/.../controllers/team-pre-planting.controller.ts(核心后端控制器)
- frontend/.../pages/team_pre_planting_page.dart(Flutter 团队预种页面)
微量修改(仅追加新行):
- controllers/index.ts: +1 行 export
- api.module.ts: +2 行 import/注册
- api_endpoints.dart: +2 行端点常量
- referral_service.dart: +4 模型类 +2 API 方法
- route_paths.dart, route_names.dart: +1 行路由定义
- app_router.dart: +1 import +1 GoRoute
- profile_page.dart: 预种按钮行追加第三个按钮
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:15:17 -08:00
hailin
d3969710be
fix(wallet): 系统账户划转前自动结算 settleableUsdt,解决全额划转余额不足
...
## 问题
省/市区域和团队账户收到的奖励进入 settleableUsdt,
但划转验证只检查 usdtAvailable,导致全额划转报"余额不足"。
## 修复
在 requestSystemWithdrawal 事务中,划转前自动执行结算:
1. 检测账户是否为区域/团队账户(6/7/8/9开头)
2. 若 settleableUsdt > 0,自动结算到 usdtAvailable
3. 记录 REWARD_SETTLED 流水明细(含 trigger=SYSTEM_WITHDRAWAL_AUTO_SETTLE)
4. 结算和划转在同一事务中,保证原子性
## 审计流水
每次自动结算会产生一条独立的 REWARD_SETTLED 流水:
- memo: "系统账户自动结算: 待结算 X 绿积分转入可用余额(划转前自动执行)"
- payloadJson: { settledAmount, previousAvailable, newAvailable, trigger }
## 其他
- 划转白名单扩展支持 6xxx(市团队)、7xxx(省团队)
- getSystemAccountName 添加省团队/市团队名称映射
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 06:30:34 -08:00
hailin
17df9b6df1
feat(admin): 预种管理页添加"待合并总量"统计项
...
- planting-service stats 端点新增 pendingMergePortions 字段
从 PrePlantingPosition 表聚合 SUM(available_portions)
- admin-web 统计卡片区新增"待合并总量(份)"显示
- 网格布局从 4 列调整为 5 列
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 04:17:38 -08:00
hailin
24fe10ee36
fix(authorization): 修复 queryAuthorizations 返回类型缺少 officePhotoUrls
...
application service 的 queryAuthorizations 方法返回类型声明中
缺少 officePhotoUrls 字段,导致 TypeScript 编译报错。
实际数据映射已正确包含该字段,只是类型注解遗漏。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 03:24:47 -08:00
hailin
ac15d6682a
feat(admin): 用户预种数量展示 & 授权申请照片查看
...
## 功能7:用户管理展示预种数量
### 需求
在用户管理(列表+详情页)展示个人及团队预种份数,
并支持跳转预种管理页查看团队中哪些ID购买了预种。
### 后端变更
referral-service — 新增内部 API:
- GET /internal/referral/pre-planting-stats/:accountSequence
- POST /internal/referral/pre-planting-stats/batch
从 TeamStatistics 表查询 selfPrePlantingPortions/teamPrePlantingPortions
admin-service:
- 新建 ReferralProxyService (src/referral/) 代理 referral-service 内部 API
- UserFullDetailDto 新增 selfPrePlantingPortions, teamPrePlantingPortions
- user-detail.controller 并行调用获取预种统计
- user.controller 批量获取用户列表预种统计
- UserListItemDto 新增 selfPrePlantingPortions, teamPrePlantingPortions
- pre-planting-config.controller 新增 teamOf 查询参数
→ 先从 referralQueryView 获取团队成员列表
→ 将 accountSequences 传递给 planting-service 过滤
planting-service:
- internal-pre-planting.controller 的 admin orders/positions 端点
新增 accountSequences 查询参数,支持按用户列表过滤
### 前端变更
admin-web:
- 用户列表页表格新增"个人预种(份)"、"团队预种(份)"两列
- 用户详情页新增预种统计卡片(个人/团队预种份数)
- 团队预种数字可点击,跳转 /pre-planting?teamOf={accountSequence}
- 预种管理页支持 teamOf URL 参数,团队过滤模式下显示提示条+返回链接
---
## 功能8:授权管理查看申请照片
### 需求
管理后台无法查看社区/市公司/省公司申请时提供的办公室照片。
原因:authorization-service 收到 officePhotoUrls 后只验证未持久化。
照片文件本身已存储在 MinIO,只需持久化 URL 到数据库。
### 后端变更
authorization-service:
- schema.prisma: AuthorizationRole 新增 officePhotoUrls String[] 字段
- authorization-role.aggregate: props/字段/getter/构造/toPersistence/所有工厂方法
- repository: save() create/update 块 + toDomain() 映射
- application service: 3个 self-apply 方法传递 officePhotoUrls 到 aggregate
- admin controller: queryAuthorizations 响应包含 officePhotoUrls
admin-service:
- schema.prisma: AuthorizationRoleQueryView 新增 officePhotoUrls 字段
- user-detail-query.repository 接口 + impl: 包含 officePhotoUrls
- user-detail.dto: AuthorizationRoleDto 新增 officePhotoUrls
### 前端变更
admin-web:
- 授权管理页表格新增"申请照片"列,点击弹出照片网格 Modal
- 照片支持点击放大(全屏 lightbox 覆盖层)
- 用户详情页授权信息 Tab 同样支持查看照片
- authorization.types.ts / userDetail.types.ts 类型更新
---
## 部署注意事项
1. authorization-service 需运行: npx prisma migrate dev --name add-office-photo-urls
2. admin-service 需运行: npx prisma migrate dev --name add-auth-role-office-photos
3. 需部署: authorization-service, admin-service, referral-service, planting-service, admin-web
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 03:09:17 -08:00
hailin
0cd0bd5694
fix(transfer): Outbox 配置值 Number() 转型,修复 Prisma take 参数类型错误
...
环境变量读取的值始终是 string,ConfigService.get<number> 不会自动转型,
导致 Prisma findMany({ take: "100" }) 报 String 类型错误。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:55:51 -08:00
hailin
5110915aa8
feat(transfer): 添加 transfer-service 初始数据库 migration
...
基于 schema.prisma 创建初始 migration SQL,包含:
- transfer_orders: 转让订单表(Saga 聚合根)
- transfer_status_logs: 状态变更审计日志
- outbox_events: Outbox Pattern 事件表
- processed_events: 幂等性保证表
容器启动时 Dockerfile 会自动执行 prisma migrate deploy 建表。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:16:28 -08:00
hailin
b3984c861c
feat(pre-planting): 预种方案调整 — 18870 USDT/棵,10份合1树
...
=== 方案变更 ===
- 全树基础价: 17830 → 18870 USDT
- 每份价格: 3566 → 1887 USDT
- 合并阈值: 5 份 → 10 份
=== 后端改动 (planting-service) ===
1. pre-planting-right-amounts.ts:
- PRE_PLANTING_PRICE_PER_PORTION: 3566 → 1887
- PRE_PLANTING_PORTIONS_PER_TREE: 5 → 10
- 10类权益金额按 floor(整棵树/10) 重算,余数归 HQ_BASE_FEE(319)
2. pre-planting-merge.aggregate.ts:
- 合并校验从硬编码 5 改为引用 PRE_PLANTING_PORTIONS_PER_TREE 常量
3. purchase-pre-planting.dto.ts:
- portionCount @Max(5) → @Max(10)
4. pre-planting-application.service.ts:
- 加价补贴计算 /5 → /PRE_PLANTING_PORTIONS_PER_TREE
- 错误文案引用常量,消除硬编码
=== 前端改动 (mobile-app) ===
1. pre_planting_purchase_page.dart: 默认价格、份数、协议文本(1/10、4%)
2. pre_planting_position_page.dart: _portionsPerTree 5→10
3. pre_planting_merge_detail_page.dart: 总价值计算和单份显示金额
4. tree_pricing_service.dart: fallback 默认值
5. pre_planting_service.dart: JSON 解析 fallback 默认值
6. 各文件注释同步更新
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:32:32 -08:00
hailin
28cf0b7769
fix(wallet): settleUserPendingRewards 补创建 REWARD_TO_SETTLEABLE 流水
...
转换 PENDING→SETTLEABLE 时,为每笔奖励创建带来源信息的
REWARD_TO_SETTLEABLE 流水,解决"分享收益"筛选缺失问题。
统计排除逻辑同步更新,通过 convertedFromPending 标记避免双重计算。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:15:19 -08:00
hailin
fda79304c6
Revert "fix(ledger): 分享收益筛选支持多类型(REWARD_TO_SETTLEABLE + REWARD_PENDING)"
...
This reverts commit d223671db7 .
2026-03-01 11:07:19 -08:00
hailin
d223671db7
fix(ledger): 分享收益筛选支持多类型(REWARD_TO_SETTLEABLE + REWARD_PENDING)
...
后端 entryType 筛选支持逗号分隔多值,前端"分享收益"同时查询两种类型,
解决未认种时收到的 REWARD_PENDING 分享权益在筛选中丢失的问题。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:02:08 -08:00
hailin
e4a2a0e37a
feat(ledger): 流水明细显示来源用户ID + 统计兼容历史批量转换数据
...
- wallet_service.dart: LedgerEntry 新增 sourceAccountFromMemo 从 memo 提取来源用户
- ledger_detail_page.dart: 流水列表项显示"来自 Dxxx"金色文字
- ledger_detail_page.dart: 权益详情弹窗添加来源用户行和备注行
- wallet-application.service.ts: 统计/趋势保留 memo 兼容历史批量转换记录
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:41:11 -08:00
hailin
d876dd1591
fix(wallet): 区分直接入账和批量转换的 REWARD_TO_SETTLEABLE
...
新增 REWARD_PENDING_CONVERTED 类型用于批量转换(待领取→可结算),
REWARD_TO_SETTLEABLE 保留给直接入账(hasPlanted=true时的新收入)。
统计排除:REWARD_PENDING_CONVERTED + REWARD_SETTLED(状态转换)
统计计入:REWARD_PENDING + REWARD_TO_SETTLEABLE(首次入账)
已迁移7条历史数据的 entry_type。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:30:47 -08:00
hailin
eba125901c
fix(wallet): 统计排除 REWARD_SETTLED 避免三重计入
...
奖励流水三阶段 REWARD_PENDING → REWARD_TO_SETTLEABLE → REWARD_SETTLED
是同一笔钱的状态转换,只在 REWARD_PENDING 阶段计入收入。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:07:22 -08:00
hailin
b905e8cb23
fix(wallet): 统计概览排除 REWARD_TO_SETTLEABLE 避免重复计入
...
REWARD_PENDING(入账) 和 REWARD_TO_SETTLEABLE(状态转换) 是同一笔收入
的两个阶段,统计时只应计入 REWARD_PENDING,排除 REWARD_TO_SETTLEABLE。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:01:36 -08:00