☰
CRM客户关系管理系统原型:线索分配、跟进留痕与商机漏斗
2026/10/27 17:52:12 网站建设 项目流程

简介:这份CRM客户关系管理系统原形面向学习客户关系管理前端实现、课程设计或毕业项目的开发者,围绕销售、市场营销与服务等业务场景,提供可参考的交互页面与功能框架,重点解决客户信息录入校验、页面交互与数据更新等原型设计问题。RAR压缩包约10MB,文件总数显示为0、类型明细暂未提供,因此无法按文件类型展开说明;从资源描述看,内容应涉及JavaScript表单验证、jQuery页面交互以及Ajax无刷新数据获取等前端技术示例。已有301人浏览学习,适合作为CRM页面原型与前端技术整合的入门参考。读者可从中了解客户管理界面的布局思路、输入校验规则、下拉菜单与滑动效果等交互做法,并借鉴导航、样式一致性和响应式设计,为搭建高效、易用的管理平台原型提供素材与实现线索。

1. 销售主管要的其实不是报表,是别再丢单

某公司的销售主管找我聊需求,开口第一句是“别给我整大屏,我就想知道这条线索现在归谁、跟到第几步、下一步什么时候跟”。他们的现状是三个人共用一张 Excel,谁改了什么全凭记忆,月底核对业绩要翻聊天记录。这大概是 CRM 客户关系管理系统原型最真实的起点:不是功能越多越好,而是把“线索分配、跟进留痕、阶段推进”这三件事固定到页面里,让数据逐渐积累起来。网上搜“CRM 客户关系管理系统原形”的人,多半是在找一套能直接改的页面骨架,而不是又一篇概念科普。这套东西适合三类人:做毕设或课程设计、需要一条讲得清楚的完整业务链路;企业内想先验证流程再谈采购;接外包需要一份能当面演示的首版 Demo。页面数量不必多,但每一页都得能回答一个业务问题。

2. 需求拆解与页面地图:三类角色推到二十个页面

2.1 角色边界先定死,页面颗粒度才定得下来

CRM 最容易失败的地方不是页面不美观,而是权限没想清楚。做着做着就会发现,“销售能不能看到同部门别人的客户”这个问题会在列表页、详情页、报表页、导出功能里反复冒出来,每冒一次就要改一遍代码。所以第一步不是画界面,是把角色和数据范围列成一张表,让后面所有接口都照着这张表来。

角色数据范围关键动作不该看到的内容
销售专员本人名下 + 公海未分配建线索、写跟进、转客户、建商机他人客户的成交金额、团队汇总
销售主管本团队全部分配线索、回收客户、看团队漏斗系统配置、其他团队数据
系统管理员全局账号、角色、数据字典、字段配置具体跟进内容(可选屏蔽)

这张表里最容易被忽略的是“数据范围”这一列。它意味着后端每一个列表接口都必须自带owner_id或team_id过滤条件,而不是前端拿到全量数据再筛。原型阶段图省事写成前端过滤,等到接真实数据那天,等于把整个查询层重写一遍,这种返工是最难承受的。

第二个要想清楚的是线索和客户到底是不是一张表。我的做法是分开:线索是“还没验证过的联系人信息”,可能来自展会、官网表单、渠道推荐,质量参差不齐;客户是“已经确认有采购意向或合作关系的组织”,一个客户下可以挂多个联系人、多个商机。两者分开的好处是线索池可以做成公海,谁都能捞,捞走有保护期,到期没跟进自动退回;而客户一旦建档就相对稳定,不会因为换销售就消失。这条规则听起来简单,但它直接决定了后面表结构和页面跳转的设计。

2.2 页面地图与路由表:六个一级菜单,二十个二级页面

角色定完,页面清单基本就自动出来了。一级菜单我一般分六块:工作台、线索、客户、商机、报表、设置。工作台放待办和今日跟进,是销售每天打开系统第一眼看到的东西;线索和客户是主战场;商机承载金额和阶段;报表只做三张(漏斗、业绩、跟进量),原型阶段不求全;设置放账号、角色、数据字典。

页面路由核心元素依赖接口
工作台/dashboard待跟进卡片、本周成交、漏斗缩略GET /api/stats/overview
线索池/leads筛选栏、表格、批量分配、领取按钮GET /api/leads
线索详情/leads/:id基本信息、跟进时间轴、转客户按钮GET /api/leads/:id
客户列表/customers组合筛选、分页、导出GET /api/customers
客户详情/customers/:id聚合信息、联系人、商机、时间轴GET /api/customers/:id/summary
商机看板/opportunities/board阶段列、卡片拖拽、金额合计PATCH /api/opportunities/:id/stage
团队漏斗/reports/funnel阶段转化率、按人对比GET /api/reports/funnel
系统设置/settings/*用户、角色、字典多接口

路由配置建议一开始就把权限标识写进meta,后面加权限只需要在守卫里判断,不用回头改每个页面。

// router/index.js —— 一级菜单统一挂在 Layout 下,二级页面作为 children const routes = [ { path: '/', component: Layout, redirect: '/dashboard', children: [ { path: 'dashboard', name: 'Dashboard', component: () => import('@/views/Dashboard.vue'), meta: { title: '工作台', icon: 'home' } // 无 permission 表示登录即可访问 }, { path: 'leads', name: 'LeadList', component: () => import('@/views/lead/List.vue'), meta: { title: '线索池', permission: 'lead:list' } }, { path: 'leads/:id', name: 'LeadDetail', component: () => import('@/views/lead/Detail.vue'), // hidden: true 让它不出现在侧边栏,但路由仍然可跳转 meta: { title: '线索详情', hidden: true, permission: 'lead:read' } }, { path: 'opportunities/board', name: 'OpportunityBoard', component: () => import('@/views/opportunity/Board.vue'), meta: { title: '商机看板', permission: 'opp:board' } } ] } ]

这段配置里三个参数值得说明。meta.permission是自定义字段,路由守卫读它来判断当前用户有没有这个权限码,没有就跳 403,这是前端层面的第一道闸。meta.hidden控制的是侧边栏渲染,详情页这类必须靠 id 才能进入的页面不该出现在菜单里,但路由本身要保留。path: 'leads/:id'用的是路由参数而不是查询串,因为详情页的 id 是资源标识,刷新后必须能还原,用 query 容易被用户手动改掉导致串数据。守卫的写法大致是:取 token → 拉用户权限列表 → 比对to.meta.permission,这段逻辑写在beforeEach里,白名单只放登录页和 404。

2.3 原型选型:低保真先跑通链路,高保真再谈视觉

原型有两条路。一条是纯静态:设计工具画页面,点击能跳转,但数据是死的。另一条是可运行:前端后端都真的跑起来,数据存库,能增删改查。毕设和课程设计建议走第二条,因为答辩现场评委最爱问的是“你演示一下从线索到成交的完整流程”,静态图答不了这个问题。企业内验证流程也建议可运行,流程对不对,只有真的走一遍数据才知道。

技术栈不用纠结,选你最熟的那套就行。前端 Vue3 + Vite + Element Plus,或者 React + Ant Design,两者做中后台表格和表单都够用;后端 Express、FastAPI、Spring Boot 任选,原型阶段不涉及高并发,谁写得快用谁;数据库 MySQL 8 足够,如果演示环境不方便装服务,SQLite 也能应付,把连接配置抽出来就行。目录按业务域分,不要按技术层分,这样加一个模块不用在三个文件夹之间来回跳。

# 目录结构:按业务域划分,views 和 api 一一对应 src/ ├── api/ # 接口封装,一个业务域一个文件 │ ├── lead.js │ ├── customer.js │ └── opportunity.js ├── views/ │ ├── lead/ # 线索:List.vue / Detail.vue │ ├── customer/ # 客户:List.vue / Detail.vue │ └── opportunity/ # 商机:Board.vue ├── components/ # FollowTimeline.vue、StageTag.vue 等复用组件 └── router/index.js

时间紧张的时候有个折中办法:第一周前端全部走 mock 数据,接口路径按约定先定死,比如统一GET /api/customers?page=1&size=20;第二周后端把真接口写出来,前端只改 axios 的baseURL,页面代码一行不动。这个约定必须在动手前写进文档,否则前后端各写各的,联调那天就是灾难现场。

3. 数据模型与接口契约:六张主表撑起整条销售链路

3.1 表结构与关键字段:能算出来的不存,要追溯的必须留痕

原型阶段的表设计不用追求大而全,但有几处必须一开始就想对,否则后面改表比重写还痛苦。核心六张表:用户表、线索表、客户表、联系人表、商机表、跟进记录表。金额一律用DECIMAL(14,2),别用 float,浮点误差在业绩汇总页会以“差三分钱”的形式让你被追问半小时;时间统一存 UTC,展示层再转本地时区,这条在跨时区场景下是唯一正确解。

-- 客户表:owner_id 和 team_id 是数据权限的两个锚点 CREATE TABLE customer ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(120) NOT NULL, industry VARCHAR(50), level TINYINT DEFAULT 3, -- 1=A 2=B 3=C,用于分级 owner_id BIGINT NOT NULL, -- 归属销售,权限过滤靠它 team_id BIGINT NOT NULL, -- 归属团队,主管看板靠它 source_lead_id BIGINT, -- 由哪条线索转来,用于溯源 status TINYINT DEFAULT 1, -- 1=正常 2=公海 3=已归档 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted_at DATETIME NULL, -- 软删除,报表要能排除 UNIQUE KEY uk_name_owner (name, owner_id, deleted_at) ); -- 跟进记录表:只增不改,是整条链路的黑匣子 CREATE TABLE follow_up ( id BIGINT PRIMARY KEY AUTO_INCREMENT, biz_type TINYINT NOT NULL, -- 1=线索 2=客户 3=商机 biz_id BIGINT NOT NULL, content TEXT NOT NULL, next_time DATETIME, -- 下次跟进时间,工作台待办取这个字段 creator_id BIGINT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_biz (biz_type, biz_id), KEY idx_next (next_time) -- 待办列表按它排序,必须建索引 );

deleted_at这个字段看着不起眼,但它是后面所有查询的隐形约束。只要表里有软删除,每个查询都得带deleted_at IS NULL,漏一个就会出现“列表里没有、总数里算进去了”的灵异现象。我的习惯是封装一个查询构造器,默认拼上这个条件,需要查归档数据时显式调用withDeleted(),把风险收在一个地方。

follow_up表用biz_type + biz_id做多态关联,好处是一张表能同时挂在线索、客户、商机上,时间轴组件只写一次;代价是不能用外键约束,得靠应用层保证。原型阶段这个取舍是划算的,因为跟进记录是纯追加的,写错的可能性低。真要严谨一点,可以在转客户的时候做一次数据迁移,把线索的跟进记录复制到客户上,保证新客户详情页打开就有历史。

3.2 统一响应结构与分页约定:别让前端为每个接口写一套解析

前后端联调最耗时间的从来不是业务逻辑,是“这个接口返回的是数组还是对象”“分页字段叫 total 还是 count”。开工前先把契约钉死,能省掉后面无数轮扯皮。我的约定是:所有接口返回统一包裹,业务数据放data,分页信息放page里,错误码放code,人话放message。

// 统一响应:成功时的结构 { "code": 0, "message": "ok", "data": [ /* 列表项 */ ], "page": { "page": 1, "size": 20, "total": 137 } } // 失败时的结构,HTTP 状态码同步返回 4xx/5xx { "code": 40301, "message": "无权访问该客户", "data": null }

这里有几个参数是刻意选的。code用 0 表示成功,而不是 200,是为了和 HTTP 状态码解耦,前端拦截器只判断code === 0,不用管 GET 和 POST 的区别。page.size默认 20 且上限 100,防止有人传size=99999把库拖死,这个上限在后端做校验,前端下拉框只给 10/20/50/100 四个选项。total必须在同一次查询里算出来,不能先查列表再查总数,因为两次查询之间数据可能变,分页器会跳页——这个坑我在早期项目里踩过,用户点第二页发现数据重复,追了半天才定位到是两次查询时间差。

分页本身建议用LIMIT offset, size的朴素写法,原型阶段数据量小,够用。真到几十万行再换游标分页,不用过早优化。但索引要提前建:客户列表按owner_id + deleted_at查,商机看板按stage + team_id查,跟进待办按next_time查,这三条建上,基本不会卡。

3.3 线索转客户的状态机:状态不是随手改的字段

线索和商机的状态流转,是整个系统里最容易被写坏的部分。写坏的典型症状是:数据库里出现一个status = 5但枚举里只有 1 到 4 的记录,或者一条已经“赢单”的商机被改回“跟进中”,业绩报表前后两次跑出不同结果。解决办法不是加校验注释,是把流转规则写成一个显式的状态机。

当前状态允许流转到触发动作附加条件
待分配跟进中、已关闭领取 / 主管分配领取人必须是本团队成员
跟进中已转客户、已关闭转客户 / 标记无效转客户必须填客户名和至少一个联系人
已转客户无终态不可回退,需要修改走客户模块
已关闭跟进中重新激活需主管权限,记录原因
// 状态流转校验:所有改状态的操作都必须先过这一关 const TRANSITIONS = { pending: ['following', 'closed'], following: ['converted', 'closed'], converted: [], closed: ['following'] } function assertTransition(from, to, operator) { const allowed = TRANSITIONS[from] || [] if (!allowed.includes(to)) { // 抛业务异常,由统一错误处理转成 4xx throw new BizError(40010, `不允许从 ${from} 流转到 ${to}`) } // 重新激活是特权操作,单独校验角色 if (from === 'closed' && to === 'following' && operator.role !== 'manager') { throw new BizError(40302, '仅主管可重新激活线索') } }

这段代码的价值在于把规则集中在一处。TRANSITIONS是唯一事实来源,前端画按钮、后端做校验、文档写说明,全都引用它,改规则只改这一张表。from === 'closed'的特判放在函数里而不是散落在业务代码中,是为了保证任何入口——列表页的批量操作、详情页的按钮、导入脚本——都走同一套判断,不会出现“页面上点不了但接口能改”的漏洞。终态converted设计成空数组,意味着不可回退,这条规则在答辩时经常被问到,回答的口径是:已转客户的线索如果再改状态,客户那边的数据就对不上了,需要修正就走客户的编辑功能,保证单一数据源。

4. 核心页面实现:列表、详情、漏斗三块硬骨头

4.1 客户列表页:组合筛选与分页的真实写法

列表页看着最简单,实际上是最考验设计的一页。销售的真实用法是:先按归属人筛,再按等级筛,偶尔搜个名字,然后翻页。如果每个条件都单独发一次请求,用户点三下筛选就发三次请求,页面还会因为返回顺序错乱而闪。正确做法是把筛选条件收进一个响应式对象,统一 watch,做 300ms 防抖,一次性提交。

// views/customer/List.vue —— 筛选与分页的核心逻辑 const query = reactive({ keyword: '', // 模糊匹配客户名,后端用 LIKE '%kw%' level: null, // 1/2/3,空表示不限 ownerId: null, // 主管看团队时可指定某个销售 page: 1, size: 20 }) // 条件变化重置到第一页,否则会出现"第 5 页没有数据"的错觉 watch(() => [query.keyword, query.level, query.ownerId], debounce(() => { query.page = 1 fetchList() }, 300)) async function fetchList() { const { data, page } = await api.getCustomers(query) list.value = data total.value = page.total }

watch里监听的是三个筛选字段而不是整个query对象,因为page和size变化时不该重置页码,否则用户点下一页会被打回第一页。debounce的作用是防止输入框每敲一个字发一次请求,300ms 是经验和体验的折中,太短没效果,太长用户觉得卡。后端对应的查询要按参数是否为空动态拼WHERE,这里必须用参数化查询,不能字符串拼接,否则一个带单引号的客户名就能让接口报错,这种低级问题在演示现场出现一次就够丢人的。

表格列的设计也有讲究:客户名做成可点击跳详情,等级用彩色标签,金额右对齐并做千分位,最后加一列“最近跟进时间”,超过 7 天没跟的标红。这一列是整张表最有业务价值的一列,它把“该跟没跟”的客户直接推到销售眼前,比任何报表都管用。

4.2 客户详情页:一屏聚合,别让用户点五次才看全

详情页的信息密度决定了这个系统到底好不好用。反面教材是把客户、联系人、商机、跟进做成四个 tab,用户想看“这个客户最近跟到哪了”得点三次。我的做法是一个聚合接口,一次返回四块数据,页面用左右分栏:左边基础信息加联系人,右边商机列表加跟进时间轴。

// GET /api/customers/:id/summary —— 聚合接口,一次查完四块 async function getCustomerSummary(req, res) { const { id } = req.params // 并行查询,四块数据互不依赖,串行会白白多等三倍时间 const [customer, contacts, opportunities, follows] = await Promise.all([ db.customer.findFirst({ where: { id, deletedAt: null } }), db.contact.findMany({ where: { customerId: id } }), db.opportunity.findMany({ where: { customerId: id } }), db.followUp.findMany({ where: { bizType: 2, bizId: id }, orderBy: { createdAt: 'desc' }, take: 20 // 时间轴只取最近 20 条,多的走"查看更多" }) ]) if (!customer) return res.fail(40404, '客户不存在') // 数据权限:非本人且非本团队主管,直接拒绝 if (!canAccess(req.user, customer)) return res.fail(40301, '无权访问该客户') res.ok({ customer, contacts, opportunities, follows }) }

Promise.all这四个查询是并行的,串行写会变成四次往返,在弱网环境下体感差别很明显。take: 20是个刻意的限制,跟进记录可能有几百条,全量返回会让首屏变慢,时间轴组件做成“最近 20 条 + 加载更多”更合理。canAccess这个判断放在聚合接口里而不是中间件,是因为它需要拿到 customer 记录才能知道 owner 是谁,属于“数据级权限”,和“接口级权限”是两回事,两者都得有。

时间轴组件建议做成通用的,传bizType和bizId就能复用在线索、客户、商机三个详情页。每条记录显示操作人、时间、内容、下次跟进时间,超过约定时间未跟进的记录用警示色标出来。这个小细节在答辩演示时特别加分,因为它直接对应“别再丢单”这个原始诉求。

4.3 商机漏斗:拖拽改阶段,先更新 UI 还是先请求

商机看板是视觉上最讨喜的一页,也是并发问题最集中的一页。用户拖一张卡片从“方案”到“谈判”,直觉上应该立刻看到卡片移过去,但后端可能因为状态机校验失败而拒绝。这里的选择是乐观更新:先改本地状态,请求失败再回滚并提示。

// 拖拽结束:先动 UI,失败回滚,保证手感 async function onDrop(cardId, targetStage) { const card = board.value.find(c => c.id === cardId) const prevStage = card.stage if (prevStage === targetStage) return card.stage = targetStage // 乐观更新 try { await api.updateStage(cardId, { stage: targetStage, version: card.version // 乐观锁版本号 }) card.version += 1 recalcColumnTotals() // 每列金额合计要重算 } catch (e) { card.stage = prevStage // 回滚 ElMessage.error(e.message || '阶段流转失败') } }

version字段是乐观锁的关键。两个人同时拖同一张卡片,先提交的成功,后提交的会带着旧版本号,后端发现version对不上就拒绝,提示“该商机已被他人修改,请刷新”。原型阶段可以不做锁,但一定要在演示时说明这个设计,因为它回答的是“多人同时用会不会乱”这个必问题。recalcColumnTotals不能省,每列的金额合计是看板的核心信息,卡片移动后不同步会让数字对不上,用户第一眼就会发现。

看板的列顺序要固定:初步接触 → 需求确认 → 方案报价 → 商务谈判 → 赢单/输单。列宽自适应,卡片上显示客户名、金额、预计成交日、负责人头像。列头显示“N 个商机 / 合计 X 万”,这个数字比任何图表都直观。输单必须强制填原因,原因做成下拉加自定义,后面做输单分析就靠这个字段,否则报表里只有一堆“其他”。

5. 避坑与排查:原型阶段最容易翻车的五个点

5.1 数据一致性:重复建档与分页错乱

现象一:同一个客户被建了三次,销售各跟各的。原因通常是线索转客户时只做了前端查重,用户点两次按钮或者两个销售同时转同一条线索,就产生了三条记录。解决办法是数据库层加唯一索引兜底,业务层再做一次软校验。我给customer表加了UNIQUE KEY uk_name_owner (name, owner_id, deleted_at),注意这里把deleted_at也放进唯一键,是为了让软删除后的同名客户能重新建,否则删掉的客户会永久占用名字。业务层在转客户前先按“客户名 + 至少一个相同手机号”做一次模糊查重,命中就弹窗提示“可能已存在,是否继续”,把决定权交给用户而不是直接拦死。

现象二:翻到第二页看到第一页的数据。原因是列表和总数用了两次独立查询,中间有数据插入,导致 offset 偏移。更隐蔽的一种是ORDER BY字段不唯一,比如按created_at排序,同一秒创建的几条记录顺序随机,翻页时就会重复或漏掉。解决方法是排序字段必须带唯一键兜底:ORDER BY created_at DESC, id DESC。这一条是典型的血泪经验,排查起来特别费劲,因为本地数据量小的时候完全复现不出来。

现象三:金额合计差几分钱。前面提过,用DECIMAL存金额,前端参与计算时也别转成 Number 直接加,要么后端算好返回,要么用整数分做单位。报表页的合计建议直接由 SQL 的SUM()出结果,别在前端把当页数据加起来,因为那只是当前页的合计,不是全部的。

5.2 权限与状态:前端藏了按钮不等于安全

现象四:普通销售能看到别人的客户。最常见的原因是把权限做成了前端隐藏按钮,接口却没有任何校验,用户改一下 URL 里的 id 就能看到。解决方法是每个涉及资源的接口都做“接口权限 + 数据权限”双重校验:接口权限看角色有没有这个权限码,数据权限看这条记录是不是归他或归他团队。这两层要写成一个可复用的中间件或者工具函数,而不是每个接口里手写一遍 if,手写迟早会漏。我的做法是封装canAccess(user, record),任何单条记录的读写都必须调它,代码评审时专门检查这一条。

现象五:商机状态被改回上一个阶段,业绩报表前后不一致。原因是状态字段被当成普通字段直接UPDATE,绕过了状态机。解决方法是把状态变更收敛成一个专用接口,比如PATCH /api/opportunities/:id/stage,其他任何更新接口都不允许修改stage字段,在 ORM 层把该字段设为不可批量更新。同时在报表侧留一手:业绩统计不依赖当前状态,而是依赖状态变更日志表,每次流转写一条日志,报表按日志算,这样即使有人绕过接口改了字段,历史数据也对得上。这张日志表就是整个系统的黑匣子,出问题的时候全靠它。

另外还有一条容易忽略的:软删除的数据混进了报表。所有报表 SQL 都要显式带deleted_at IS NULL,别指望 ORM 的默认作用域,因为报表往往用原生 SQL 写,作用域不生效。我一般会在报表模块的基类里统一拼这个条件,减少遗漏。

6. 验收与答辩:拿一条完整业务链路自证

原型做完,怎么证明它能用?不是把每个页面点一遍,而是走一条完整链路,让数据从头流到尾。我通常准备一条固定剧本:新建一条线索(来源选“官网表单”)→ 主管把它分配给某个销售 → 销售写一条跟进记录并设置下次跟进时间 → 工作台出现待办 → 线索转成客户,带一个联系人 → 在客户下建一个商机,填金额和预计成交日 → 拖过三个阶段 → 赢单 → 打开报表看漏斗和业绩是否同步变化。这条链路走通,系统就立住了;走不通,问题一定出在状态机或者数据权限上,定位范围很小。

验收清单我一般按这五项过一遍,每项都能当场演示:

验收项判定标准常见失败点
主链路贯通线索到赢单全程无阻断,数据可追溯转客户后跟进记录丢失
数据权限用两个不同角色账号交叉验证详情页能越权访问
状态机非法流转被拒绝并给出明确提示终态可回退
分页与筛选组合条件 + 翻页结果稳定排序字段不唯一导致重复
数据一致性报表合计与列表合计一致软删除数据未排除

答辩时最常被追问的三个问题,提前准备好答案能省很多临场慌乱。第一是“为什么线索和客户要分表”,回答要点是数据成熟度不同、跟进策略不同、公海回收只针对线索。第二是“多人同时操作怎么办”,回答乐观锁加状态机加操作日志三层。第三是“数据量大了怎么办”,回答索引设计加聚合接口加时间轴分页,不要吹分布式,原型阶段谈分布式反而显得不踏实。

演示节奏上有个小技巧:别从登录页开始讲功能列表,直接从工作台的待办卡片切入,说“这是销售今天要跟的五个人”,然后点进其中一个走完整链路。评委的注意力只有前几分钟,先给场景再给功能,比先给菜单树有效得多。演示前把所有演示数据清一遍,只留剧本里要用的那几条,列表页干干净净,翻页不会翻出测试数据。

这套东西我自己改过好几版,最开始那版就是因为权限只做了前端,被一个随手改 URL 的动作当场打脸。从那以后我每次做完原型,都会用两个不同角色的账号把主链路各走一遍,再拿一个越权的 id 手动试一次,确认接口真的会拒绝,才敢拿去演示。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询