feat: 修改员工APP咨询业务流程图
This commit is contained in:
@@ -3,292 +3,312 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>健康咨询 - 员工咨询流程图 | 健康长庆原型</title>
|
||||
<title>健康咨询 - 员工咨询业务流程图</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
background: #f5f7fa;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||||
color: #1a1a1a;
|
||||
padding: 32px;
|
||||
min-width: 1100px;
|
||||
}
|
||||
.page-header {
|
||||
text-align: center; margin-bottom: 32px;
|
||||
}
|
||||
.page-header h1 { font-size: 24px; font-weight: 700; color: #1a1a1a; }
|
||||
.page-header p { font-size: 14px; color: #8c8c8c; margin-top: 6px; }
|
||||
.legend {
|
||||
display: flex; justify-content: center; gap: 24px; margin-bottom: 28px; flex-wrap: wrap;
|
||||
}
|
||||
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #595959; }
|
||||
.legend-dot { width: 14px; height: 14px; border-radius: 4px; flex-shrink: 0; }
|
||||
|
||||
/* 流程图容器 */
|
||||
.flowchart-wrap {
|
||||
display: flex; gap: 28px; justify-content: center; align-items: flex-start; flex-wrap: nowrap;
|
||||
}
|
||||
.flow-column {
|
||||
background: #fff; border-radius: 16px; padding: 24px 20px 28px;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.06); min-width: 320px; max-width: 360px; flex: 1;
|
||||
}
|
||||
.flow-column-title {
|
||||
font-size: 16px; font-weight: 700; text-align: center; padding: 8px 0 16px;
|
||||
border-bottom: 2px solid #f0f0f0; margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 节点样式 */
|
||||
.node {
|
||||
position: relative; border-radius: 10px; padding: 10px 14px; margin: 0 auto;
|
||||
text-align: center; font-size: 13px; font-weight: 500; width: 90%;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.node:hover { transform: scale(1.03); }
|
||||
.node-entry { background: #e6f4ff; border: 1.5px solid #91caff; color: #0958d9; }
|
||||
.node-page { background: #f6ffed; border: 1.5px solid #b7eb8f; color: #389e0d; }
|
||||
.node-action { background: #fff7e6; border: 1.5px solid #ffd591; color: #d46b08; }
|
||||
.node-state { border-radius: 20px; padding: 7px 14px; font-size: 12px; }
|
||||
.node-state.s-progress { background: #e6f4ff; border: 1.5px solid #91caff; color: #1677ff; }
|
||||
.node-state.s-done { background: #f6ffed; border: 1.5px solid #b7eb8f; color: #52c41a; }
|
||||
.node-state.s-timeout { background: #fff7e6; border: 1.5px solid #ffd591; color: #fa8c16; }
|
||||
.node-state.s-cancel { background: #f5f5f5; border: 1.5px solid #d9d9d9; color: #8c8c8c; }
|
||||
.node-state.s-reject { background: #fff2f0; border: 1.5px solid #ffccc7; color: #ff4d4f; }
|
||||
.node-state.s-confirm { background: #f9f0ff; border: 1.5px solid #d3adf7; color: #722ed1; }
|
||||
.node-state.s-wait { background: #fff7e6; border: 1.5px solid #ffd591; color: #fa8c16; }
|
||||
.node-dialog { background: #fff0f6; border: 1.5px dashed #ffadd2; color: #c41d7f; border-radius: 10px; }
|
||||
.node-end { background: #f5f5f5; border: 1.5px solid #d9d9d9; color: #595959; border-radius: 20px; }
|
||||
|
||||
.file-tag {
|
||||
display: block; font-size: 10px; color: #8c8c8c; font-weight: 400; margin-top: 3px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 箭头连接线 */
|
||||
.arrow-down {
|
||||
display: flex; flex-direction: column; align-items: center; padding: 6px 0;
|
||||
}
|
||||
.arrow-down .line { width: 2px; height: 18px; background: #d9d9d9; }
|
||||
.arrow-down .head { width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 6px solid #d9d9d9; }
|
||||
.arrow-label {
|
||||
font-size: 10px; color: #8c8c8c; background: #fff; padding: 0 4px; margin: -2px 0;
|
||||
}
|
||||
|
||||
/* 分支容器 */
|
||||
.branch-wrap {
|
||||
display: flex; gap: 10px; justify-content: center; margin: 0 -6px;
|
||||
}
|
||||
.branch { flex: 1; display: flex; flex-direction: column; align-items: center; }
|
||||
.branch .node { width: 100%; font-size: 12px; padding: 8px 6px; }
|
||||
.branch .file-tag { font-size: 9px; }
|
||||
|
||||
/* 分支线 */
|
||||
.branch-line {
|
||||
display: flex; align-items: flex-start; justify-content: center; height: 24px; position: relative; width: 100%;
|
||||
}
|
||||
.branch-line::before {
|
||||
content: ''; position: absolute; top: 0; left: 25%; right: 25%; height: 2px; background: #d9d9d9;
|
||||
}
|
||||
.branch-line .bl { position: absolute; top: 0; width: 2px; height: 24px; background: #d9d9d9; }
|
||||
.branch-line .bl-l { left: 25%; }
|
||||
.branch-line .bl-r { right: 25%; }
|
||||
.branch-line .bl-c { left: 50%; transform: translateX(-50%); }
|
||||
|
||||
.branch-line-3::before { left: 16.6%; right: 16.6%; }
|
||||
.branch-line-3 .bl-l { left: 16.6%; }
|
||||
.branch-line-3 .bl-r { right: 16.6%; }
|
||||
|
||||
.branch-line-5::before { left: 10%; right: 10%; }
|
||||
.branch-line-5 .bl-1 { left: 10%; }
|
||||
.branch-line-5 .bl-2 { left: 30%; }
|
||||
.branch-line-5 .bl-3 { left: 50%; transform: translateX(-50%); }
|
||||
.branch-line-5 .bl-4 { right: 30%; }
|
||||
.branch-line-5 .bl-5 { right: 10%; }
|
||||
|
||||
/* 状态分支 - 更紧凑 */
|
||||
.state-branches { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin: 0 -4px; }
|
||||
.state-branches .node-state { flex-shrink: 0; }
|
||||
|
||||
.section-label {
|
||||
font-size: 11px; color: #8c8c8c; text-align: center; margin: 12px 0 6px;
|
||||
border-top: 1px dashed #e8e8e8; padding-top: 10px;
|
||||
}
|
||||
|
||||
/* 起始大节点 */
|
||||
.node-start {
|
||||
background: linear-gradient(135deg, #1677ff, #0958d9); color: #fff;
|
||||
border: none; font-size: 15px; font-weight: 700; padding: 14px; border-radius: 12px;
|
||||
width: 60%; margin: 0 auto;
|
||||
}
|
||||
@media (max-width: 1100px) {
|
||||
.flowchart-wrap { flex-wrap: wrap; }
|
||||
.flow-column { max-width: 100%; min-width: 0; }
|
||||
}
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
body{background:#f5f7fa;font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Helvetica Neue',sans-serif;color:#1a1a1a;padding:40px 20px}
|
||||
.page-header{text-align:center;margin-bottom:24px}
|
||||
.page-header h1{font-size:24px;font-weight:700}
|
||||
.page-header p{font-size:13px;color:#8c8c8c;margin-top:6px}
|
||||
.legend{display:flex;justify-content:center;gap:24px;margin-bottom:24px;flex-wrap:wrap}
|
||||
.legend-item{display:flex;align-items:center;gap:6px;font-size:12px;color:#595959}
|
||||
.legend-shape{width:32px;height:20px;flex-shrink:0}
|
||||
.canvas-wrap{overflow-x:auto;padding-bottom:40px}
|
||||
svg text{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Helvetica Neue',sans-serif}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-header">
|
||||
<h1>员工健康咨询 — 完整业务流程图</h1>
|
||||
<p>覆盖咨询专家(图文 / 视频)与咨询小助手两大路径,标注页面文件与状态流转</p>
|
||||
<h1>员工健康咨询 — 业务流程图</h1>
|
||||
<p>涵盖找专家、图文咨询、视频咨询、咨询小助手、我的咨询五条业务线</p>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#e6f4ff;border:1px solid #91caff"></div>入口 / 导航页</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#f6ffed;border:1px solid #b7eb8f"></div>功能页面</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#fff7e6;border:1px solid #ffd591"></div>操作 / 选择</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#fff0f6;border:1px dashed #ffadd2"></div>弹窗 / 对话框</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="border-radius:10px;background:#f5f5f5;border:1px solid #d9d9d9"></div>终态</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="border-radius:10px;background:#e6f4ff;border:1px solid #91caff"></div>进行中</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="border-radius:10px;background:#f6ffed;border:1px solid #b7eb8f"></div>已完成</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="border-radius:10px;background:#fff7e6;border:1px solid #ffd591"></div>已超时/待开始</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="border-radius:10px;background:#fff2f0;border:1px solid #ffccc7"></div>已拒绝</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="border-radius:10px;background:#f9f0ff;border:1px solid #d3adf7"></div>待确认</div>
|
||||
</div>
|
||||
|
||||
<!-- 起始节点 -->
|
||||
<div style="text-align:center;margin-bottom:8px;">
|
||||
<div class="node node-start">健康咨询首页<span class="file-tag" style="color:rgba(255,255,255,.7)">index.html</span></div>
|
||||
</div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<!-- 三列流程 -->
|
||||
<div class="flowchart-wrap">
|
||||
|
||||
<!-- ========== 图文咨询 ========== -->
|
||||
<div class="flow-column">
|
||||
<div class="flow-column-title" style="color:#0958d9">📝 咨询专家 — 图文咨询</div>
|
||||
|
||||
<div class="node node-entry">找专家<span class="file-tag">find-expert.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">按医院/科室/疾病</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-page">专家列表<span class="file-tag">expert-list.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-page">专家详情<span class="file-tag">expert-profile.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">点击「图文咨询」</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-action">选择咨询人 & 健康档案<span class="file-tag">select-person.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-state s-progress">进行中 — 图文聊天<span class="file-tag">text-chat.html</span></div>
|
||||
|
||||
<div class="section-label">咨询结束后的状态分支</div>
|
||||
|
||||
<div class="branch-line"><div class="bl bl-l"></div><div class="bl bl-c"></div><div class="bl bl-r"></div></div>
|
||||
<div class="branch-wrap">
|
||||
<div class="branch">
|
||||
<div class="node node-state s-timeout">已超时<span class="file-tag">record-detail-timeout.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-end">再次咨询</div>
|
||||
</div>
|
||||
<div class="branch">
|
||||
<div class="node node-state s-done">已完成·未评价<span class="file-tag">record-detail-unrated.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">评价</div><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-dialog">评价医生<span class="file-tag">rate-doctor.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-state s-done">已完成·已评价<span class="file-tag">record-detail-rated.html</span></div>
|
||||
</div>
|
||||
<div class="branch">
|
||||
<div class="node node-dialog">结束咨询确认<span class="file-tag">end-consult-dialog.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">确认结束</div><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-dialog">评价医生<span class="file-tag">rate-doctor.html</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<svg class="legend-shape" viewBox="0 0 32 20"><rect x="1" y="1" width="30" height="18" rx="9" fill="#e8f4ff" stroke="#1677ff" stroke-width="1.5"/></svg>起止框
|
||||
</div>
|
||||
|
||||
<!-- ========== 视频咨询 ========== -->
|
||||
<div class="flow-column">
|
||||
<div class="flow-column-title" style="color:#722ed1">🎥 咨询专家 — 视频咨询</div>
|
||||
|
||||
<div class="node node-entry">找专家<span class="file-tag">find-expert.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">按医院/科室/疾病</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-page">专家列表<span class="file-tag">expert-list.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-page">专家详情<span class="file-tag">expert-profile.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">点击「视频咨询」</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-action">预约视频咨询<span class="file-tag">video-booking.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">选择日期时段</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-action">选择咨询人 & 健康档案<span class="file-tag">select-person.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-page">预约成功<span class="file-tag">video-success.html</span></div>
|
||||
|
||||
<div class="section-label">视频咨询状态流转</div>
|
||||
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-state s-confirm">待确认<span class="file-tag">video-detail-confirming.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">医生确认</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-state s-wait">待开始<span class="file-tag">video-detail-pending.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">进入视频</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-state s-done">已完成<span class="file-tag">video-detail-done.html</span></div>
|
||||
|
||||
<div class="section-label">异常状态分支</div>
|
||||
<div class="branch-line"><div class="bl bl-l"></div><div class="bl bl-r"></div></div>
|
||||
<div class="branch-wrap">
|
||||
<div class="branch">
|
||||
<div class="node node-state s-cancel">已取消<span class="file-tag">video-detail-cancelled.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-end">重新预约</div>
|
||||
</div>
|
||||
<div class="branch">
|
||||
<div class="node node-state s-reject">已拒绝<span class="file-tag">video-detail-rejected.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
<div class="node node-end">重新预约</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<svg class="legend-shape" viewBox="0 0 32 20"><rect x="1" y="1" width="30" height="18" rx="3" fill="#fff" stroke="#333" stroke-width="1.5"/></svg>处理框
|
||||
</div>
|
||||
|
||||
<!-- ========== 小助手咨询 ========== -->
|
||||
<div class="flow-column" style="max-width:300px;min-width:260px">
|
||||
<div class="flow-column-title" style="color:#389e0d">💬 咨询小助手</div>
|
||||
|
||||
<div class="node node-entry">首页点击「小助手」<span class="file-tag">index.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-state s-progress">进行中 — 小助手聊天<span class="file-tag">assistant-chat.html</span></div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="arrow-label">结束咨询</div><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-state s-done">已完成 — 历史记录<span class="file-tag">assistant-chat-history.html</span></div>
|
||||
|
||||
<div class="section-label">咨询记录入口</div>
|
||||
<div class="arrow-down"><div class="line"></div><div class="head"></div></div>
|
||||
|
||||
<div class="node node-entry">我的咨询<span class="file-tag">my-records.html</span></div>
|
||||
<div style="font-size:11px;color:#8c8c8c;text-align:center;margin-top:10px;line-height:1.8;">
|
||||
一级Tab:咨询专家 / 小助手<br>
|
||||
二级Tab(专家):图文咨询 / 视频咨询<br>
|
||||
列表按状态跳转到对应详情页
|
||||
</div>
|
||||
|
||||
<div class="section-label">辅助页面</div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px;margin-top:8px;">
|
||||
<div class="node node-dialog" style="width:100%">选择咨询人弹窗<span class="file-tag">select-person-dialog.html</span></div>
|
||||
<div class="node node-dialog" style="width:100%">选择体检报告弹窗<span class="file-tag">select-report-dialog.html</span></div>
|
||||
<div class="node node-dialog" style="width:100%">结束咨询确认弹窗<span class="file-tag">end-consult-dialog.html</span></div>
|
||||
<div class="node node-page" style="width:100%">专家评价列表<span class="file-tag">expert-reviews.html</span></div>
|
||||
<div class="node node-page" style="width:100%">医院详情<span class="file-tag">hospital-detail.html</span></div>
|
||||
<div class="node node-page" style="width:100%">搜索页<span class="file-tag">search.html</span></div>
|
||||
<div class="node node-page" style="width:100%">选择咨询记录<span class="file-tag">select-record.html</span></div>
|
||||
<div class="node node-page" style="width:100%">咨询人详情<span class="file-tag">consult-person-detail.html</span></div>
|
||||
<div class="node node-page" style="width:100%">添加健康档案<span class="file-tag">add-health-record.html</span></div>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<svg class="legend-shape" viewBox="0 0 32 20"><polygon points="16,1 31,10 16,19 1,10" fill="#fffbe6" stroke="#d48806" stroke-width="1.5"/></svg>判断框
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<svg class="legend-shape" viewBox="0 0 32 20"><rect x="1" y="1" width="30" height="18" rx="3" fill="#fff" stroke="#999" stroke-width="1" stroke-dasharray="4 2"/></svg>注释框
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<svg class="legend-shape" viewBox="0 0 32 20"><line x1="2" y1="10" x2="28" y2="10" stroke="#666" stroke-width="1.5"/><polygon points="28,7 32,10 28,13" fill="#666"/></svg>流程线
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部说明 -->
|
||||
<div style="text-align:center;margin-top:36px;font-size:12px;color:#bfbfbf;">
|
||||
员工端 · 健康咨询模块 · 业务流程图 | 共 <?php echo count(glob('*.html')); ?> 个页面
|
||||
<div class="canvas-wrap">
|
||||
<svg id="fc"></svg>
|
||||
</div>
|
||||
<script>
|
||||
/* ===== 流程图数据定义 ===== */
|
||||
/* 节点类型: T=起止框, P=处理框, D=判断框, N=注释框 */
|
||||
const W=160,H=42,DW=130,DH=72; // 处理框宽高、菱形宽高
|
||||
const nodes=[
|
||||
// ---- 入口 ----
|
||||
{id:'start',t:'T',l:'开始',x:700,y:30},
|
||||
{id:'home',t:'P',l:'健康咨询首页',x:700,y:110},
|
||||
{id:'d_entry',t:'D',l:'选择入口',x:700,y:200},
|
||||
// ---- 找专家主线 ----
|
||||
{id:'find',t:'P',l:'找专家页面',x:380,y:320},
|
||||
{id:'d_search',t:'D',l:'搜索方式',x:380,y:410},
|
||||
{id:'s_hosp',t:'P',l:'按医院→医院详情',x:120,y:520,w:150},
|
||||
{id:'s_dept',t:'P',l:'按科室',x:290,y:520,w:80},
|
||||
{id:'s_dis',t:'P',l:'按疾病',x:470,y:520,w:80},
|
||||
{id:'s_kw',t:'P',l:'综合搜索→搜索结果',x:640,y:520,w:160},
|
||||
{id:'expert_list',t:'P',l:'专家列表',x:380,y:620},
|
||||
{id:'expert_page',t:'P',l:'专家主页',x:380,y:700},
|
||||
{id:'d_type',t:'D',l:'咨询类型',x:380,y:790},
|
||||
// ---- 图文咨询 ----
|
||||
{id:'tw_notice',t:'P',l:'咨询须知弹窗',x:180,y:910},
|
||||
{id:'tw_person',t:'P',l:'选择咨询人',x:180,y:1000},
|
||||
{id:'tw_note1',t:'N',l:'可新增咨询人\n可新增健康档案\n可查看档案详情\n可快速咨询跳过',x:0,y:1000,w:150,h:70},
|
||||
{id:'tw_chat',t:'P',l:'图文咨询聊天',x:180,y:1090},
|
||||
{id:'tw_note2',t:'N',l:'可发送图片/拍摄\n体检报告/健康档案\n文件/位置',x:0,y:1090,w:140,h:50},
|
||||
{id:'d_tw_st',t:'D',l:'咨询状态',x:180,y:1190},
|
||||
{id:'tw_timeout',t:'T',l:'已超时',x:0,y:1320,c:'#fff1f0',sc:'#cf1322'},
|
||||
{id:'tw_end_dlg',t:'P',l:'结束咨询确认弹窗',x:180,y:1370,w:160},
|
||||
{id:'tw_auto',t:'P',l:'已完成(待评价)',x:380,y:1320,w:150},
|
||||
{id:'tw_done',t:'P',l:'已完成(待评价)',x:180,y:1460,w:150},
|
||||
{id:'tw_rate',t:'P',l:'评价医生',x:180,y:1550},
|
||||
{id:'tw_rated',t:'T',l:'已评价',x:180,y:1640,c:'#f6ffed',sc:'#52c41a'},
|
||||
// ---- 视频咨询 ----
|
||||
{id:'vd_notice',t:'P',l:'咨询须知弹窗',x:600,y:910},
|
||||
{id:'vd_person',t:'P',l:'选择咨询人',x:600,y:1000},
|
||||
{id:'vd_book',t:'P',l:'视频咨询预约',x:600,y:1090},
|
||||
{id:'vd_ok',t:'P',l:'预约成功',x:600,y:1170},
|
||||
{id:'vd_confirm',t:'P',l:'待确认',x:600,y:1250,c:'#f9f0ff',sc:'#722ed1'},
|
||||
{id:'d_vd_resp',t:'D',l:'医生响应',x:600,y:1340},
|
||||
{id:'vd_cancel',t:'T',l:'已取消',x:410,y:1450,c:'#f5f5f5',sc:'#999'},
|
||||
{id:'vd_pending',t:'P',l:'待开始',x:600,y:1450,c:'#fff7e6',sc:'#d46b08'},
|
||||
{id:'vd_reject',t:'T',l:'已拒绝',x:790,y:1450,c:'#f5f5f5',sc:'#999'},
|
||||
{id:'d_vd_time',t:'D',l:'到达预约时间',x:600,y:1550,w:140},
|
||||
{id:'vd_cancel2',t:'T',l:'已取消',x:410,y:1680,c:'#f5f5f5',sc:'#999'},
|
||||
{id:'vd_ing',t:'P',l:'进行中',x:600,y:1680,c:'#e6f4ff',sc:'#1677ff'},
|
||||
{id:'vd_done',t:'P',l:'已完成',x:600,y:1770,c:'#f6ffed',sc:'#52c41a'},
|
||||
{id:'vd_rate',t:'P',l:'评价医生',x:600,y:1860},
|
||||
{id:'vd_rated',t:'T',l:'已评价',x:600,y:1950,c:'#f6ffed',sc:'#52c41a'},
|
||||
// ---- 咨询小助手 ----
|
||||
{id:'ai_chat',t:'P',l:'小助手聊天页',x:980,y:320},
|
||||
{id:'ai_note',t:'N',l:'可发送图片/拍摄\n文件/位置',x:980,y:230,w:120,h:36},
|
||||
{id:'d_ai_st',t:'D',l:'咨询状态',x:980,y:430},
|
||||
{id:'ai_timeout',t:'T',l:'已超时',x:820,y:540,c:'#fff1f0',sc:'#cf1322'},
|
||||
{id:'ai_end_dlg',t:'P',l:'结束咨询确认弹窗',x:980,y:540,w:160},
|
||||
{id:'ai_auto',t:'P',l:'已完成',x:1150,y:540,w:140},
|
||||
{id:'ai_done',t:'P',l:'已完成',x:980,y:640,c:'#f6ffed',sc:'#52c41a'},
|
||||
// ---- 我的咨询 ----
|
||||
{id:'my_rec',t:'P',l:'我的咨询页面',x:1500,y:320},
|
||||
{id:'d_my_tab',t:'D',l:'选择类型',x:1500,y:430},
|
||||
{id:'my_tw',t:'P',l:'图文咨询记录',x:1330,y:550,w:130},
|
||||
{id:'my_vd',t:'P',l:'视频咨询记录',x:1500,y:550,w:130},
|
||||
{id:'my_ai',t:'P',l:'小助手记录',x:1670,y:550,w:120},
|
||||
{id:'d_my_tw',t:'D',l:'咨询状态',x:1330,y:660},
|
||||
{id:'my_tw_chat',t:'P',l:'继续聊天',x:1220,y:770,w:100},
|
||||
{id:'my_tw_detail',t:'P',l:'咨询详情',x:1430,y:770,w:100},
|
||||
{id:'my_tw_hist',t:'P',l:'历史对话(只读)',x:1430,y:860,w:140},
|
||||
{id:'my_vd_detail',t:'P',l:'视频咨询详情',x:1500,y:660,w:130},
|
||||
{id:'my_vd_note',t:'N',l:'按状态展示:\n待确认/待开始\n已完成/已取消/已拒绝',x:1650,y:770,w:140,h:50},
|
||||
{id:'my_ai_hist',t:'P',l:'小助手历史对话',x:1670,y:660,w:130},
|
||||
{id:'my_end',t:'T',l:'返回',x:1500,y:960,c:'#f6ffed',sc:'#52c41a'},
|
||||
];
|
||||
/* ===== 连线定义 [from, to, label?, waypoints?] ===== */
|
||||
const edges=[
|
||||
// 入口
|
||||
['start','home'],['home','d_entry'],
|
||||
['d_entry','find','找专家'],['d_entry','ai_chat','咨询小助手'],['d_entry','my_rec','我的咨询'],
|
||||
// 找专家
|
||||
['find','d_search'],
|
||||
['d_search','s_hosp','按医院'],['d_search','s_dept','按科室'],['d_search','s_dis','按疾病'],['d_search','s_kw','综合搜索'],
|
||||
['s_hosp','expert_list'],['s_dept','expert_list'],['s_dis','expert_list'],['s_kw','expert_list'],
|
||||
['expert_list','expert_page'],['expert_page','d_type'],
|
||||
['d_type','tw_notice','图文咨询'],['d_type','vd_notice','视频咨询'],
|
||||
// 图文咨询
|
||||
['tw_notice','tw_person'],['tw_person','tw_chat'],['tw_chat','d_tw_st'],
|
||||
['d_tw_st','tw_end_dlg','主动结束'],['d_tw_st','tw_timeout','未回复且超7天'],['d_tw_st','tw_auto','7天无回复\n自动完成'],
|
||||
['tw_end_dlg','tw_done'],['tw_done','tw_rate'],['tw_auto','tw_rate',null,[380,1460,380,1550]],
|
||||
['tw_rate','tw_rated'],
|
||||
// 视频咨询
|
||||
['vd_notice','vd_person'],['vd_person','vd_book'],['vd_book','vd_ok'],['vd_ok','vd_confirm'],
|
||||
['vd_confirm','d_vd_resp'],
|
||||
['d_vd_resp','vd_cancel','用户取消'],['d_vd_resp','vd_pending','医生确认'],['d_vd_resp','vd_reject','医生拒绝'],
|
||||
['vd_pending','d_vd_time'],
|
||||
['d_vd_time','vd_cancel2','用户取消'],['d_vd_time','vd_ing','到达时间'],
|
||||
['vd_ing','vd_done'],['vd_done','vd_rate'],['vd_rate','vd_rated'],
|
||||
// 小助手
|
||||
['ai_chat','d_ai_st'],
|
||||
['d_ai_st','ai_timeout','7天未回复'],['d_ai_st','ai_end_dlg','主动结束'],['d_ai_st','ai_auto','7天无回复\n自动完成'],
|
||||
['ai_end_dlg','ai_done'],['ai_done','ai_end'],
|
||||
// 我的咨询
|
||||
['my_rec','d_my_tab'],
|
||||
['d_my_tab','my_tw','图文'],['d_my_tab','my_vd','视频'],['d_my_tab','my_ai','小助手'],
|
||||
['my_tw','d_my_tw'],
|
||||
['d_my_tw','my_tw_chat','进行中'],['d_my_tw','my_tw_detail','已完成'],
|
||||
['my_tw_detail','my_tw_hist'],['my_tw_hist','my_end'],
|
||||
['my_vd','my_vd_detail'],['my_vd_detail','my_end'],
|
||||
['my_ai','my_ai_hist'],['my_ai_hist','my_end'],
|
||||
];
|
||||
|
||||
<script>
|
||||
// 统计当前目录页面数(静态标注)
|
||||
document.querySelector('[style*="margin-top:36px"]').innerHTML =
|
||||
'员工端 · 健康咨询模块 · 业务流程图';
|
||||
</script>
|
||||
/* ===== 注释连线(虚线)[from, to] ===== */
|
||||
const noteEdges=[
|
||||
['tw_note1','tw_person'],['tw_note2','tw_chat'],
|
||||
['ai_note','ai_chat'],['my_vd_note','my_vd_detail'],
|
||||
];
|
||||
/* ===== 渲染引擎 ===== */
|
||||
const NS='http://www.w3.org/2000/svg';
|
||||
const svg=document.getElementById('fc');
|
||||
const nMap={};
|
||||
nodes.forEach(n=>{nMap[n.id]=n;if(!n.w)n.w=W;if(!n.h)n.h=H;});
|
||||
|
||||
/* 创建SVG元素 */
|
||||
function el(tag,attrs){
|
||||
const e=document.createElementNS(NS,tag);
|
||||
for(const k in attrs)e.setAttribute(k,attrs[k]);
|
||||
return e;
|
||||
}
|
||||
|
||||
/* 多行文本 */
|
||||
function addText(g,txt,cx,cy,fs,fill,fw){
|
||||
const lines=txt.split('\n');
|
||||
const lh=fs*1.4;
|
||||
const startY=cy-((lines.length-1)*lh)/2;
|
||||
lines.forEach((line,i)=>{
|
||||
g.appendChild(el('text',{x:cx,y:startY+i*lh,'text-anchor':'middle','dominant-baseline':'central','font-size':fs,'fill':fill||'#333','font-weight':fw||'normal'})).textContent=line;
|
||||
});
|
||||
}
|
||||
|
||||
/* 获取节点锚点 */
|
||||
function anchor(n,side){
|
||||
const cx=n.x,cy=n.y,hw=n.w/2,hh=n.h/2;
|
||||
if(n.t==='D'){
|
||||
const dhw=Math.max(n.w||DW,DW)/2,dhh=DH/2;
|
||||
if(side==='t')return[cx,cy-dhh];if(side==='b')return[cx,cy+dhh];
|
||||
if(side==='l')return[cx-dhw,cy];if(side==='r')return[cx+dhw,cy];
|
||||
}
|
||||
if(side==='t')return[cx,cy-hh];if(side==='b')return[cx,cy+hh];
|
||||
if(side==='l')return[cx-hw,cy];if(side==='r')return[cx+hw,cy];
|
||||
return[cx,cy];
|
||||
}
|
||||
|
||||
/* 自动选择锚点方向 */
|
||||
function autoAnchors(fn,tn){
|
||||
const dx=tn.x-fn.x,dy=tn.y-fn.y;
|
||||
const adx=Math.abs(dx),ady=Math.abs(dy);
|
||||
if(ady>=adx){return dy>0?['b','t']:['t','b'];}
|
||||
else{return dx>0?['r','l']:['l','r'];}
|
||||
}
|
||||
|
||||
/* 绘制箭头连线 */
|
||||
function drawEdge(fid,tid,label,waypoints){
|
||||
const fn=nMap[fid],tn=nMap[tid];
|
||||
if(!fn||!tn)return;
|
||||
const[fs,ts]=autoAnchors(fn,tn);
|
||||
const[x1,y1]=anchor(fn,fs);
|
||||
const[x2,y2]=anchor(tn,ts);
|
||||
const g=el('g',{});
|
||||
const mid=`fc-arrow-${fid}-${tid}`;
|
||||
// 箭头标记
|
||||
if(!document.getElementById('ah')){
|
||||
const defs=el('defs',{});
|
||||
const mk=el('marker',{id:'ah',viewBox:'0 0 10 10',refX:'9',refY:'5',markerWidth:'8',markerHeight:'8',orient:'auto-start-reverse'});
|
||||
mk.appendChild(el('path',{d:'M 0 0 L 10 5 L 0 10 z',fill:'#999'}));
|
||||
defs.appendChild(mk);svg.appendChild(defs);
|
||||
}
|
||||
if(waypoints&&waypoints.length>=4){
|
||||
let d=`M${x1},${y1}`;
|
||||
for(let i=0;i<waypoints.length;i+=2)d+=` L${waypoints[i]},${waypoints[i+1]}`;
|
||||
d+=` L${x2},${y2}`;
|
||||
g.appendChild(el('path',{d:d,fill:'none',stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}else{
|
||||
// 折线连接
|
||||
if(fs==='b'&&ts==='t'){
|
||||
if(Math.abs(x1-x2)<2){
|
||||
g.appendChild(el('line',{x1,y1,x2,y2,stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}else{
|
||||
const my=(y1+y2)/2;
|
||||
g.appendChild(el('path',{d:`M${x1},${y1} L${x1},${my} L${x2},${my} L${x2},${y2}`,fill:'none',stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}
|
||||
}else if(fs==='r'&&ts==='l'){
|
||||
const mx=(x1+x2)/2;
|
||||
g.appendChild(el('path',{d:`M${x1},${y1} L${mx},${y1} L${mx},${y2} L${x2},${y2}`,fill:'none',stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}else if(fs==='l'&&ts==='r'){
|
||||
const mx=(x1+x2)/2;
|
||||
g.appendChild(el('path',{d:`M${x1},${y1} L${mx},${y1} L${mx},${y2} L${x2},${y2}`,fill:'none',stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}else if(fs==='l'&&ts==='t'){
|
||||
g.appendChild(el('path',{d:`M${x1},${y1} L${x2},${y1} L${x2},${y2}`,fill:'none',stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}else if(fs==='r'&&ts==='t'){
|
||||
g.appendChild(el('path',{d:`M${x1},${y1} L${x2},${y1} L${x2},${y2}`,fill:'none',stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}else{
|
||||
g.appendChild(el('line',{x1,y1,x2,y2,stroke:'#999','stroke-width':'1.5','marker-end':'url(#ah)'}));
|
||||
}
|
||||
}
|
||||
// 标签 - 放在靠近目标节点的1/3处,避免遮挡源节点
|
||||
if(label){
|
||||
const lx=x1+(x2-x1)*0.5, ly=y1+(y2-y1)*0.7;
|
||||
const lines=label.split('\n');
|
||||
const lh=11*1.3;
|
||||
const bw=Math.max(...lines.map(l=>l.length*11))+8;
|
||||
const bh=lines.length*lh+4;
|
||||
g.appendChild(el('rect',{x:lx-bw/2,y:ly-bh/2,width:bw,height:bh,rx:'3',fill:'#fff',stroke:'none',opacity:'0.9'}));
|
||||
addText(g,label,lx,ly,10,'#666');
|
||||
}
|
||||
svg.appendChild(g);
|
||||
}
|
||||
|
||||
/* 绘制注释虚线 */
|
||||
function drawNoteEdge(fid,tid){
|
||||
const fn=nMap[fid],tn=nMap[tid];
|
||||
if(!fn||!tn)return;
|
||||
const[fs,ts]=autoAnchors(fn,tn);
|
||||
const[x1,y1]=anchor(fn,fs==='b'?'r':fs==='t'?'r':fs);
|
||||
const[x2,y2]=anchor(tn,ts==='b'?'l':ts==='t'?'l':ts);
|
||||
svg.appendChild(el('line',{x1,y1,x2,y2,stroke:'#bbb','stroke-width':'1','stroke-dasharray':'4 3'}));
|
||||
}
|
||||
|
||||
/* 绘制节点 */
|
||||
function drawNode(n){
|
||||
const g=el('g',{});
|
||||
const cx=n.x,cy=n.y;
|
||||
if(n.t==='T'){
|
||||
const w=n.w,h=n.h;
|
||||
const fill=n.c||'#e8f4ff',sc=n.sc||'#1677ff';
|
||||
g.appendChild(el('rect',{x:cx-w/2,y:cy-h/2,width:w,height:h,rx:h/2,fill:fill,stroke:sc,'stroke-width':'2'}));
|
||||
addText(g,n.l,cx,cy,13,sc==='#52c41a'?'#389e0d':sc==='#cf1322'?'#cf1322':'#1677ff','600');
|
||||
}else if(n.t==='P'){
|
||||
const w=n.w,h=n.h;
|
||||
const fill=n.c||'#fff',sc=n.sc||'#595959';
|
||||
g.appendChild(el('rect',{x:cx-w/2,y:cy-h/2,width:w,height:h,rx:6,fill:fill,stroke:sc,'stroke-width':'1.5'}));
|
||||
addText(g,n.l,cx,cy,12,'#333','500');
|
||||
}else if(n.t==='D'){
|
||||
const dw=Math.max(n.w||DW,DW),dh=DH;
|
||||
const pts=`${cx},${cy-dh/2} ${cx+dw/2},${cy} ${cx},${cy+dh/2} ${cx-dw/2},${cy}`;
|
||||
g.appendChild(el('polygon',{points:pts,fill:'#fffbe6',stroke:'#d48806','stroke-width':'1.5'}));
|
||||
addText(g,n.l,cx,cy,12,'#8B6914','600');
|
||||
}else if(n.t==='N'){
|
||||
const w=n.w||140,h=n.h||50;
|
||||
g.appendChild(el('rect',{x:cx-w/2,y:cy-h/2,width:w,height:h,rx:4,fill:'#fafafa',stroke:'#ccc','stroke-width':'1','stroke-dasharray':'4 2'}));
|
||||
addText(g,n.l,cx,cy,10,'#999');
|
||||
}
|
||||
svg.appendChild(g);
|
||||
}
|
||||
|
||||
/* ===== 执行渲染 ===== */
|
||||
// 先画连线再画节点(节点覆盖连线)
|
||||
edges.forEach(e=>drawEdge(e[0],e[1],e[2]||null,e[3]||null));
|
||||
noteEdges.forEach(e=>drawNoteEdge(e[0],e[1]));
|
||||
nodes.forEach(n=>drawNode(n));
|
||||
|
||||
// 自动计算画布大小
|
||||
let maxX=0,maxY=0;
|
||||
nodes.forEach(n=>{
|
||||
const hw=(n.w||W)/2+20,hh=(n.h||H)/2+20;
|
||||
if(n.x+hw>maxX)maxX=n.x+hw;
|
||||
if(n.y+hh>maxY)maxY=n.y+hh;
|
||||
});
|
||||
svg.setAttribute('width',maxX+40);
|
||||
svg.setAttribute('height',maxY+40);
|
||||
svg.setAttribute('viewBox',`-100 0 ${maxX+160} ${maxY+40}`);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user