# 企迹 (qiji) — 政企周报管理系统 设计文档 ## 项目背景 中国电信政企客户经理团队目前使用 Excel 进行周报管理,包含四个 Sheet:每日拜访记录、下周工作计划、小微业务商机跟单、要客拜访计划。现有方式存在填报效率低、无法挂载照片、汇总查看不便、考核靠人工点名扣分、客户数据无法沉淀等问题。 本系统以 FastAPI + Vue 3 构建,部署在本地服务器 + 云服务器的混合拓扑上,对接已有的 Casdoor(认证)、PostgreSQL(数据库)、MinIO(文件存储)、企业微信(消息推送与快捷入口)。 ## 用户规模与角色 小型支局,约 5-8 人:3-5 名客户经理 + 1 名支局长 + 偶尔分管领导查看。 ### 角色权限矩阵 | 角色 | 数据可见性 | 操作权限 | |------|-----------|---------| | 客户经理 | 只看自己的拜访记录、工作计划、商机、要客拜访 | 填/改/删自己的记录,上传照片,新建客户 | | 支局长 | 全支局所有人的所有数据 | 增删改所有人记录,导出汇总,查看填报统计,手动触发催办/推送公告,管理客户档案与归属分配 | | 分管领导 | 同支局长全量视图 | 仅查看和导出,不可编辑 | ## 技术架构 ``` 本地服务器(内网) ├── FastAPI (uvicorn, port 8000) ├── PostgreSQL(已有,复用) └── MinIO(已有,复用) 云服务器 └── Vue 3 前端 (nginx, port 443, 域名) ↕ API 请求走 HTTPS → 本地服务器公网映射端口 Casdoor(已有部署,OIDC) 企业微信(管理后台创建自建应用) ``` 开发阶段前后端均在本地:`localhost:8000` + `localhost:5173` 联调。 ### 后端:FastAPI - 单体应用,FastAPI + SQLAlchemy (async) + Alembic 做数据迁移 - JWT 鉴权,token 签发与验证对接 Casdoor OIDC - 文件上传:客户端获取 MinIO 预签名 URL 直传,API 只记录 object key - 定时任务:APScheduler,每日 18:00 检查填报情况触发企微提醒 ### 前端:Vue 3 - Vue 3 + Vite + TypeScript - 组件库:Element Plus(中文生态好,表格/表单组件成熟) - 两套适配布局:PC Web 端(支局长/分管领导汇总查看)+ 移动端(客户经理外勤快速填报,也是企微应用落地页) ### 存储:MinIO - 组织方式:`{date}/{manager}/{uuid}.jpg` - 单张限制 10MB,一次拜访最多 9 张 - 上传走预签名 URL,绕过 API 中转 - 查看走预签名下载 URL(有效期 1 小时) - 缩略图由 MinIO 策略自动生成 - 删除拜访记录时同步清理关联照片 ### 认证:Casdoor - FastAPI 作为 OIDC Relying Party - 用户在 Casdoor 已分配角色(客户经理 / 支局长 / 分管领导),JWT 携带角色信息 - 企业微信用户绑定 Casdoor 账号后,可实现企微内静默登录 ## 数据模型 共 7 张核心表,全部使用 PostgreSQL。 ### customers — 客户档案 | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | name | VARCHAR(200) | 单位名称 | | industry | VARCHAR(100) | 所属行业 | | address | VARCHAR(500) | 单位地址 | | in_use_services | TEXT | 在用业务(枚举文本) | | monthly_fee | VARCHAR(100) | 月使用费 | | created_by | UUID → users.id | 创建人 | | created_at | TIMESTAMP | | | updated_at | TIMESTAMP | | ### customer_contacts — 客户联系人 | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | customer_id | UUID → customers.id | 所属客户 | | name | VARCHAR(50) | 联系人姓名 | | phone | VARCHAR(20) | 联系方式 | | role_desc | VARCHAR(100) | 角色描述(如"技术对接人") | ### customer_assignments — 客户经理归属 | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | customer_id | UUID → customers.id | | | manager_id | UUID → users.id | | | role | VARCHAR(20) | 'primary' / 'assistant' | | assigned_at | TIMESTAMP | 分配时间 | | assigned_by | UUID → users.id | 操作人(支局长) | 支持归属转移:支局长修改 `manager_id` 即可,历史拜访记录保留在 `visits.manager_id` 原值不变。 ### visits — 每日拜访记录(对应"周报"sheet) | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | customer_id | UUID → customers.id | 走访单位 | | visit_date | DATE | 拜访日期 | | visit_method | VARCHAR(20) | 上门/电话/微信/出差 | | time_range | VARCHAR(30) | 如 "9:00-10:00" | | communication_content | TEXT | 沟通内容 | | customer_demand | TEXT | 客户需求 | | companions | UUID[] | 同访人员 ID 数组 | | photos | TEXT[] | MinIO object key 数组 | | manager_id | UUID → users.id | 客户经理 | | created_at | TIMESTAMP | | | updated_at | TIMESTAMP | | ### work_plans — 下周工作计划 | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | customer_id | UUID → customers.id | 计划走访单位 | | plan_content | TEXT | 工作计划 | | plan_date | DATE | 计划拜访时间 | | manager_id | UUID → users.id | | | status | VARCHAR(20) | 计划中/已完成/已取消 | ### mini_business — 小微业务商机(对应"小微业务"sheet) | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | customer_id | UUID → customers.id | 单位名称 | | product_type | VARCHAR(200) | 产品类型 | | amount | VARCHAR(100) | 金额 | | follow_up_detail | TEXT | 跟进内容具体情况 | | status | VARCHAR(50) | 跟进状态 | | manager_id | UUID → users.id | | | expected_revenue_date | VARCHAR(50) | 预计列收时间 | ### key_visits — 要客拜访计划 | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | customer_id | UUID → customers.id | 单位 | | urgency_level | VARCHAR(10) | 紧急重要度:重要/一般/紧急 | | description | TEXT | 内容描述 | | progress_status | VARCHAR(20) | 进展状态 | | planned_date | VARCHAR(50) | 计划拜访时间 | | planned_visitor | VARCHAR(100) | 计划拜访人 | | visit_target | VARCHAR(100) | 拜访对象 | | manager_id | UUID → users.id | | ### users — 用户(对接 Casdoor) | 字段 | 类型 | 说明 | |------|------|------| | id | UUID | 主键 | | casdoor_id | VARCHAR(100) | Casdoor 用户 ID | | name | VARCHAR(50) | 姓名 | | role | VARCHAR(30) | manager / director / leader | | department | VARCHAR(100) | 部门 | | wecom_userid | VARCHAR(100) | 企业微信 userid | ## 核心功能设计 ### 一、客户经理填报 **入口**:移动端「今日拜访」按钮 + 企微工作台菜单「今日拜访」。 **表单字段**: - 客户单位:下拉选择(仅显示自己负责的客户 + 自己新建的客户),支持搜索,支持快速新建客户 - 选择客户后自动带出联系人信息 - 拜访日期:默认今天 - 拜访方式:单选(上门 / 电话 / 微信 / 出差) - 时间范围:两个时间选择器 - 同访人员:多选,选了谁自动在对方账号下创建一条预填草稿(沟通内容留空让对方补) - 沟通内容:自由文本 - 客户需求:自由文本(用于汇总时的关键字提取) - 拜访照片:最多 9 张,拍照或从相册选,走 MinIO 预签名直传 **首页状态**:显示「今天已录入 N 条」,下方为当天已填记录的摘要卡片列表。 ### 二、支局长汇总视图 **仪表盘首页**: - 四张数字卡片:本周拜访次数、工作计划条数、商机跟单条数、要客拜访条数 - 填报进度条:每个客户经理的填报情况(已填/未填),未填人员红色标记 ⚠ - 快捷入口:本周周报详情、导出 Excel、历史周报 **周报详情页**:四个 Tab 对应四个业务模块 - 支持按人筛选、按客户筛选 - 时间轴模式按天分组 - 照片缩略图,点击放大查看 - 一键导出 Excel(格式与现有模板一致) **考核与催办**: - 每日 18:00 自动检查,企微推送提醒未填报的客户经理 - 支局长可手动点击「催办」按钮,选择人员发送应用消息 - 支局长可编辑一条自定义公告,推送到全员企微 - 支局长可设置"当日最低拜访条数"阈值,低于阈值也预警 ### 三、分管领导视图 与支局长相同的全量数据视图,所有编辑按钮灰色禁用。核心目标是随时打开看,首屏加载 1 秒以内。 ### 四、客户档案管理 - 独立客户档案,包含单位基本信息、在用业务、月使用费、关键联系人 - 客户经理—客户归属关系(主负责 / 协办),支局长统一管理分配 - 支持批量导入:从存量收入清单 Excel 导入客户和归属关系 - 客户查重:建客户时自动提示疑似重复,支局长定期合并 - **归属转移**:客户经理离职时,支局长将客户批量转移给新同事,历史拜访记录完整保留在原客户经理名下 ### 五、数据导入导出 - **导入**:上传旧周报 Excel → 系统解析 sheet → 预览匹配字段 → 确认导入;同一天同一人同一客户自动跳过不重复 - **导出**:支局长点击「导出本周周报」,生成与原 Excel 模板格式完全一致的四 sheet .xlsx 文件 ## 企业微信集成 ### 工作台菜单 | 菜单名称 | 跳转目标 | |---------|---------| | 今日拜访 | 移动端填报页 | | 本周周报 | 支局长汇总视图 | | 客户查询 | 客户档案搜索页 | ### 登录流程 1. 用户从企微菜单进入,前端拿企微 `code` 换取 `userid` 2. 服务端用 `userid` 查找已绑定的 Casdoor 账号 3. 已绑定:直接签发 JWT,用户无感进入系统 4. 未绑定:引导去 Casdoor 完成一次账号绑定,之后永久生效 ### 消息推送 | 场景 | 方式 | 触发 | |------|------|------| | 每日填报提醒 | 应用消息 → 未填人员 | 每日 18:00 自动 | | 手动催办 | 支局长选人 → 发送应用消息 | 手动 | | 支局长公告 | 编辑公告 → 发应用消息 → 全员 | 手动 | ### 后续扩展(首期不做) - 企微聊天侧边栏:在跟客户的聊天窗口右侧弹出拜访记录入口,自动带入客户信息 ## 部署说明 1. FastAPI 后端部署于本地服务器,通过内网访问 PostgreSQL 和 MinIO 2. API 端口通过公网映射暴露给云服务器上的前端 3. Vue 前端部署于云服务器 nginx,HTTPS 访问 4. 开发阶段前后端均在本地运行,联调结构与生产一致 5. Casdoor、PostgreSQL、MinIO、企业微信应用均为已有基础设施,本系统作为新接入方