diff --git a/openspec/changes/archive/2025-12-25-add-bank-visit-plan/proposal.md b/openspec/changes/archive/2025-12-25-add-bank-visit-plan/proposal.md new file mode 100644 index 0000000..558828c --- /dev/null +++ b/openspec/changes/archive/2025-12-25-add-bank-visit-plan/proposal.md @@ -0,0 +1,21 @@ +# Change: 添加银行端客户拜访计划功能 + +## Why + +银行端客户经理需要记录和管理客户拜访活动,以便跟踪客户关系、记录营销产品推广情况,并保存现场拜访照片作为凭证。当前系统缺少拜访计划管理功能,无法满足客户关系管理的业务需求。 + +## What Changes + +- 在银行端添加客户拜访计划创建页面 +- 支持设置拜访日期、选择客户、定位位置、选择营销产品、填写拜访主题和备注 +- 支持上传拜访场景照片(拍照或从相册选择) +- 添加拜访计划保存功能 +- 添加拜访计划列表和详情查看功能 + +## Impact + +- Affected specs: `bank-visit-plan` (新能力) +- Affected code: + - `src/pagesBank/` - 新增拜访计划相关页面 + - `src/pagesBank/api/` - 新增拜访计划 API 接口 + - `src/typings/bank.ts` - 新增拜访计划类型定义 \ No newline at end of file diff --git a/openspec/changes/archive/2025-12-25-add-bank-visit-plan/specs/bank-visit-plan/spec.md b/openspec/changes/archive/2025-12-25-add-bank-visit-plan/specs/bank-visit-plan/spec.md new file mode 100644 index 0000000..41ed244 --- /dev/null +++ b/openspec/changes/archive/2025-12-25-add-bank-visit-plan/specs/bank-visit-plan/spec.md @@ -0,0 +1,72 @@ +## ADDED Requirements + +### Requirement: 创建拜访计划 +银行端用户 SHALL 能够创建客户拜访计划,记录拜访的详细信息。 + +#### Scenario: 成功创建拜访计划 +- **WHEN** 用户填写完整的拜访计划信息(日期、客户、位置、拜访主题、照片) +- **THEN** 系统 SHALL 保存拜访计划并返回成功提示 + +#### Scenario: 创建拜访计划时验证必填字段 +- **WHEN** 用户提交拜访计划时缺少必填字段(日期、客户、位置、拜访主题、照片) +- **THEN** 系统 SHALL 显示相应的错误提示,阻止提交 + +#### Scenario: 选择营销产品 +- **WHEN** 用户点击营销产品选择器 +- **THEN** 系统 SHALL 显示可选产品列表,支持多选 + +#### Scenario: 上传拜访场景图 +- **WHEN** 用户点击上传按钮 +- **THEN** 系统 SHALL 提供拍照和从相册选择两种方式 + +### Requirement: 拜访计划列表 +银行端用户 SHALL 能够查看拜访计划列表,支持筛选和搜索。 + +#### Scenario: 查看拜访计划列表 +- **WHEN** 用户进入拜访计划列表页面 +- **THEN** 系统 SHALL 显示所有拜访计划,按日期倒序排列 + +#### Scenario: 按状态筛选拜访计划 +- **WHEN** 用户选择状态筛选条件(待拜访、已完成、已取消) +- **THEN** 系统 SHALL 显示对应状态的拜访计划 + +#### Scenario: 搜索拜访计划 +- **WHEN** 用户输入关键词搜索 +- **THEN** 系统 SHALL 显示匹配的拜访计划(按客户名称或拜访主题) + +### Requirement: 拜访计划详情 +银行端用户 SHALL 能够查看拜访计划的详细信息。 + +#### Scenario: 查看拜访计划详情 +- **WHEN** 用户点击拜访计划列表项 +- **THEN** 系统 SHALL 显示拜访计划的完整信息(日期、客户、位置、营销产品、拜访主题、备注、照片) + +#### Scenario: 更新拜访状态 +- **WHEN** 用户在详情页更新拜访状态 +- **THEN** 系统 SHALL 保存状态变更并刷新页面 + +#### Scenario: 编辑拜访计划 +- **WHEN** 用户点击编辑按钮 +- **THEN** 系统 SHALL 进入编辑模式,允许修改拜访计划信息 + +### Requirement: 客户选择器 +系统 SHALL 提供客户选择器,支持从客户列表中选择目标客户。 + +#### Scenario: 打开客户选择器 +- **WHEN** 用户点击客户选择字段 +- **THEN** 系统 SHALL 弹出客户列表页面 + +#### Scenario: 选择客户 +- **WHEN** 用户从列表中选择一个客户 +- **THEN** 系统 SHALL 返回并显示选中的客户信息 + +### Requirement: 位置定位 +系统 SHALL 支持获取当前位置或手动输入地址。 + +#### Scenario: 自动定位 +- **WHEN** 用户点击定位按钮 +- **THEN** 系统 SHALL 获取当前位置并显示地址信息 + +#### Scenario: 手动输入地址 +- **WHEN** 用户手动输入地址 +- **THEN** 系统 SHALL 保存用户输入的地址信息 \ No newline at end of file diff --git a/openspec/changes/archive/2025-12-25-add-bank-visit-plan/tasks.md b/openspec/changes/archive/2025-12-25-add-bank-visit-plan/tasks.md new file mode 100644 index 0000000..1ef4a09 --- /dev/null +++ b/openspec/changes/archive/2025-12-25-add-bank-visit-plan/tasks.md @@ -0,0 +1,42 @@ +# Implementation Tasks + +## 1. 类型定义和 API 接口 +- [ ] 1.1 在 `src/typings/bank.ts` 中添加拜访计划相关类型定义 +- [ ] 1.2 在 `src/pagesBank/api/index.ts` 中添加拜访计划 API 接口 +- [ ] 1.3 在 `src/pagesBank/mock/index.ts` 中添加拜访计划 Mock 数据 + +## 2. 拜访计划创建页面 +- [ ] 2.1 创建 `src/pagesBank/visit/create.vue` 拜访计划创建页面 +- [ ] 2.2 实现日期选择器组件 +- [ ] 2.3 实现客户选择器(弹出客户列表) +- [ ] 2.4 实现位置定位功能(地图定位/文本输入) +- [ ] 2.5 实现营销产品多选功能 +- [ ] 2.6 实现拜访主题和备注输入 +- [ ] 2.7 实现图片上传功能(拍照/相册选择) +- [ ] 2.8 实现表单验证和提交功能 + +## 3. 拜访计划列表页面 +- [ ] 3.1 创建 `src/pagesBank/visit/list.vue` 拜访计划列表页面 +- [ ] 3.2 实现拜访计划列表展示 +- [ ] 3.3 实现状态筛选(待拜访、已完成、已取消) +- [ ] 3.4 实现搜索功能 + +## 4. 拜访计划详情页面 +- [ ] 4.1 创建 `src/pagesBank/visit/detail.vue` 拜访计划详情页面 +- [ ] 4.2 实现拜访计划详情展示 +- [ ] 4.3 实现拜访状态更新功能 +- [ ] 4.4 实现拜访记录编辑功能 + +## 5. 路由配置 +- [ ] 5.1 在 `src/pages.json` 中添加拜访计划相关路由配置 + +## 6. 导航入口 +- [ ] 6.1 在银行端首页或客户详情页添加"创建拜访计划"入口 +- [ ] 6.2 在客户详情页添加"拜访记录"入口 + +## 7. 测试和验证 +- [ ] 7.1 测试拜访计划创建流程 +- [ ] 7.2 测试拜访计划列表展示和筛选 +- [ ] 7.3 测试拜访计划详情查看和编辑 +- [ ] 7.4 测试图片上传功能 +- [ ] 7.5 测试表单验证 \ No newline at end of file diff --git a/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/proposal.md b/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/proposal.md new file mode 100644 index 0000000..106a79c --- /dev/null +++ b/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/proposal.md @@ -0,0 +1,29 @@ +# Change: 修改银行端客户拜访计划功能 + +## Why + +当前拜访计划功能在创建时要求填写位置和上传拜访场景图,但在实际业务场景中,这些信息应该在拜访完成时才需要填写。创建拜访计划时只需要记录基本的拜访安排(日期、客户、主题等),而在标记拜访完成时才需要补充位置信息和上传现场照片。这样的流程更符合实际业务需求。 + +## What Changes + +- **创建拜访计划页面** (`/pagesBank/visit/create`) 修改: + - 移除位置输入和定位功能 + - 移除上传拜访场景图功能 + - 保留日期、客户选择、营销产品、拜访主题、备注字段 + - 更新表单验证逻辑,不再验证位置和照片 + +- **拜访计划详情页面** (`/pagesBank/visit/detail?id={}`) 修改: + - 在标记完成时,要求填写位置信息(模拟从地图获取地址,默认使用"广东省茂名市") + - 在标记完成时,要求上传拜访场景图 + - 添加位置和照片的必填验证 + - 更新状态更新流程,先验证位置和照片后再更新状态 + +## Impact + +- Affected specs: `bank-visit-plan` (修改) +- Affected code: + - `src/pagesBank/visit/create.vue` - 移除位置和照片相关代码 + - `src/pagesBank/visit/detail.vue` - 添加完成时的位置和照片填写功能 + - `src/pagesBank/api/index.ts` - 更新 `updateVisitStatus` API 支持位置和照片参数 + - `src/typings/bank.ts` - 更新 `CreateVisitPlanParams` 类型定义 + - `openspec/specs/bank-visit-plan/spec.md` - 更新需求规格说明 \ No newline at end of file diff --git a/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/specs/bank-visit-plan/spec.md b/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/specs/bank-visit-plan/spec.md new file mode 100644 index 0000000..0abb63e --- /dev/null +++ b/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/specs/bank-visit-plan/spec.md @@ -0,0 +1,91 @@ +## MODIFIED Requirements + +### Requirement: 创建拜访计划 +银行端用户 SHALL 能够创建客户拜访计划,记录拜访的基本信息。 + +#### Scenario: 成功创建拜访计划 +- **WHEN** 用户填写完整的拜访计划信息(日期、客户、拜访主题) +- **THEN** 系统 SHALL 保存拜访计划并返回成功提示 + +#### Scenario: 创建拜访计划时验证必填字段 +- **WHEN** 用户提交拜访计划时缺少必填字段(日期、客户、拜访主题) +- **THEN** 系统 SHALL 显示相应的错误提示,阻止提交 + +#### Scenario: 选择营销产品 +- **WHEN** 用户点击营销产品选择器 +- **THEN** 系统 SHALL 显示可选产品列表,支持多选 + +### Requirement: 拜访计划列表 +银行端用户 SHALL 能够查看拜访计划列表,支持筛选和搜索。 + +#### Scenario: 查看拜访计划列表 +- **WHEN** 用户进入拜访计划列表页面 +- **THEN** 系统 SHALL 显示所有拜访计划,按日期倒序排列 + +#### Scenario: 按状态筛选拜访计划 +- **WHEN** 用户选择状态筛选条件(待拜访、已完成、已取消) +- **THEN** 系统 SHALL 显示对应状态的拜访计划 + +#### Scenario: 搜索拜访计划 +- **WHEN** 用户输入关键词搜索 +- **THEN** 系统 SHALL 显示匹配的拜访计划(按客户名称或拜访主题) + +### Requirement: 拜访计划详情 +银行端用户 SHALL 能够查看拜访计划的详细信息。 + +#### Scenario: 查看拜访计划详情 +- **WHEN** 用户点击拜访计划列表项 +- **THEN** 系统 SHALL 显示拜访计划的完整信息(日期、客户、营销产品、拜访主题、备注) + +#### Scenario: 标记拜访完成 +- **WHEN** 用户点击"标记完成"按钮 +- **THEN** 系统 SHALL 弹出填写位置和上传照片的表单 +- **AND** 用户填写位置信息(支持自动定位或手动输入,默认地址为"广东省茂名市") +- **AND** 用户上传至少一张拜访场景图 +- **AND** 系统 SHALL 验证位置和照片必填 +- **AND** 验证通过后更新拜访状态为"已完成" + +#### Scenario: 标记完成时验证必填字段 +- **WHEN** 用户提交完成标记时缺少位置信息或照片 +- **THEN** 系统 SHALL 显示相应的错误提示,阻止状态更新 + +#### Scenario: 编辑拜访计划 +- **WHEN** 用户点击编辑按钮 +- **THEN** 系统 SHALL 进入编辑模式,允许修改拜访计划信息(日期、主题、备注) + +### Requirement: 客户选择器 +系统 SHALL 提供客户选择器,支持从客户列表中选择目标客户。 + +#### Scenario: 打开客户选择器 +- **WHEN** 用户点击客户选择字段 +- **THEN** 系统 SHALL 弹出客户列表页面 + +#### Scenario: 选择客户 +- **WHEN** 用户从列表中选择一个客户 +- **THEN** 系统 SHALL 返回并显示选中的客户信息 + +### Requirement: 位置定位 +系统 SHALL 支持获取当前位置或手动输入地址。 + +#### Scenario: 自动定位 +- **WHEN** 用户点击定位按钮 +- **THEN** 系统 SHALL 获取当前位置并显示地址信息 + +#### Scenario: 手动输入地址 +- **WHEN** 用户手动输入地址 +- **THEN** 系统 SHALL 保存用户输入的地址信息 + +#### Scenario: 使用默认地址 +- **WHEN** 用户未填写位置信息 +- **THEN** 系统 SHALL 使用默认地址"广东省茂名市" + +### Requirement: 上传拜访场景图 +系统 SHALL 支持上传拜访场景照片。 + +#### Scenario: 上传拜访场景图 +- **WHEN** 用户点击上传按钮 +- **THEN** 系统 SHALL 提供拍照和从相册选择两种方式 + +#### Scenario: 验证照片数量 +- **WHEN** 用户标记拜访完成时 +- **THEN** 系统 SHALL 要求至少上传一张拜访场景图 \ No newline at end of file diff --git a/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/tasks.md b/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/tasks.md new file mode 100644 index 0000000..2294033 --- /dev/null +++ b/openspec/changes/archive/2025-12-25-modify-bank-visit-plan/tasks.md @@ -0,0 +1,67 @@ +# Tasks: 修改银行端客户拜访计划功能 + +## 任务列表 + +### 1. 修改类型定义 +- [x] 更新 `src/typings/bank.ts` 中的 `CreateVisitPlanParams` 接口 + - 移除 `location`、`latitude`、`longitude`、`photos` 字段 + - 这些字段将在标记完成时通过 `updateVisitStatus` API 提供 + - 新增 `CompleteVisitPlanParams` 接口用于标记完成时的参数 + +### 2. 修改创建拜访计划页面 +- [x] 修改 `src/pagesBank/visit/create.vue` + - 移除位置输入和定位功能 + - 移除上传拜访场景图功能 + - 更新表单验证逻辑 + - 移除位置验证 + - 移除照片验证 + - 更新提交表单逻辑 + - 移除位置和照片参数 + +### 3. 修改拜访计划详情页面 +- [x] 修改 `src/pagesBank/visit/detail.vue` + - 添加标记完成时的表单状态管理 + - 添加位置输入和定位功能 + - 添加上传拜访场景图功能 + - 修改 `handleUpdateStatus` 函数 + - 点击"标记完成"时弹出填写位置和上传照片的表单 + - 验证位置和照片必填 + - 验证通过后调用更新状态 API + - 更新模板部分,添加位置和照片填写表单 + +### 4. 修改 API 接口 +- [x] 修改 `src/pagesBank/api/index.ts` + - 更新 `createVisitPlan` 函数 + - 移除位置和照片参数处理 + - 创建时位置和照片为空 + - 更新 `updateVisitStatus` 函数 + - 添加 `location`、`latitude`、`longitude`、`photos` 参数 + - 更新拜访计划时保存位置和照片信息 + - 更新 `updateVisitPlan` 函数 + - 移除位置和照片相关字段的处理 + +### 5. 更新 Mock 数据 +- [x] 修改 `src/pagesBank/mock/index.ts` + - 更新 `mockVisitPlans` 数据结构 + - 确保待拜访的拜访计划位置和照片为空 + - 已完成的拜访计划包含位置和照片信息 + +### 6. 更新规格说明文档 +- [x] 更新 `openspec/specs/bank-visit-plan/spec.md` + - 应用修改提案中的规格变更 + - 更新创建拜访计划的需求 + - 更新拜访计划详情的需求 + - 添加标记完成时的场景 + +### 7. 测试验证 +- [x] 测试创建拜访计划功能 + - 验证不填写位置和照片可以成功创建 + - 验证必填字段验证正常工作 +- [x] 测试标记拜访完成功能 + - 验证必须填写位置和上传照片才能标记完成 + - 验证自动定位功能正常 + - 验证默认地址"广东省茂名市"正常使用 + - 验证照片上传功能正常 +- [x] 测试拜访计划详情页面 + - 验证位置和照片信息正确显示 + - 验证编辑功能正常工作 \ No newline at end of file diff --git a/openspec/specs/bank-visit-plan/spec.md b/openspec/specs/bank-visit-plan/spec.md new file mode 100644 index 0000000..02e0c8b --- /dev/null +++ b/openspec/specs/bank-visit-plan/spec.md @@ -0,0 +1,95 @@ +# bank-visit-plan Specification + +## Purpose +TBD - created by archiving change add-bank-visit-plan. Update Purpose after archive. +## Requirements +### Requirement: 创建拜访计划 +银行端用户 SHALL 能够创建客户拜访计划,记录拜访的基本信息。 + +#### Scenario: 成功创建拜访计划 +- **WHEN** 用户填写完整的拜访计划信息(日期、客户、拜访主题) +- **THEN** 系统 SHALL 保存拜访计划并返回成功提示 + +#### Scenario: 创建拜访计划时验证必填字段 +- **WHEN** 用户提交拜访计划时缺少必填字段(日期、客户、拜访主题) +- **THEN** 系统 SHALL 显示相应的错误提示,阻止提交 + +#### Scenario: 选择营销产品 +- **WHEN** 用户点击营销产品选择器 +- **THEN** 系统 SHALL 显示可选产品列表,支持多选 + +### Requirement: 拜访计划列表 +银行端用户 SHALL 能够查看拜访计划列表,支持筛选和搜索。 + +#### Scenario: 查看拜访计划列表 +- **WHEN** 用户进入拜访计划列表页面 +- **THEN** 系统 SHALL 显示所有拜访计划,按日期倒序排列 + +#### Scenario: 按状态筛选拜访计划 +- **WHEN** 用户选择状态筛选条件(待拜访、已完成、已取消) +- **THEN** 系统 SHALL 显示对应状态的拜访计划 + +#### Scenario: 搜索拜访计划 +- **WHEN** 用户输入关键词搜索 +- **THEN** 系统 SHALL 显示匹配的拜访计划(按客户名称或拜访主题) + +### Requirement: 拜访计划详情 +银行端用户 SHALL 能够查看拜访计划的详细信息。 + +#### Scenario: 查看拜访计划详情 +- **WHEN** 用户点击拜访计划列表项 +- **THEN** 系统 SHALL 显示拜访计划的完整信息(日期、客户、营销产品、拜访主题、备注) + +#### Scenario: 标记拜访完成 +- **WHEN** 用户点击"标记完成"按钮 +- **THEN** 系统 SHALL 弹出填写位置和上传照片的表单 +- **AND** 用户填写位置信息(支持自动定位或手动输入,默认地址为"广东省茂名市") +- **AND** 用户上传至少一张拜访场景图 +- **AND** 系统 SHALL 验证位置和照片必填 +- **AND** 验证通过后更新拜访状态为"已完成" + +#### Scenario: 标记完成时验证必填字段 +- **WHEN** 用户提交完成标记时缺少位置信息或照片 +- **THEN** 系统 SHALL 显示相应的错误提示,阻止状态更新 + +#### Scenario: 编辑拜访计划 +- **WHEN** 用户点击编辑按钮 +- **THEN** 系统 SHALL 进入编辑模式,允许修改拜访计划信息(日期、主题、备注) + +### Requirement: 客户选择器 +系统 SHALL 提供客户选择器,支持从客户列表中选择目标客户。 + +#### Scenario: 打开客户选择器 +- **WHEN** 用户点击客户选择字段 +- **THEN** 系统 SHALL 弹出客户列表页面 + +#### Scenario: 选择客户 +- **WHEN** 用户从列表中选择一个客户 +- **THEN** 系统 SHALL 返回并显示选中的客户信息 + +### Requirement: 位置定位 +系统 SHALL 支持获取当前位置或手动输入地址。 + +#### Scenario: 自动定位 +- **WHEN** 用户点击定位按钮 +- **THEN** 系统 SHALL 获取当前位置并显示地址信息 + +#### Scenario: 手动输入地址 +- **WHEN** 用户手动输入地址 +- **THEN** 系统 SHALL 保存用户输入的地址信息 + +#### Scenario: 使用默认地址 +- **WHEN** 用户未填写位置信息 +- **THEN** 系统 SHALL 使用默认地址"广东省茂名市" + +### Requirement: 上传拜访场景图 +系统 SHALL 支持上传拜访场景照片。 + +#### Scenario: 上传拜访场景图 +- **WHEN** 用户点击上传按钮 +- **THEN** 系统 SHALL 提供拍照和从相册选择两种方式 + +#### Scenario: 验证照片数量 +- **WHEN** 用户标记拜访完成时 +- **THEN** 系统 SHALL 要求至少上传一张拜访场景图 + diff --git a/src/pages.json b/src/pages.json index 53796b9..33192d7 100644 --- a/src/pages.json +++ b/src/pages.json @@ -246,6 +246,30 @@ "navigationBarTitleText": "客户管理" } }, + { + "path": "customer/detail", + "style": { + "navigationBarTitleText": "客户详情" + } + }, + { + "path": "visit/list", + "style": { + "navigationBarTitleText": "拜访计划" + } + }, + { + "path": "visit/create", + "style": { + "navigationBarTitleText": "创建拜访计划" + } + }, + { + "path": "visit/detail", + "style": { + "navigationBarTitleText": "拜访计划详情" + } + }, { "path": "me/index", "style": { diff --git a/src/pagesBank/api/index.ts b/src/pagesBank/api/index.ts index 64a203a..6d239f4 100644 --- a/src/pagesBank/api/index.ts +++ b/src/pagesBank/api/index.ts @@ -1,15 +1,21 @@ -import type { - BankStats, - AuditItem, - AuditStatus, +import type { + BankStats, + AuditItem, + AuditStatus, BankCustomer, - WithdrawAuditDetail + WithdrawAuditDetail, + VisitPlan, + CreateVisitPlanParams, + MarketingProduct } from '@/typings/bank' +import { VisitStatus } from '@/typings/bank' import { mockBankStats, mockAuditList, getMockWithdrawDetail, - mockCustomerList + mockCustomerList, + mockVisitPlans, + mockMarketingProducts } from '../mock' /** 获取银行端首页统计 */ @@ -173,3 +179,150 @@ export function getCustomerWithdraws(params: { }, 500) }) } + +/** 获取营销产品列表 */ +export function getMarketingProducts(): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(mockMarketingProducts) + }, 300) + }) +} + +/** 获取拜访计划列表 */ +export function getVisitPlanList(params: { + status?: string + pageNum: number + pageSize: number + keyword?: string +}): Promise<{ list: VisitPlan[]; total: number }> { + return new Promise((resolve) => { + setTimeout(() => { + let list = [...mockVisitPlans] + + // 状态筛选 + if (params.status) { + list = list.filter(item => item.status === params.status) + } + + // 关键词筛选 + if (params.keyword) { + const keyword = params.keyword.toLowerCase() + list = list.filter(item => + item.customerName.toLowerCase().includes(keyword) || + item.topic.toLowerCase().includes(keyword) + ) + } + + // 按日期倒序 + list.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) + + resolve({ list, total: list.length }) + }, 500) + }) +} + +/** 获取拜访计划详情 */ +export function getVisitPlanDetail(id: string): Promise { + return new Promise((resolve) => { + setTimeout(() => { + const plan = mockVisitPlans.find(item => item.id === id) + resolve(plan || null) + }, 300) + }) +} + +/** 创建拜访计划 */ +export function createVisitPlan(data: CreateVisitPlanParams): Promise { + return new Promise((resolve) => { + setTimeout(() => { + const customer = mockCustomerList.find(c => c.id === data.customerId) + const products = mockMarketingProducts.filter(p => data.productIds.includes(p.id)) + + const newPlan: VisitPlan = { + id: `V${Date.now()}`, + customerId: data.customerId, + customerName: customer?.merchantName || '', + date: data.date, + location: '', + latitude: undefined, + longitude: undefined, + products, + topic: data.topic, + remark: data.remark, + photos: [], + status: VisitStatus.PENDING, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString() + } + + mockVisitPlans.unshift(newPlan) + resolve(newPlan) + }, 500) + }) +} + +/** 更新拜访计划 */ +export function updateVisitPlan(id: string, data: Partial): Promise { + return new Promise((resolve) => { + setTimeout(() => { + const plan = mockVisitPlans.find(item => item.id === id) + if (plan) { + if (data.customerId) { + const customer = mockCustomerList.find(c => c.id === data.customerId) + plan.customerId = data.customerId + plan.customerName = customer?.merchantName || '' + } + if (data.date) plan.date = data.date + if (data.productIds) { + plan.products = mockMarketingProducts.filter(p => data.productIds!.includes(p.id)) + } + if (data.topic) plan.topic = data.topic + if (data.remark !== undefined) plan.remark = data.remark + plan.updatedAt = new Date().toISOString() + } + resolve(true) + }, 500) + }) +} + +/** 更新拜访状态 */ +export function updateVisitStatus( + id: string, + status: VisitStatus, + location?: string, + latitude?: number, + longitude?: number, + photos?: string[] +): Promise { + return new Promise((resolve) => { + setTimeout(() => { + const plan = mockVisitPlans.find(item => item.id === id) + if (plan) { + plan.status = status + plan.updatedAt = new Date().toISOString() + // 标记完成时更新位置和照片 + if (status === VisitStatus.COMPLETED) { + if (location) plan.location = location + if (latitude !== undefined) plan.latitude = latitude + if (longitude !== undefined) plan.longitude = longitude + if (photos) plan.photos = photos + } + } + resolve(true) + }, 300) + }) +} + +/** 删除拜访计划 */ +export function deleteVisitPlan(id: string): Promise { + return new Promise((resolve) => { + setTimeout(() => { + const index = mockVisitPlans.findIndex(item => item.id === id) + if (index > -1) { + mockVisitPlans.splice(index, 1) + } + resolve(true) + }, 300) + }) +} diff --git a/src/pagesBank/customer/detail.vue b/src/pagesBank/customer/detail.vue index 5e6f167..411b148 100644 --- a/src/pagesBank/customer/detail.vue +++ b/src/pagesBank/customer/detail.vue @@ -92,6 +92,18 @@ function handleFreeze() { }) } +function handleCreateVisit() { + uni.navigateTo({ + url: `/pagesBank/visit/create?customerId=${id.value}` + }) +} + +function handleVisitRecords() { + uni.navigateTo({ + url: `/pagesBank/visit/list?customerId=${id.value}` + }) +} + onLoad((options) => { if (options?.id) { id.value = options.id @@ -189,6 +201,14 @@ onLoad((options) => { 提现记录 + + + 创建拜访 + + + + 拜访记录 + {{ detail.status === 'frozen' ? '解冻账户' : '冻结账户' }} diff --git a/src/pagesBank/dashboard/index.vue b/src/pagesBank/dashboard/index.vue index 2486b93..7caf951 100644 --- a/src/pagesBank/dashboard/index.vue +++ b/src/pagesBank/dashboard/index.vue @@ -15,7 +15,8 @@ const bankStore = useBankStore() const quickActions = [ { icon: 'i-carbon-task-approved', label: '待审核', path: '/pagesBank/audit/list' }, { icon: 'i-carbon-group', label: '客户管理', path: '/pagesBank/customer/list' }, - { icon: 'i-carbon-report', label: '数据报表', path: '' }, // 暂未实现 + { icon: 'i-carbon-calendar', label: '拜访计划', path: '/pagesBank/visit/list' }, + { icon: 'i-carbon-add', label: '创建拜访', path: '/pagesBank/visit/create' }, { icon: 'i-carbon-settings', label: '设置', path: '/pagesBank/me/index' }, ] diff --git a/src/pagesBank/mock/index.ts b/src/pagesBank/mock/index.ts index a680e3c..544743c 100644 --- a/src/pagesBank/mock/index.ts +++ b/src/pagesBank/mock/index.ts @@ -1,10 +1,12 @@ -import type { - BankStats, - AuditItem, +import type { + BankStats, + AuditItem, BankCustomer, - WithdrawAuditDetail + WithdrawAuditDetail, + VisitPlan, + MarketingProduct } from '@/typings/bank' -import { AuditStatus, AuditType } from '@/typings/bank' +import { AuditStatus, AuditType, VisitStatus } from '@/typings/bank' // 统计数据 Mock export const mockBankStats: BankStats = { @@ -109,3 +111,69 @@ export const mockWithdrawHistory = [ { id: 'W005', amount: 10000.00, status: AuditStatus.APPROVED, time: '2024-12-01 09:00', bank: '工商银行(8888)' }, { id: 'W008', amount: 2000.00, status: AuditStatus.REJECTED, time: '2024-11-20 16:20', bank: '工商银行(8888)', reason: '账户信息有误' }, ] + +// 营销产品 Mock +export const mockMarketingProducts: MarketingProduct[] = [ + { id: 'P001', name: '公司理财', type: 'credit' }, + { id: 'P002', name: '公司贷款', type: 'loan' }, + { id: 'P003', name: '信用卡', type: 'credit' }, + { id: 'P004', name: '结算服务', type: 'settlement' }, + { id: 'P005', name: '企业网银', type: 'other' }, +] + +// 拜访计划 Mock +export const mockVisitPlans: VisitPlan[] = [ + { + id: 'V001', + customerId: 'C1001', + customerName: '张三', + date: '2025-12-26', + location: '', + latitude: undefined, + longitude: undefined, + products: [ + { id: 'P001', name: '公司理财', type: 'credit' }, + { id: 'P002', name: '公司贷款', type: 'loan' } + ], + topic: '推广公司理财和贷款产品', + remark: '客户对理财产品感兴趣,需要详细介绍', + photos: [], + status: VisitStatus.PENDING, + createdAt: '2025-12-25 10:00:00', + updatedAt: '2025-12-25 10:00:00' + }, + { + id: 'V002', + customerId: 'C1002', + customerName: '李四', + date: '2025-12-24', + location: '广东省茂名市', + latitude: 21.6630, + longitude: 110.9250, + products: [ + { id: 'P003', name: '信用卡', type: 'credit' } + ], + topic: '信用卡业务推广', + remark: '客户已有信用卡,考虑升级', + photos: ['/static/images/visit2.jpg', '/static/images/visit3.jpg'], + status: VisitStatus.COMPLETED, + createdAt: '2025-12-23 15:30:00', + updatedAt: '2025-12-24 18:00:00' + }, + { + id: 'V003', + customerId: 'C1001', + customerName: '张三', + date: '2025-12-20', + location: '', + latitude: undefined, + longitude: undefined, + products: [], + topic: '客户回访', + remark: '因客户临时有事,拜访取消', + photos: [], + status: VisitStatus.CANCELLED, + createdAt: '2025-12-19 09:00:00', + updatedAt: '2025-12-20 10:00:00' + } +] diff --git a/src/pagesBank/visit/create.vue b/src/pagesBank/visit/create.vue new file mode 100644 index 0000000..4a1faf9 --- /dev/null +++ b/src/pagesBank/visit/create.vue @@ -0,0 +1,425 @@ + + +