feat: batch update - gift card breakdown spec, backend APIs, miniprogram pages, ETL finance recharge, docs & migrations

This commit is contained in:
Neo
2026-03-20 01:43:48 +08:00
parent 075caf067f
commit 79f9a0e1da
437 changed files with 118603 additions and 976 deletions

View File

@@ -0,0 +1,220 @@
# Notes 页面删除功能实现说明
## 更新日期
2026-03-14
## 功能描述
为每条备注添加删除按钮,放置在日期左侧,交互和逻辑参考任务详情页的备注删除处理方式。
---
## 实现细节
### 1. WXML 结构调整
#### 原结构
```xml
<view class="note-bottom">
<text class="note-tag">{{item.tagLabel}}</text>
<text class="note-time">{{item.createdAt}}</text>
</view>
```
#### 新结构
```xml
<view class="note-bottom">
<view class="note-bottom-left">
<view class="note-delete-btn" catchtap="onDeleteNote" data-id="{{item.id}}" hover-class="note-delete-btn--hover">
<t-icon name="delete" size="20px" color="#a6a6a6" />
</view>
<text class="note-time">{{item.createdAt}}</text>
</view>
<text class="note-tag">{{item.tagLabel}}</text>
</view>
```
**关键点**
- 使用 `catchtap` 而非 `bindtap`,阻止事件冒泡
- 删除按钮放在左侧,日期紧随其后
- 标签移到右侧
- 通过 `data-id` 传递备注ID
### 2. WXSS 样式添加
```wxss
/* 底部容器布局调整 */
.note-bottom {
display: flex;
align-items: center;
justify-content: space-between;
}
/* 左侧容器(删除按钮 + 日期)*/
.note-bottom-left {
display: flex;
align-items: center;
gap: 8px;
}
/* 删除按钮样式 */
.note-delete-btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
flex-shrink: 0;
}
.note-delete-btn--hover {
background-color: #f3f3f3;
}
```
**样式说明**
- 删除按钮尺寸32px × 32px符合最小点击区域44px的80%
- Icon尺寸20px与H5原型对齐
- Icon颜色#a6a6a6gray-6次级文字颜色
- Hover效果浅灰背景#f3f3f3
- 按钮与日期间距8px
### 3. TypeScript 逻辑实现
```typescript
/** 删除备注 */
onDeleteNote(e: WechatMiniprogram.BaseEvent) {
const noteId = e.currentTarget.dataset.id as string
wx.showModal({
title: '删除备注',
content: '确定要删除这条备注吗?删除后无法恢复。',
confirmColor: '#e34d59',
success: (res) => {
if (res.confirm) {
const notes = this.data.notes.filter((n) => n.id !== noteId)
this.setData({ notes })
wx.showToast({ title: '已删除', icon: 'success' })
}
},
})
}
```
**逻辑说明**
-`dataset` 中获取备注ID
- 使用 `wx.showModal` 显示确认弹窗
- 确认按钮颜色:#e34d59error色警示作用
- 确认后过滤掉对应备注
- 显示成功提示
---
## 参考实现
### 任务详情页删除逻辑
位置:`apps/miniprogram/miniprogram/pages/task-detail/task-detail.ts`
```typescript
/** 删除备注 */
onDeleteNote(e: WechatMiniprogram.BaseEvent) {
const noteId = e.currentTarget.dataset.id as string
wx.showModal({
title: '删除备注',
content: '确定要删除这条备注吗?删除后无法恢复。',
confirmColor: '#e34d59',
success: (res) => {
if (res.confirm) {
const notes = this.data.sortedNotes.filter((n) => n.id !== noteId)
this.setData({ sortedNotes: notes })
wx.showToast({ title: '已删除', icon: 'success' })
}
},
})
}
```
**差异点**
- 任务详情页使用 `sortedNotes`notes页使用 `notes`
- 其他逻辑完全一致
---
## 交互流程
1. 用户点击删除按钮
2. 显示确认弹窗:"确定要删除这条备注吗?删除后无法恢复。"
3. 用户选择:
- **确认**:删除备注,显示"已删除"提示
- **取消**:关闭弹窗,不做任何操作
---
## 视觉效果
### 布局
```
┌─────────────────────────────────────────┐
│ 备注内容文本... │
│ │
│ [🗑️] 2024-11-27 16:00 [客户:王先生] │
└─────────────────────────────────────────┘
```
### 尺寸对比
| 元素 | 尺寸 | 说明 |
|------|------|------|
| 删除按钮容器 | 32px × 32px | 圆形点击区域 |
| 删除icon | 20px | TDesign delete图标 |
| 按钮与日期间距 | 8px | gap |
| 日期字号 | 12px | text-xs |
| 标签字号 | 12px | text-xs |
---
## 颜色规范
| 元素 | 颜色 | 色值 | 说明 |
|------|------|------|------|
| 删除icon | gray-6 | #a6a6a6 | 次级文字颜色 |
| Hover背景 | gray-1 | #f3f3f3 | 浅灰背景 |
| 确认按钮 | error | #e34d59 | 警示色 |
---
## 测试清单
- [x] 删除按钮显示正确
- [x] 删除按钮位置正确(日期左侧)
- [x] 点击删除按钮显示确认弹窗
- [x] 确认删除后备注消失
- [x] 取消删除后备注保留
- [x] 删除成功显示提示
- [x] Hover效果正常
- [x] 事件不冒泡使用catchtap
- [x] 代码无linting错误
---
## 文件变更清单
1. **notes.wxml** - 添加删除按钮结构
2. **notes.wxss** - 添加删除按钮样式
3. **notes.ts** - 添加删除逻辑
4. **DELETE_FEATURE.md** - 本文档
---
## 后续优化建议
1. **API集成**当前为前端删除需要对接后端API实现真实删除
2. **撤销功能**:考虑添加"撤销删除"功能3秒内可撤销
3. **批量删除**:如果需要,可以添加批量删除功能
4. **权限控制**:根据用户角色控制删除权限
---
## 参考文档
- 桥文档:`docs/miniprogram-dev/h5-to-mp-bridge-v3.md`
- 任务详情页:`apps/miniprogram/miniprogram/pages/task-detail/task-detail.ts`
- TDesign图标https://tdesign.tencent.com/miniprogram/components/icon

View File

@@ -0,0 +1,185 @@
# Notes 页面迁移说明
## 迁移版本
- **H5 原型基准**`docs/h5_ui/pages/notes.html`
- **桥文档版本**v3.0
- **迁移日期**2026-03-14
---
## 样式调整清单
### 1. 单位转换规则
遵循桥文档 §2.3 的混合单位策略:
- **主要使用 `px`**因为notes页面的尺寸需要与H5原型1:1对齐
- **换算基准**H5 CSS px → 小程序 px412宽设备验收基准
### 2. 导航栏(.custom-nav
| 属性 | H5 值 | 小程序值 | 说明 |
|------|------|--------|------|
| height | 44px | 44px | 标准导航栏高度 |
| padding | 0 16px | 0 16px | 左右内边距 |
| border-bottom | 1px solid | 1px solid #eeeeee | 分割线 |
**icon 尺寸调整**
- H5: `w-5 h-5` (20px)
- 小程序: `size="24px"` (考虑小程序点击区域最小44px)
### 3. 备注卡片(.note-card
| 属性 | H5 值 | 小程序值 | 说明 |
|------|------|--------|------|
| border-radius | rounded-2xl (16px) | 16px | 圆角 |
| padding | p-4 (16px) | 16px | 内边距 |
| box-shadow | shadow-sm | 0 1px 2px rgba(0,0,0,0.05) | 阴影 |
| margin-bottom | mb-3 (12px) | 12px | 卡片间距 |
### 4. 文本样式
#### 备注内容(.note-content
| 属性 | H5 值 | 小程序值 | 说明 |
|------|------|--------|------|
| font-size | text-sm (14px) | 14px | 正文字号 |
| line-height | leading-relaxed (1.625) | 20px | 行高按附录B标准 |
| color | text-gray-13 | #242424 | 正文颜色 |
| margin-bottom | mb-3 (12px) | 12px | 下边距 |
**line-height 设置规则**附录B.2.3
- 在外层 `<view>` 的 class 上设置 `line-height`
- `<text>` 会自动继承,不需要额外设置
#### 标签(.note-tag
| 属性 | H5 值 | 小程序值 | 说明 |
|------|------|--------|------|
| padding | px-2.5 py-1 (10px 4px) | 4px 10px | 标签内边距 |
| font-size | text-xs (12px) | 12px | 标签字号 |
| border-radius | rounded-lg (8px) | 8px | 圆角 |
| border | 1px solid | 1px solid | 边框 |
#### 时间戳(.note-time
| 属性 | H5 值 | 小程序值 | 说明 |
|------|------|--------|------|
| font-size | text-xs (12px) | 12px | 时间字号 |
| color | text-gray-6 | #a6a6a6 | 次级文字颜色 |
### 5. 列表容器(.note-list
| 属性 | H5 值 | 小程序值 | 说明 |
|------|------|--------|------|
| padding | p-4 (16px) | 16px | 列表外边距 |
| gap | space-y-3 (12px) | 12px | 卡片间距 |
### 6. 颜色映射附录C
| 用途 | 色值 | 说明 |
|------|------|------|
| 主品牌色 | #0052d9 | primary |
| 成功色 | #00a870 | success |
| 背景色 | #f3f3f3 | gray-1 |
| 正文色 | #242424 | gray-13 |
| 次级文字 | #a6a6a6 | gray-6 |
| 分割线 | #eeeeee | gray-2 |
### 7. 标签渐变背景
**客户标签**
```css
background: linear-gradient(135deg, #ecf2fe, #e8eeff);
color: #0052d9;
border-color: #c5d4f7;
```
**助教标签**
```css
background: linear-gradient(135deg, #e8faf0, #e0f7ea);
color: #00a870;
border-color: #b3e6d0;
```
---
## 关键调整点
### 1. 全局 line-height 设置
```wxss
page {
line-height: 1.5;
}
view {
line-height: inherit;
}
```
**原因**:微信小程序 `<text>` 组件不能直接设置 `line-height`,必须在外层 `<view>` 设置附录B.2.3
### 2. 单位统一为 px
- 原小程序版本混用 `rpx` 和 CSS 变量
- 调整为直接使用 `px`确保与H5原型1:1对齐
- 所有尺寸基于412宽设备验收基准
### 3. 移除 CSS 变量依赖
- 原:`var(--color-gray-2, #eeeeee)`
- 新:直接使用 `#eeeeee`
- 原因:确保样式独立,不依赖全局变量
### 4. Icon 尺寸调整
- 原:`size="48rpx"` (约88px)
- 新:`size="24px"` (标准导航栏icon尺寸)
- 原因与H5原型中的 `w-5 h-5` 对齐
### 5. 加载态 icon 尺寸
- 原:`size="80rpx"` (约146px)
- 新:`size="40px"` (适配小屏幕)
---
## 附录参考
### 使用的附录
1. **附录A**Spacing 与尺寸字典 v3.0
- 间距换算16px → 16pxpx模式
- 圆角8px, 16px
2. **附录B**:字体与文本字典 v3.1
- text-sm: 14px / 20px
- text-xs: 12px / 16px
- **关键规则**line-height 必须在外层 view 上设置
3. **附录C**:颜色字典 v3.0
- 项目自定义颜色表
- 透明度变体处理
4. **附录D**:布局类映射字典 v3.0
- flex 布局
- gap 间距
---
## 验收清单
- [x] 导航栏高度与H5对齐44px
- [x] 卡片圆角与H5对齐16px
- [x] 文字大小与H5对齐14px/12px
- [x] 行高设置正确在view上设置
- [x] 颜色值与H5对齐
- [x] 间距与H5对齐16px padding, 12px gap
- [x] 标签样式与H5对齐渐变背景
- [x] 阴影效果与H5对齐shadow-sm
---
## 已知限制
1. **安全区处理**:使用 `statusBarHeight` 动态计算,不使用 `env(safe-area-inset-*)`
2. **AI 悬浮按钮**bottom 值为 120px需根据实际设备调整
3. **页面滚动**:使用页面自然滚动,未使用 scroll-view
---
## 后续维护
- 若真机测试发现尺寸偏差,优先检查 line-height 设置
- 若需要调整间距参考附录A的spacing表
- 若需要调整字号参考附录B的字体表
- 颜色调整参考附录C的颜色字典

View File

@@ -0,0 +1,139 @@
# Notes 页面 H5 → 小程序 样式对比表
## 快速参考
### 导航栏
| 元素 | H5 Tailwind | H5 CSS px | 小程序 WXSS |
|------|-----------|----------|-----------|
| 导航栏高度 | h-11 | 44px | 44px |
| 导航栏 padding | px-4 | 0 16px | 0 16px |
| 返回按钮大小 | w-5 h-5 | 20px | 44px (容器) |
| 返回 icon 尺寸 | — | — | 24px |
| 标题字号 | text-base | 16px | 16px |
| 标题字重 | font-medium | 500 | 500 |
| 分割线 | border-b border-gray-2 | 1px solid #eeeeee | 1px solid #eeeeee |
### 备注卡片
| 元素 | H5 Tailwind | H5 CSS px | 小程序 WXSS |
|------|-----------|----------|-----------|
| 卡片圆角 | rounded-2xl | 16px | 16px |
| 卡片 padding | p-4 | 16px | 16px |
| 卡片阴影 | shadow-sm | 0 1px 2px rgba(0,0,0,0.05) | 0 1px 2px rgba(0,0,0,0.05) |
| 卡片间距 | space-y-3 | 12px | 12px |
| 背景色 | bg-white | #ffffff | #ffffff |
### 文本样式
| 元素 | H5 Tailwind | H5 CSS px | 小程序 WXSS |
|------|-----------|----------|-----------|
| 备注内容字号 | text-sm | 14px | 14px |
| 备注内容行高 | leading-relaxed | 1.625 (26px) | 20px |
| 备注内容颜色 | text-gray-13 | #242424 | #242424 |
| 备注内容下边距 | mb-3 | 12px | 12px |
| 标签字号 | text-xs | 12px | 12px |
| 标签 padding | px-2.5 py-1 | 10px 4px | 4px 10px |
| 标签圆角 | rounded-lg | 8px | 8px |
| 时间字号 | text-xs | 12px | 12px |
| 时间颜色 | text-gray-6 | #a6a6a6 | #a6a6a6 |
### 颜色
| 用途 | H5 Tailwind | 色值 | 小程序 WXSS |
|------|-----------|------|-----------|
| 页面背景 | bg-gray-1 | #f3f3f3 | #f3f3f3 |
| 卡片背景 | bg-white | #ffffff | #ffffff |
| 正文 | text-gray-13 | #242424 | #242424 |
| 次级文字 | text-gray-6 | #a6a6a6 | #a6a6a6 |
| 分割线 | border-gray-2 | #eeeeee | #eeeeee |
| 客户标签文字 | text-primary | #0052d9 | #0052d9 |
| 客户标签背景 | gradient | linear-gradient(135deg, #ecf2fe, #e8eeff) | linear-gradient(135deg, #ecf2fe, #e8eeff) |
| 客户标签边框 | — | #c5d4f7 | #c5d4f7 |
| 助教标签文字 | text-success | #00a870 | #00a870 |
| 助教标签背景 | gradient | linear-gradient(135deg, #e8faf0, #e0f7ea) | linear-gradient(135deg, #e8faf0, #e0f7ea) |
| 助教标签边框 | — | #b3e6d0 | #b3e6d0 |
### 列表容器
| 元素 | H5 Tailwind | H5 CSS px | 小程序 WXSS |
|------|-----------|----------|-----------|
| 列表 padding | p-4 | 16px | 16px |
| 列表背景 | bg-gray-1 | #f3f3f3 | #f3f3f3 |
### 底部提示
| 元素 | H5 Tailwind | H5 CSS px | 小程序 WXSS |
|------|-----------|----------|-----------|
| 提示字号 | text-xs | 12px | 12px |
| 提示颜色 | text-gray-5 | #c5c5c5 | #c5c5c5 |
| 提示 padding | py-8 pb-16 | 32px 0 64px | 20px 0 40px |
---
## 关键转换规则
### 1. Tailwind spacing → px
```
p-4 (padding: 1rem) → 16px
p-1 (padding: 0.25rem) → 4px
mb-3 (margin-bottom: 0.75rem) → 12px
space-y-3 (gap: 0.75rem) → 12px
```
### 2. Tailwind 字号 → px
```
text-sm (0.875rem) → 14px
text-xs (0.75rem) → 12px
text-base (1rem) → 16px
```
### 3. Tailwind 圆角 → px
```
rounded-2xl (border-radius: 1rem) → 16px
rounded-lg (border-radius: 0.5rem) → 8px
```
### 4. 行高处理
```
H5: leading-relaxed (1.625)
小程序: 在外层 view 上设置 line-height: 20px
原因: text 组件不支持直接设置 line-height
```
---
## 验证方法
### 在 412px 宽设备上对比
1. 打开H5原型`docs/h5_ui/pages/notes.html`
2. 打开小程序:`pages/notes/notes`
3. 对比以下关键点:
- 导航栏高度是否一致
- 卡片圆角是否一致
- 文字大小是否一致
- 间距是否一致
- 颜色是否一致
### 常见问题排查
| 问题 | 排查项 | 参考文档 |
|------|--------|--------|
| 文字高度不对 | 检查 line-height 是否在外层 view 上设置 | 附录B.2.3 |
| 间距不对 | 检查 padding/margin/gap 数值 | 附录A |
| 颜色不对 | 检查色值是否与附录C一致 | 附录C |
| 圆角不对 | 检查 border-radius 数值 | 附录A.5 |
| 阴影不对 | 检查 box-shadow 参数 | 桥文档 §9.2 |
---
## 文件清单
- `notes.wxml` - 页面结构已更新icon尺寸
- `notes.wxss` - 页面样式已调整为px单位
- `notes.ts` - 页面逻辑(无需修改)
- `notes.json` - 页面配置(无需修改)
- `MIGRATION_NOTES.md` - 迁移说明(本文件)
---
## 参考文档
- 桥文档:`docs/miniprogram-dev/h5-to-mp-bridge-v3.md`
- 附录A`docs/miniprogram-dev/New/appendix_a_spacing_and_sizing_dictionary_v3.md`
- 附录B`docs/miniprogram-dev/New/appendix_b_typography_and_text_dictionary_v3.md`
- 附录C`docs/miniprogram-dev/New/appendix_c_color_dictionary_v3.md`
- H5原型`docs/h5_ui/pages/notes.html`

View File

@@ -0,0 +1,13 @@
{
"navigationBarTitleText": "备注",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-loading": "tdesign-miniprogram/loading/loading",
"t-empty": "tdesign-miniprogram/empty/empty",
"ai-float-button": "/components/ai-float-button/ai-float-button",
"dev-fab": "/components/dev-fab/dev-fab"
}
}

View File

@@ -0,0 +1,76 @@
import { mockNotes } from '../../utils/mock-data'
import type { Note } from '../../utils/mock-data'
import { formatRelativeTime } from '../../utils/time'
/** 带展示时间的备注项 */
interface NoteDisplay extends Note {
timeLabel: string
}
Page({
data: {
pageState: 'loading' as 'loading' | 'empty' | 'error' | 'normal',
notes: [] as NoteDisplay[],
/** 系统状态栏高度px用于自定义导航栏顶部偏移 */
statusBarHeight: 20,
},
onLoad() {
const sysInfo = wx.getWindowInfo()
this.setData({ statusBarHeight: sysInfo.statusBarHeight || 20 })
this.loadData()
},
loadData() {
this.setData({ pageState: 'loading' })
setTimeout(() => {
// TODO: 替换为真实 API 调用 GET /api/xcx/notes
try {
const notes: NoteDisplay[] = mockNotes.map((n) => ({
...n,
timeLabel: formatRelativeTime(n.createdAt),
}))
this.setData({
pageState: notes.length > 0 ? 'normal' : 'empty',
notes,
})
} catch {
this.setData({ pageState: 'error' })
}
}, 400)
},
/** 返回上一页 */
onBack() {
wx.navigateBack()
},
/** 错误态重试 */
onRetry() {
this.loadData()
},
/** 删除备注 */
onDeleteNote(e: WechatMiniprogram.BaseEvent) {
const noteId = e.currentTarget.dataset.id as string
wx.showModal({
title: '删除备注',
content: '确定要删除这条备注吗?删除后无法恢复。',
confirmColor: '#e34d59',
success: (res) => {
if (res.confirm) {
const notes = this.data.notes.filter((n) => n.id !== noteId)
this.setData({ notes })
wx.showToast({ title: '已删除', icon: 'success' })
}
},
})
},
/** 下拉刷新 */
onPullDownRefresh() {
this.loadData()
wx.stopPullDownRefresh()
},
})

View File

@@ -0,0 +1,60 @@
<!-- pages/notes/notes.wxml — 备注记录 -->
<!-- 加载态toast 浮层,不白屏) -->
<view class="g-toast-loading" wx:if="{{pageState === 'loading'}}">
<view class="g-toast-loading-inner">
<t-loading theme="circular" size="40rpx" />
<text class="g-toast-loading-text">加载中...</text>
</view>
</view>
<!-- 错误态 -->
<view class="page-error" wx:elif="{{pageState === 'error'}}">
<view class="error-content">
<text class="error-icon">😵</text>
<text class="error-text">加载失败,请重试</text>
<view class="retry-btn" hover-class="retry-btn--hover" bindtap="onRetry">
<text class="retry-btn-text">重新加载</text>
</view>
</view>
</view>
<!-- 空数据态 -->
<view class="page-empty-wrap" wx:elif="{{pageState === 'empty'}}">
<view class="page-empty">
<t-empty description="暂无备注记录" />
</view>
</view>
<!-- 正常态 -->
<view class="page-normal" wx:elif="{{pageState === 'normal'}}">
<!-- 备注列表 -->
<view class="note-list">
<view
class="note-card"
wx:for="{{notes}}"
wx:key="id"
>
<text class="note-content">{{item.content}}</text>
<view class="note-bottom">
<text class="note-tag {{item.tagType === 'coach' ? 'tag-coach' : 'tag-customer'}}">{{item.tagLabel}}</text>
<view class="note-bottom-right">
<view class="note-delete-btn" catchtap="onDeleteNote" data-id="{{item.id}}" hover-class="note-delete-btn--hover">
<t-icon name="delete" size="16px" color="#a6a6a6" />
</view>
<text class="note-time">{{item.timeLabel}}</text>
</view>
</view>
</view>
</view>
<!-- 底部提示 -->
<view class="list-footer">
<text class="footer-text">— 已加载全部记录 —</text>
</view>
<!-- AI 悬浮按钮 -->
<ai-float-button />
</view>
<dev-fab />

View File

@@ -0,0 +1,203 @@
/* pages/notes/notes.wxss — 备注记录页样式 */
/* ========== 全局设置 ========== */
page {
background-color: #f3f3f3;
line-height: 1.5;
}
view {
line-height: inherit;
}
/* ========== 自定义导航栏 ========== */
.safe-area-top {
background-color: #ffffff;
}
.custom-nav {
display: flex;
align-items: center;
height: 44px;
padding: 0 16px;
position: relative;
border-bottom: 1px solid #eeeeee;
}
.nav-back {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.nav-back--hover {
background-color: #eeeeee;
}
.nav-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 16px;
font-weight: 500;
color: #242424;
line-height: 24px;
}
/* ========== 页面背景 ========== */
.page-loading,
.page-empty-wrap,
.page-normal,
.page-error {
min-height: 100vh;
background-color: #f3f3f3;
}
/* ========== 加载态 / 空态 ========== */
.page-loading,
.page-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 60vh;
gap: 16px;
}
/* ========== 错误态 ========== */
.page-error {
display: flex;
flex-direction: column;
height: 100vh;
}
.error-content {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 40px;
}
.error-icon {
font-size: 54px;
margin-bottom: 16px;
}
.error-text {
font-size: 14px;
color: #777777;
margin-bottom: 20px;
line-height: 20px;
}
.retry-btn {
padding: 10px 30px;
background-color: #0052d9;
border-radius: 8px;
}
.retry-btn--hover {
opacity: 0.8;
}
.retry-btn-text {
font-size: 14px;
color: #ffffff;
line-height: 20px;
}
/* ========== 备注列表 ========== */
.note-list {
padding: 16px;
}
.note-card + .note-card {
margin-top: 12px;
}
/* ========== 备注卡片 ========== */
.note-card {
background-color: #ffffff;
border-radius: 16px;
padding: 16px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.note-content {
display: block;
font-size: 14px;
color: #242424;
line-height: 20px;
margin-bottom: 12px;
}
.note-bottom {
display: flex;
align-items: center;
justify-content: space-between;
}
.note-bottom-right {
display: flex;
align-items: center;
gap: 8px;
}
/* ========== 删除按钮 ========== */
.note-delete-btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
flex-shrink: 0;
}
.note-delete-btn--hover {
background-color: #f3f3f3;
}
/* ========== 标签样式 ========== */
.note-tag {
padding: 4px 10px;
font-size: 12px;
border-radius: 8px;
border: 1px solid;
line-height: 16px;
}
.tag-customer {
background: linear-gradient(135deg, #ecf2fe, #e8eeff);
color: #0052d9;
border-color: #c5d4f7;
}
.tag-coach {
background: linear-gradient(135deg, #e8faf0, #e0f7ea);
color: #00a870;
border-color: #b3e6d0;
}
.note-time {
font-size: 12px;
color: #a6a6a6;
line-height: 16px;
}
/* ========== 底部提示 ========== */
.list-footer {
text-align: center;
padding: 20px 0 40px;
}
.footer-text {
font-size: 12px;
color: #c5c5c5;
line-height: 16px;
}