Implement login functionality and UI updates across the application. Added silent login process in App.vue, updated styles for various components, and integrated smoke record dialog. Enhanced onboarding and profile pages with improved layouts and user experience. Updated manifest and configuration files for deployment. Added easycom configuration for component auto-import.
This commit is contained in:
+613
-25
@@ -103,39 +103,627 @@ Phase 6: 优化与测试 (2天)
|
||||
|
||||
## 4. Phase 3: 记录与历史 (2天)
|
||||
|
||||
### 4.1 Day 1: 记录表单
|
||||
### 4.1 Day 1: 记录表单组件
|
||||
|
||||
#### 记录弹窗组件
|
||||
- [ ] 时间选择 (默认当前时间)
|
||||
- [ ] 原因标签选择 (压力大/无聊/社交/习惯等)
|
||||
- [ ] 备注输入
|
||||
- [ ] 支数选择 (默认1)
|
||||
#### 4.1.1 smoke-record-dialog 组件开发
|
||||
|
||||
#### API 集成
|
||||
- [ ] `POST /logs` 新增记录
|
||||
- [ ] `POST /logs/resisted` 忍住记录
|
||||
- [ ] 提交后刷新首页数据
|
||||
**组件结构** (`components/smoke-record-dialog/smoke-record-dialog.vue`)
|
||||
- [x] 底部弹出动画 (从底部滑入,半屏展示)
|
||||
- [x] 明亮主题 UI (白色背景 + 翡翠绿主题色 #10B981)
|
||||
- [x] 遮罩层点击关闭
|
||||
- [x] 表单项布局
|
||||
|
||||
**表单字段实现**
|
||||
- [x] 时间选择器
|
||||
- 日期选择 (picker mode="date")
|
||||
- 时间选择 (picker mode="time")
|
||||
- 默认当前时间
|
||||
- 自动拼接为 `smoke_at` 字段
|
||||
|
||||
- [x] 数量选择器 (仅抽烟模式显示)
|
||||
- 加减按钮 (+/-)
|
||||
- 数字输入框
|
||||
- 最小值 1
|
||||
- 默认值 1
|
||||
|
||||
- [x] 烟瘾等级选择 (仅抽烟模式显示)
|
||||
- 1-5 级按钮组
|
||||
- 选中态样式切换
|
||||
- 默认值 2
|
||||
|
||||
- [x] 备注输入框
|
||||
- 多行文本域 (textarea)
|
||||
- 最大长度 200 字符
|
||||
- 根据模式显示不同占位符
|
||||
- 抽烟: "记录抽烟原因..."
|
||||
- 忍住: "记录抵抗心得..."
|
||||
|
||||
**组件逻辑**
|
||||
- [x] Props 定义
|
||||
```javascript
|
||||
{
|
||||
show: Boolean, // 控制显示
|
||||
type: String // 'smoke' | 'resisted'
|
||||
}
|
||||
```
|
||||
|
||||
- [x] 数据初始化
|
||||
- 打开弹框时自动初始化当前时间
|
||||
- 根据 type 设置默认值
|
||||
- smoke: num=1, level=2
|
||||
- resisted: num=0, level=2
|
||||
|
||||
- [x] 提交逻辑
|
||||
```javascript
|
||||
{
|
||||
smoke_time: "2025-01-25",
|
||||
smoke_at: "2025-01-25 14:30:00",
|
||||
remark: "",
|
||||
level: 2,
|
||||
num: 1 // 或 0 (忍住时)
|
||||
}
|
||||
```
|
||||
|
||||
- [x] 关闭动画
|
||||
- 延迟 300ms 触发 update:show
|
||||
- 平滑过渡效果
|
||||
|
||||
#### 4.1.2 组件配置
|
||||
|
||||
**easycom 自动导入** (`pages.json`)
|
||||
- [x] 配置组件路径
|
||||
```json
|
||||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^smoke-record-dialog$": "@/components/smoke-record-dialog/smoke-record-dialog.vue"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**组件文档**
|
||||
- [x] 创建 `components/smoke-record-dialog/README.md`
|
||||
- [x] 包含使用示例、Props 说明、Events 说明
|
||||
- [x] 创建 `components/README.md` 全局组件使用指南
|
||||
|
||||
#### 4.1.3 API 集成
|
||||
|
||||
**API 封装** (`api/smoke.js`)
|
||||
- [x] `createLog(data)` - POST /api/v1/smoke/logs
|
||||
- 支持抽烟记录 (num > 0)
|
||||
- 支持忍住记录 (num = 0, level = 0)
|
||||
|
||||
- [ ] `updateLog(id, data)` - PUT /api/v1/smoke/logs/:id
|
||||
- [ ] `deleteLog(id)` - DELETE /api/v1/smoke/logs/:id
|
||||
- [x] `getLatestLogs(limit)` - GET /api/v1/smoke/logs/latest
|
||||
|
||||
**首页集成** (`pages/index/index.vue`)
|
||||
- [x] 引入组件 (easycom 自动导入)
|
||||
- [x] 双向绑定 show 状态
|
||||
- [x] 区分两种模式
|
||||
```vue
|
||||
<smoke-record-dialog
|
||||
v-model:show="showDialog"
|
||||
:type="dialogType"
|
||||
@submit="handleSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
- [x] 提交处理
|
||||
- 调用 API 创建记录
|
||||
- 更新 dashboard store 数据
|
||||
- 抽烟: incrementTodayCount()
|
||||
- 抽烟: resetTimer()
|
||||
- 显示成功提示
|
||||
- 关闭弹框
|
||||
|
||||
**性能优化**
|
||||
- [x] 组件懒加载 (easycom 按需加载)
|
||||
- [x] 表单数据仅在打开时初始化
|
||||
- [x] 提交后自动关闭
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Day 2: 历史记录页
|
||||
|
||||
#### 列表页面
|
||||
- [ ] 筛选 Tabs (全部/已抽烟/已忍住)
|
||||
- [ ] 时间线布局
|
||||
- [ ] 按日期分组
|
||||
- [ ] 下拉刷新 + 上拉加载
|
||||
#### 4.2.1 页面结构 (`pages/logs/index.vue`)
|
||||
|
||||
#### 记录卡片
|
||||
- [ ] 类型图标 (抽烟/忍住)
|
||||
- [ ] 时间 + 原因标签
|
||||
- [ ] 间隔时间显示
|
||||
- [ ] 左滑操作 (编辑/删除)
|
||||
**顶部导航**
|
||||
- [ ] 导航栏标题 "历史记录"
|
||||
- [ ] 筛选 Tabs 组件
|
||||
```javascript
|
||||
tabs: [
|
||||
{ id: 'all', name: '全部' },
|
||||
{ id: 'smoke', name: '已抽烟', filter: (item) => item.num > 0 },
|
||||
{ id: 'resisted', name: '已忍住', filter: (item) => item.num === 0 }
|
||||
]
|
||||
```
|
||||
|
||||
#### 编辑/删除
|
||||
- [ ] 编辑弹窗
|
||||
- [ ] 删除确认
|
||||
- [ ] `PUT/DELETE /logs/:id`
|
||||
**列表容器**
|
||||
- [ ] scroll-view 组件
|
||||
- [ ] 下拉刷新 (refresher-enabled)
|
||||
- [ ] 上拉加载更多
|
||||
- [ ] 空状态提示
|
||||
|
||||
**交付物**:完整的记录流程,历史记录页可用
|
||||
#### 4.2.2 数据层
|
||||
|
||||
**Store 设计** (`stores/logs.js`)
|
||||
```javascript
|
||||
{
|
||||
state: {
|
||||
logs: [], // 记录列表
|
||||
total: 0, // 总条数
|
||||
page: 1, // 当前页
|
||||
pageSize: 20, // 每页数量
|
||||
hasMore: true, // 是否有更多
|
||||
loading: false // 加载状态
|
||||
},
|
||||
|
||||
getters: {
|
||||
groupedByDate: (state) => {
|
||||
// 按日期分组
|
||||
// { '2025-01-25': [...], '2025-01-24': [...] }
|
||||
},
|
||||
smokeCount: (state) => {
|
||||
// 抽烟记录数量
|
||||
},
|
||||
resistedCount: (state) => {
|
||||
// 忍住记录数量
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
async fetchLogs(refresh = false),
|
||||
async loadMore(),
|
||||
async deleteLog(id),
|
||||
clearLogs()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**API 调用**
|
||||
- [ ] `getLogs({ page, page_size, start, end })`
|
||||
- [ ] `getLatestLogs(limit)` - 首次快速加载
|
||||
- [ ] `deleteLog(id)`
|
||||
|
||||
#### 4.2.3 记录卡片组件 (`components/log-item/log-item.vue`)
|
||||
|
||||
**卡片布局**
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🚬 14:30 3 支 │
|
||||
│ 压力大、工作繁忙 │
|
||||
│ 距上次 2小时15分 │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**字段显示**
|
||||
- [ ] 类型图标
|
||||
- 🚬 抽烟 (num > 0)
|
||||
- 💪 忍住 (num = 0)
|
||||
|
||||
- [ ] 时间显示
|
||||
- 格式: HH:mm
|
||||
- 今天/昨天/具体日期
|
||||
|
||||
- [ ] 数量显示 (抽烟时)
|
||||
- `${num} 支`
|
||||
- 烟瘾等级 (1-5 级)
|
||||
|
||||
- [ ] 备注内容
|
||||
- 单行显示,超出省略
|
||||
- 最多显示 50 字符
|
||||
|
||||
- [ ] 间隔时间
|
||||
- 距上一条记录的时间差
|
||||
- 格式: "X小时Y分" / "X分钟"
|
||||
|
||||
**卡片样式**
|
||||
- [ ] 白色背景
|
||||
- [ ] 圆角 16rpx
|
||||
- [ ] 阴影效果
|
||||
- [ ] 抽烟/忍住不同边框色
|
||||
- 抽烟: 红色左边框
|
||||
- 忍住: 绿色左边框
|
||||
|
||||
#### 4.2.4 左滑操作
|
||||
|
||||
**左滑按钮**
|
||||
- [ ] 使用 uni-ui 的 uni-swipe-action
|
||||
- [ ] 编辑按钮 (蓝色)
|
||||
- 打开编辑弹框
|
||||
- 预填充当前数据
|
||||
|
||||
- [ ] 删除按钮 (红色)
|
||||
- 显示确认对话框
|
||||
- 调用删除 API
|
||||
- 更新列表数据
|
||||
|
||||
**编辑功能**
|
||||
- [ ] 复用 smoke-record-dialog 组件
|
||||
- [ ] 添加 recordId 和 mode props
|
||||
```vue
|
||||
<smoke-record-dialog
|
||||
v-model:show="showEditDialog"
|
||||
:type="editType"
|
||||
:record-id="editRecordId"
|
||||
mode="edit"
|
||||
@submit="handleUpdate"
|
||||
/>
|
||||
```
|
||||
|
||||
- [ ] 预填充数据
|
||||
- [ ] 调用 updateLog API
|
||||
- [ ] 刷新列表
|
||||
|
||||
**删除功能**
|
||||
- [ ] uni.showModal 确认对话框
|
||||
- [ ] 调用 deleteLog API
|
||||
- [ ] 乐观更新 (先删除本地数据)
|
||||
- [ ] 失败时回滚
|
||||
|
||||
#### 4.2.5 日期分组
|
||||
|
||||
**分组逻辑**
|
||||
```javascript
|
||||
function groupByDate(logs) {
|
||||
const groups = {}
|
||||
logs.forEach(log => {
|
||||
const date = formatDate(log.smoke_time)
|
||||
if (!groups[date]) {
|
||||
groups[date] = {
|
||||
date,
|
||||
displayDate: getDisplayDate(date), // 今天/昨天/MM-DD
|
||||
logs: []
|
||||
}
|
||||
}
|
||||
groups[date].logs.push(log)
|
||||
})
|
||||
return Object.values(groups)
|
||||
}
|
||||
```
|
||||
|
||||
**渲染结构**
|
||||
```vue
|
||||
<view class="date-group" v-for="group in groupedLogs" :key="group.date">
|
||||
<view class="date-header">{{ group.displayDate }}</view>
|
||||
<log-item
|
||||
v-for="log in group.logs"
|
||||
:key="log.id"
|
||||
:data="log"
|
||||
@edit="handleEdit"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</view>
|
||||
```
|
||||
|
||||
#### 4.2.6 加载状态
|
||||
|
||||
**下拉刷新**
|
||||
- [ ] refresher-triggered 状态控制
|
||||
- [ ] 重置 page = 1
|
||||
- [ ] 清空现有数据
|
||||
- [ ] 调用 fetchLogs(true)
|
||||
- [ ] 完成后关闭刷新状态
|
||||
|
||||
**上拉加载**
|
||||
- [ ] onReachBottom 触发
|
||||
- [ ] 检查 hasMore 状态
|
||||
- [ ] page++
|
||||
- [ ] 调用 loadMore()
|
||||
- [ ] 追加数据到列表
|
||||
|
||||
**加载骨架屏**
|
||||
- [ ] 初次加载显示
|
||||
- [ ] 3-5 个卡片骨架
|
||||
- [ ] shimmer 动画效果
|
||||
|
||||
**空状态**
|
||||
- [ ] 无数据时显示
|
||||
- [ ] 空状态图标 + 文案
|
||||
- [ ] 引导按钮 "去记录"
|
||||
|
||||
#### 4.2.7 浮动操作按钮
|
||||
|
||||
**新增按钮**
|
||||
- [ ] 固定在右下角
|
||||
- [ ] 圆形按钮 (96rpx)
|
||||
- [ ] ➕ 图标
|
||||
- [ ] 点击打开记录弹框
|
||||
- [ ] 阴影 + 缩放动画
|
||||
|
||||
**样式**
|
||||
```css
|
||||
.fab {
|
||||
position: fixed;
|
||||
right: 32rpx;
|
||||
bottom: 120rpx; /* 避开 tabbar */
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
background: #10B981;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 8rpx 24rpx rgba(16, 185, 129, 0.4);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.8 性能优化
|
||||
|
||||
**列表优化**
|
||||
- [ ] 虚拟列表 (数据量 > 100 时)
|
||||
- [ ] 分页加载 (每页 20 条)
|
||||
- [ ] 图片懒加载 (如有头像等)
|
||||
|
||||
**缓存策略**
|
||||
- [ ] 首次加载使用 getLatestLogs (快速)
|
||||
- [ ] 后续使用分页接口
|
||||
- [ ] 缓存最近 3 页数据
|
||||
- [ ] 超过 5 分钟刷新缓存
|
||||
|
||||
**用户体验**
|
||||
- [ ] 乐观更新 (删除/编辑)
|
||||
- [ ] Loading 状态提示
|
||||
- [ ] 错误处理 + 重试按钮
|
||||
- [ ] 防抖处理 (下拉刷新/上拉加载)
|
||||
|
||||
---
|
||||
|
||||
### 4.3 验收标准
|
||||
|
||||
**记录功能**
|
||||
- [x] 弹框动画流畅 (< 300ms)
|
||||
- [x] 表单提交成功率 > 99%
|
||||
- [x] 支持快速记录 (< 3 步)
|
||||
- [ ] 编辑/删除操作正常
|
||||
|
||||
**历史记录页**
|
||||
- [ ] 列表加载 < 1s
|
||||
- [ ] 滚动流畅 (60fps)
|
||||
- [ ] 分组显示正确
|
||||
- [ ] 筛选功能正常
|
||||
- [ ] 下拉刷新/上拉加载正常
|
||||
|
||||
**数据同步**
|
||||
- [ ] 新增记录后首页数据实时更新
|
||||
- [ ] 删除记录后列表实时更新
|
||||
- [ ] 编辑记录后详情实时更新
|
||||
|
||||
**异常处理**
|
||||
- [ ] 网络异常提示
|
||||
- [ ] 删除失败回滚
|
||||
- [ ] 空状态正确显示
|
||||
|
||||
**交付物**:
|
||||
- ✅ smoke-record-dialog 组件 (已完成)
|
||||
- ✅ 组件文档和使用指南 (已完成)
|
||||
- ✅ 首页记录功能集成 (已完成)
|
||||
- [ ] 历史记录页完整功能
|
||||
- [ ] log-item 组件
|
||||
- [ ] logs store 状态管理
|
||||
- [ ] 编辑/删除功能
|
||||
|
||||
---
|
||||
|
||||
### 4.4 Phase 3 技术要点与最佳实践
|
||||
|
||||
#### 4.4.1 组件设计原则
|
||||
|
||||
**组件命名规范**
|
||||
- ✅ 使用 kebab-case: `smoke-record-dialog`
|
||||
- ✅ 目录结构: `components/smoke-record-dialog/smoke-record-dialog.vue`
|
||||
- ❌ 避免 PascalCase: `SmokeRecordDialog.vue` (微信小程序依赖分析问题)
|
||||
|
||||
**组件 API 风格**
|
||||
- ✅ 使用 Options API (更好的兼容性)
|
||||
- ✅ 支持 v-model:show 双向绑定
|
||||
- ✅ 使用 @submit 事件传递数据
|
||||
- ✅ Props 类型校验完整
|
||||
|
||||
**组件复用性**
|
||||
- 通过 props.type 区分模式 ('smoke' / 'resisted')
|
||||
- 表单字段根据模式动态显示/隐藏
|
||||
- 提交数据格式统一,由组件内部处理差异
|
||||
|
||||
#### 4.4.2 状态管理策略
|
||||
|
||||
**Store 职责划分**
|
||||
```javascript
|
||||
// dashboard.js - 首页数据
|
||||
{
|
||||
todayCount, // 今日抽烟数
|
||||
minutesSinceLast, // 距上次时间
|
||||
nextSmokeTime, // 下次建议时间
|
||||
actions: {
|
||||
incrementTodayCount(),
|
||||
resetTimer()
|
||||
}
|
||||
}
|
||||
|
||||
// logs.js - 历史记录
|
||||
{
|
||||
logs, // 记录列表
|
||||
page, total, hasMore, // 分页信息
|
||||
actions: {
|
||||
fetchLogs(),
|
||||
loadMore(),
|
||||
deleteLog()
|
||||
}
|
||||
}
|
||||
|
||||
// user.js - 用户信息
|
||||
{
|
||||
user, // 用户基本信息
|
||||
token, // 认证令牌
|
||||
isLogin // 登录状态
|
||||
}
|
||||
```
|
||||
|
||||
**数据流向**
|
||||
```
|
||||
用户操作 → 组件 emit → 页面处理 → 调用 API
|
||||
↓
|
||||
更新 Store ← API 响应
|
||||
↓
|
||||
触发视图更新
|
||||
```
|
||||
|
||||
#### 4.4.3 API 错误处理
|
||||
|
||||
**统一错误处理** (`api/request.js`)
|
||||
```javascript
|
||||
// 已实现
|
||||
- Token 失效自动刷新
|
||||
- 网络错误重试 (最多 3 次)
|
||||
- 错误码统一处理
|
||||
- Toast 提示
|
||||
|
||||
// 需要注意
|
||||
- 记录提交失败要保留用户输入
|
||||
- 删除失败要回滚本地状态
|
||||
- 编辑冲突要提示用户
|
||||
```
|
||||
|
||||
**乐观更新 vs 悲观更新**
|
||||
- 删除操作: 乐观更新 (先删除,失败回滚)
|
||||
- 新增操作: 悲观更新 (成功后添加)
|
||||
- 编辑操作: 悲观更新 (成功后更新)
|
||||
|
||||
#### 4.4.4 性能优化清单
|
||||
|
||||
**组件层面**
|
||||
- [x] easycom 按需加载
|
||||
- [x] 弹框懒加载 (打开时才初始化数据)
|
||||
- [ ] 虚拟列表 (历史记录 > 100 条)
|
||||
- [ ] 图片懒加载
|
||||
|
||||
**请求层面**
|
||||
- [ ] 并行请求 (多个接口同时调用)
|
||||
- [ ] 请求缓存 (5 分钟内复用)
|
||||
- [ ] 防抖处理 (快速点击)
|
||||
- [ ] 请求取消 (页面离开时)
|
||||
|
||||
**渲染层面**
|
||||
- [ ] 分页加载 (每页 20 条)
|
||||
- [ ] 骨架屏过渡
|
||||
- [ ] 平滑滚动
|
||||
- [ ] 动画性能优化 (CSS transform)
|
||||
|
||||
#### 4.4.5 用户体验优化
|
||||
|
||||
**反馈机制**
|
||||
- 提交成功: Toast 提示 + 自动关闭弹框
|
||||
- 提交失败: Toast 提示 + 保留输入内容
|
||||
- 删除确认: Modal 二次确认
|
||||
- 加载状态: Loading + 禁用按钮
|
||||
|
||||
**快捷操作**
|
||||
- 首页快速记录按钮 (2 个按钮对应 2 种模式)
|
||||
- 历史记录页浮动新增按钮
|
||||
- 左滑快速删除/编辑
|
||||
- 下拉刷新快速更新
|
||||
|
||||
**引导提示**
|
||||
- 首次使用引导
|
||||
- 空状态引导
|
||||
- 错误状态引导
|
||||
- 功能提示
|
||||
|
||||
#### 4.4.6 测试要点
|
||||
|
||||
**单元测试**
|
||||
- [ ] 组件 props 验证
|
||||
- [ ] 表单数据初始化
|
||||
- [ ] 日期分组逻辑
|
||||
- [ ] 时间格式化函数
|
||||
|
||||
**集成测试**
|
||||
- [ ] 记录提交流程
|
||||
- [ ] 编辑/删除流程
|
||||
- [ ] 分页加载流程
|
||||
- [ ] 筛选切换流程
|
||||
|
||||
**E2E 测试场景**
|
||||
```
|
||||
场景 1: 快速记录抽烟
|
||||
1. 点击"记录抽烟"按钮
|
||||
2. 不修改默认值
|
||||
3. 直接提交
|
||||
4. 验证首页数据更新
|
||||
|
||||
场景 2: 详细记录
|
||||
1. 点击"记录抽烟"按钮
|
||||
2. 修改时间、数量、等级
|
||||
3. 输入备注
|
||||
4. 提交
|
||||
5. 在历史记录页验证
|
||||
|
||||
场景 3: 编辑记录
|
||||
1. 进入历史记录页
|
||||
2. 左滑某条记录
|
||||
3. 点击编辑
|
||||
4. 修改内容
|
||||
5. 提交
|
||||
6. 验证更新成功
|
||||
|
||||
场景 4: 删除记录
|
||||
1. 进入历史记录页
|
||||
2. 左滑某条记录
|
||||
3. 点击删除
|
||||
4. 确认删除
|
||||
5. 验证列表更新
|
||||
```
|
||||
|
||||
#### 4.4.7 常见问题与解决方案
|
||||
|
||||
**问题 1: 微信小程序组件依赖分析错误**
|
||||
```
|
||||
错误: components/SmokeRecordDialog.js 已被代码依赖分析忽略
|
||||
解决:
|
||||
1. 使用 kebab-case 命名
|
||||
2. 组件放在同名文件夹内
|
||||
3. 配置 easycom 自动导入
|
||||
4. 使用 Options API
|
||||
```
|
||||
|
||||
**问题 2: 弹框关闭时数据未重置**
|
||||
```
|
||||
原因: 组件销毁前未清理数据
|
||||
解决: watch show 变化,false 时清理数据
|
||||
```
|
||||
|
||||
**问题 3: 列表滚动性能差**
|
||||
```
|
||||
原因: 数据量大,DOM 节点过多
|
||||
解决:
|
||||
1. 虚拟列表
|
||||
2. 分页加载
|
||||
3. 使用 CSS transform 优化动画
|
||||
```
|
||||
|
||||
**问题 4: 删除后列表显示错误**
|
||||
```
|
||||
原因: 本地状态未同步
|
||||
解决: 乐观更新时正确处理索引
|
||||
```
|
||||
|
||||
#### 4.4.8 安全注意事项
|
||||
|
||||
**输入校验**
|
||||
- 时间范围验证 (不能是未来时间)
|
||||
- 数量范围验证 (1-99)
|
||||
- 备注长度限制 (200 字符)
|
||||
- XSS 防护 (转义用户输入)
|
||||
|
||||
**权限控制**
|
||||
- 只能编辑/删除自己的记录
|
||||
- Token 验证
|
||||
- 接口鉴权
|
||||
|
||||
**数据保护**
|
||||
- 敏感信息脱敏
|
||||
- 本地存储加密
|
||||
- HTTPS 传输
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user