## 功能概述
在不影响任何现有业务的前提下,新增"强制阅读弹窗"功能:
- 管理员创建通知时可勾选「需要强制弹窗阅读」
- App 冷启动进入主页 或 从后台切回前台时自动触发检查
- 存在未读且标记 requiresForceRead=true 的通知时,依次逐条弹窗
- 用户无法通过点击背景或返回键关闭弹窗(强制阅读)
- 最后一条通知弹窗底部显示 checkbox「我已经阅读并知晓」
- 未勾选时"确定"按钮置灰禁用
- 勾选后"确定"变为金色可点击,点击后所有弹窗消失
- 全部看完后仅对已展示的强制阅读通知按 ID 逐一标记已读
(不影响普通未读通知的 badge 计数)
## 涉及改动
### 后端 admin-service
- `prisma/schema.prisma`
- Notification 模型新增字段 `requiresForceRead Boolean @default(false)`
- `prisma/migrations/20260227100000_add_requires_force_read_to_notifications/migration.sql`
- 手动创建 SQL migration(本地无 DATABASE_URL 环境)
- 部署时需在服务器执行 `npx prisma migrate deploy`
- `src/domain/entities/notification.entity.ts`
- 实体类构造器新增 `requiresForceRead`
- create() / update() 方法均支持该字段,默认值 false
- `src/infrastructure/persistence/mappers/notification.mapper.ts`
- toDomain() 从 Prisma 记录读取 requiresForceRead
- toPersistence() 写入 requiresForceRead
- `src/api/dto/request/notification.dto.ts`
- CreateNotificationDto / UpdateNotificationDto 各新增可选字段 requiresForceRead
- `src/api/dto/response/notification.dto.ts`
- NotificationResponseDto(管理端)新增 requiresForceRead
- UserNotificationResponseDto(移动端)新增 requiresForceRead
- `src/api/controllers/notification.controller.ts`
- create() / update() 透传 requiresForceRead 到 entity
### 前端 admin-web
- `src/services/notificationService.ts`
- NotificationItem / CreateNotificationRequest / UpdateNotificationRequest 新增 requiresForceRead
- `src/app/(dashboard)/notifications/page.tsx`
- 通知列表:requiresForceRead=true 时显示红色「强制阅读」标签
- 创建/编辑表单:新增 checkbox「需要强制弹窗阅读」及说明文字
- form state / submit payload / edit 初始化均包含 requiresForceRead
### 移动端 mobile-app
- `lib/core/services/notification_service.dart`
- NotificationItem 新增字段 requiresForceRead(默认 false,fromJson 安全读取)
- `lib/features/notification/presentation/pages/notification_inbox_page.dart`
- markAsRead / markAllAsRead 重建 NotificationItem 时保留 requiresForceRead
- `lib/features/notification/presentation/widgets/force_read_notification_dialog.dart`(新建)
- 单条强制阅读弹窗组件
- 顶部显示通知类型图标 + 进度「1/3」
- 可滚动内容区展示完整通知
- 非最后条:「下一条 ▶」按钮(始终可点)
- 最后一条:checkbox + 「确定」(勾选后才可点)
- barrierDismissible: false + PopScope(canPop: false),无法逃出
- `lib/features/home/presentation/pages/home_shell_page.dart`
- 新增状态:_isShowingForceReadDialog(实例,防重入)
_lastForceReadDialogShownAt(静态,60秒冷却)
- 新增方法 _checkAndShowForceReadDialog():
Guard 1: 防重入锁
Guard 2: 60秒冷却(防回前台闪弹)
Guard 3: 检查用户已登录
Guard 4: 检查无其他弹窗在显示
弹窗期间同时设置 _isShowingDialog=true,阻止后台合同/KYC检查并发
全部看完后仅标记 forceReadList 中的通知为已读,再 refresh() 刷新 badge
- initState addPostFrameCallback 中新增调用
- didChangeAppLifecycleState resumed 分支中新增调用
- resetContractCheckState() 中重置 _lastForceReadDialogShownAt(账号切换隔离)
## 安全与兼容性
- API 调用失败时静默返回,不阻断用户进入 App
- 仅对 requiresForceRead=true 的通知弹窗,普通通知完全不受影响
- 与现有合同弹窗、KYC弹窗、维护弹窗、更新弹窗无冲突
- 静态冷却变量在账号切换时重置,避免新账号被旧账号冷却影响
- badge 准确:仅标记已展示的强制通知,不动其他未读通知计数
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| nginx | ||
| public | ||
| scripts | ||
| src | ||
| .dockerignore | ||
| .env.development | ||
| .env.production | ||
| .eslintrc.json | ||
| .gitignore | ||
| .prettierrc | ||
| Dockerfile | ||
| README.md | ||
| deploy.sh | ||
| docker-compose.yml | ||
| next.config.ts | ||
| package-lock.json | ||
| package.json | ||
| tsconfig.json | ||
README.md
RWADurian Admin Web
榴莲认种管理后台 - Next.js 15 + TypeScript + SCSS
技术栈
- 框架: Next.js 15 (App Router)
- 语言: TypeScript
- 样式: SCSS Modules
- 状态管理: Redux Toolkit + Zustand
- UI 组件: Recharts (图表)
- 部署: Docker + Nginx
本地开发
环境要求
- Node.js 20+
- npm 或 yarn
安装依赖
npm install
启动开发服务器
npm run dev
构建
npm run build
npm start
Docker 部署
快速部署 (推荐)
项目已配置 Docker 一键部署方案,使用 Git 管理代码。
在服务器上部署:
# 1. 克隆项目 (首次)
git clone <repository-url>
cd rwadurian/frontend/admin-web
# 2. 或更新代码 (已有项目)
cd ~/rwadurian/frontend/admin-web
git pull
# 3. 赋予脚本执行权限
chmod +x scripts/*.sh deploy.sh nginx/*.sh
# 4. 一键部署 Docker 应用
./scripts/deploy.sh
# 5. 安装 Nginx + SSL (首次需要)
sudo ./nginx/install.sh
Docker 管理脚本
| 脚本 | 功能 |
|---|---|
./scripts/deploy.sh |
一键部署 (构建+启动) |
./scripts/build.sh |
仅构建镜像 |
./scripts/start.sh |
启动服务 |
./scripts/stop.sh |
停止服务 |
./scripts/restart.sh |
重启服务 |
./scripts/logs.sh |
查看实时日志 |
./scripts/status.sh |
查看服务状态 |
./scripts/health.sh |
健康检查 |
./scripts/clean.sh |
清理容器和镜像 |
使用原始 deploy.sh
# 启动服务
./deploy.sh start
# 停止服务
./deploy.sh stop
# 重启服务
./deploy.sh restart
# 查看日志
./deploy.sh logs
# 查看状态
./deploy.sh status
# 清理
./deploy.sh clean
自定义端口
PORT=8080 ./scripts/deploy.sh
Nginx 配置
前提条件
- 域名 DNS A 记录已指向服务器 IP
- 防火墙开放 80 和 443 端口
- Docker 应用已在 3000 端口运行
一键安装 (推荐)
cd nginx
sudo ./install.sh
脚本会自动完成:
- 系统更新
- 安装 Nginx
- 安装 Certbot
- 配置防火墙
- 申请 Let's Encrypt SSL 证书
- 配置 HTTPS 反向代理
手动配置
项目结构
admin-web/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── (auth)/ # 认证相关页面 (登录、注册)
│ │ ├── (dashboard)/ # 仪表板页面
│ │ └── api/ # API 路由
│ ├── components/ # React 组件
│ │ ├── common/ # 通用组件
│ │ ├── features/ # 功能组件
│ │ └── layout/ # 布局组件
│ ├── store/ # 状态管理
│ │ ├── redux/ # Redux Toolkit
│ │ └── zustand/ # Zustand stores
│ ├── services/ # API 服务
│ ├── utils/ # 工具函数
│ └── styles/ # 全局样式
├── public/ # 静态资源
├── nginx/ # Nginx 配置
│ ├── README.md # Nginx 部署文档
│ ├── install.sh # 一键安装脚本
│ ├── setup-ssl.sh # SSL 配置脚本
│ └── rwaadmin.szaiai.com.conf # Nginx 站点配置
├── scripts/ # Docker 管理脚本
├── Dockerfile # Docker 镜像构建
├── docker-compose.yml # Docker 编排
├── deploy.sh # 部署脚本
└── README.md # 本文档
环境变量
项目使用不同的环境配置文件:
.env.local- 本地开发.env.development- 开发环境.env.production- 生产环境
功能特性
- ✅ 用户管理
- ✅ 排行榜
- ✅ 权限管理
- ✅ 数据统计
- ✅ 系统设置
- ✅ 帮助中心
- ✅ 侧边栏收起/展开
- ✅ 响应式布局
- ✅ 健康检查 API
API 端点
GET /api/health- 健康检查
访问地址
- 本地开发: http://localhost:3000
- 生产环境: https://rwaadmin.szaiai.com
常见问题
1. Docker 构建失败
确保本地有 .next 和 node_modules 已添加到 .dockerignore
2. 502 Bad Gateway
检查 Docker 容器是否运行:
docker ps
./scripts/status.sh
3. SSL 证书申请失败
- 确认域名 DNS 解析正确
- 确认 80 端口可访问
- 查看错误日志:
sudo tail -f /var/log/letsencrypt/letsencrypt.log
许可证
MIT