| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
- <title>山峡化工 · 运输计划(WebView H5 Demo)</title>
- <style>
- :root {
- --brand: #0a9f6d;
- --brand-dark: #087f57;
- --brand-soft: #e9f9f2;
- --barley: #d6a343;
- --barley-soft: #fff7e8;
- --bg: #f5f8f7;
- --surface: #ffffff;
- --text: #1f2a26;
- --muted: #6b7b74;
- --placeholder: #9aa8a1;
- --border: #dcebe4;
- --danger: #d14343;
- --warning: #cf8a19;
- --success: #189b65;
- --radius: 14px;
- --shadow: 0 6px 16px rgba(10, 159, 109, 0.08);
- --header: linear-gradient(145deg, #087f57 0%, #0a9f6d 72%, #d6a343 165%);
- }
- * { box-sizing: border-box; margin: 0; padding: 0; }
- body {
- background: #dfe8e3;
- color: var(--text);
- font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
- font-size: 14px;
- line-height: 1.45;
- }
- .stage {
- max-width: 980px;
- margin: 0 auto;
- padding: 20px 16px 40px;
- }
- .banner {
- background: #1f2a26;
- color: #fff;
- border-radius: 12px;
- padding: 14px 16px;
- margin-bottom: 16px;
- font-size: 13px;
- }
- .banner strong { color: #9fe3c4; }
- .banner code {
- background: rgba(255,255,255,.12);
- padding: 1px 6px;
- border-radius: 4px;
- font-size: 12px;
- }
- .grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
- gap: 18px;
- align-items: start;
- }
- .phone {
- max-width: 390px;
- margin: 0 auto;
- background: var(--bg);
- border-radius: 28px;
- overflow: hidden;
- box-shadow: 0 18px 40px rgba(0,0,0,.14);
- border: 8px solid #24312c;
- min-height: 760px;
- position: relative;
- }
- .phone-label {
- text-align: center;
- font-size: 12px;
- color: #4d5c56;
- margin-bottom: 8px;
- font-weight: 600;
- }
- .status-bar {
- height: 28px;
- background: var(--brand-dark);
- color: rgba(255,255,255,.85);
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 16px;
- font-size: 11px;
- }
- .header {
- background: var(--header);
- color: #fff;
- padding: 10px 14px 14px;
- }
- .header-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 8px;
- }
- .back { opacity: .92; font-size: 13px; }
- .header h1 { font-size: 20px; font-weight: 700; margin-top: 8px; }
- .header .hint {
- margin-top: 4px;
- font-size: 11px;
- opacity: .85;
- }
- .search {
- margin-top: 12px;
- background: rgba(255,255,255,.95);
- color: var(--placeholder);
- border-radius: 999px;
- padding: 10px 14px;
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 13px;
- }
- .search .dot {
- width: 8px; height: 8px; border-radius: 50%;
- background: var(--brand);
- flex-shrink: 0;
- }
- .date-row {
- display: flex;
- gap: 8px;
- overflow-x: auto;
- padding: 10px 12px 0;
- -webkit-overflow-scrolling: touch;
- }
- .chip {
- flex: 0 0 auto;
- padding: 6px 12px;
- border-radius: 999px;
- background: #fff;
- border: 1px solid var(--border);
- color: var(--muted);
- font-size: 12px;
- }
- .chip.active {
- background: var(--brand-soft);
- border-color: #b7ebce;
- color: var(--brand-dark);
- font-weight: 600;
- }
- .tabs {
- display: flex;
- gap: 6px;
- overflow-x: auto;
- padding: 10px 12px;
- -webkit-overflow-scrolling: touch;
- }
- .tab {
- flex: 0 0 auto;
- padding: 7px 12px;
- border-radius: 999px;
- background: #fff;
- border: 1px solid var(--border);
- color: var(--muted);
- font-size: 12px;
- cursor: pointer;
- }
- .tab.active {
- background: var(--brand);
- border-color: var(--brand);
- color: #fff;
- font-weight: 600;
- }
- .toolbar {
- display: flex;
- gap: 8px;
- padding: 0 12px 10px;
- overflow-x: auto;
- }
- .btn {
- flex: 0 0 auto;
- height: 34px;
- padding: 0 12px;
- border-radius: 8px;
- border: 1px solid var(--border);
- background: #fff;
- color: var(--text);
- font-size: 12px;
- cursor: pointer;
- display: inline-flex;
- align-items: center;
- gap: 4px;
- }
- .btn-primary {
- background: var(--brand);
- border-color: var(--brand);
- color: #fff;
- font-weight: 600;
- }
- .btn-danger {
- color: var(--danger);
- border-color: #f0c2c2;
- background: #fff7f7;
- }
- .list {
- padding: 0 12px 88px;
- display: flex;
- flex-direction: column;
- gap: 10px;
- }
- .card {
- background: var(--surface);
- border-radius: var(--radius);
- box-shadow: var(--shadow);
- padding: 12px 12px 10px;
- border: 1px solid rgba(220,235,228,.8);
- cursor: pointer;
- }
- .card:active { transform: scale(.995); }
- .card-head {
- display: flex;
- justify-content: space-between;
- gap: 8px;
- align-items: flex-start;
- }
- .plan-no {
- font-size: 15px;
- font-weight: 700;
- color: var(--brand-dark);
- }
- .sub {
- margin-top: 2px;
- font-size: 12px;
- color: var(--muted);
- }
- .tag {
- flex-shrink: 0;
- font-size: 11px;
- padding: 3px 8px;
- border-radius: 999px;
- font-weight: 600;
- color: #fff;
- }
- .tag-warn { background: #d97706; }
- .tag-ok { background: #059669; }
- .tag-mute { background: #64748b; }
- .tag-wait { background: #cf8a19; }
- .meta {
- margin-top: 8px;
- display: grid;
- gap: 4px;
- font-size: 12px;
- color: var(--muted);
- }
- .meta b { color: var(--text); font-weight: 500; }
- .products {
- margin-top: 8px;
- background: var(--brand-soft);
- border-radius: 10px;
- padding: 8px 10px;
- font-size: 12px;
- color: var(--brand-dark);
- }
- .card-foot {
- margin-top: 10px;
- display: flex;
- justify-content: flex-end;
- gap: 8px;
- flex-wrap: wrap;
- }
- .fab-bar {
- position: absolute;
- left: 0; right: 0; bottom: 0;
- padding: 10px 12px calc(12px + env(safe-area-inset-bottom, 0px));
- background: linear-gradient(180deg, transparent, var(--bg) 28%);
- display: flex;
- gap: 8px;
- }
- .fab-bar .btn { flex: 1; justify-content: center; height: 42px; font-size: 13px; }
- .fab-bar .btn-primary { flex: 1.35; }
- /* detail */
- .detail-body { padding: 12px; padding-bottom: 96px; }
- .section {
- background: #fff;
- border-radius: var(--radius);
- padding: 12px;
- margin-bottom: 10px;
- box-shadow: var(--shadow);
- }
- .section h3 {
- font-size: 13px;
- margin-bottom: 8px;
- color: var(--brand-dark);
- }
- .kv { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; font-size: 13px; border-bottom: 1px dashed var(--border); }
- .kv:last-child { border-bottom: none; }
- .kv span:first-child { color: var(--muted); flex-shrink: 0; }
- .kv span:last-child { text-align: right; }
- .actions-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 8px;
- }
- .actions-grid .btn { height: 40px; justify-content: center; }
- .note {
- margin-top: 8px;
- font-size: 11px;
- color: var(--muted);
- background: var(--barley-soft);
- border-radius: 8px;
- padding: 8px 10px;
- }
- .hidden { display: none !important; }
- .choice-hint {
- margin-top: 18px;
- background: #fff;
- border-radius: 12px;
- padding: 14px 16px;
- border: 1px solid #cfe3d9;
- font-size: 13px;
- color: #355248;
- }
- .choice-hint ol { margin: 8px 0 0 18px; }
- </style>
- </head>
- <body>
- <div class="stage">
- <div class="banner">
- <strong>运输计划 · 小程序 WebView H5 Demo</strong><br />
- 对齐管理端 <code>/#/pl/plan</code> 核心能力;小程序侧仅壳页 + <code>web-view</code> 加载本 H5,业务改动发 H5 即可,无需反复提审。<br />
- 文件路径:<code>bak/mobile-ui/shanxia-mp-pl-plan-webview-demo.html</code>
- </div>
- <div class="grid">
- <!-- LIST -->
- <div>
- <div class="phone-label">① 列表页(默认)</div>
- <div class="phone" id="phone-list">
- <div class="status-bar"><span>09:41</span><span>WebView</span></div>
- <header class="header">
- <div class="header-row">
- <span class="back">← 工作台</span>
- <button class="btn btn-primary" type="button" style="height:30px">+ 新增</button>
- </div>
- <h1>运输计划</h1>
- <div class="hint">登录态由小程序注入 Token · H5 调同一套 /api</div>
- <div class="search"><span class="dot"></span>计划编号 / 供方 / 需方 / 产品 / 车牌号</div>
- </header>
- <div class="date-row">
- <button class="chip active" type="button">今天</button>
- <button class="chip" type="button">明天</button>
- <button class="chip" type="button">本周</button>
- <button class="chip" type="button">本月</button>
- <button class="chip" type="button">自定义</button>
- </div>
- <div class="tabs" id="list-tabs">
- <button class="tab active" type="button" data-tab="pending">待安排</button>
- <button class="tab" type="button" data-tab="arranged">已安排</button>
- <button class="tab" type="button" data-tab="draft">草稿中</button>
- <button class="tab" type="button" data-tab="all">全部</button>
- <button class="tab" type="button" data-tab="inbound">入库单</button>
- <button class="tab" type="button" data-tab="outbound">出库单</button>
- <button class="tab" type="button" data-tab="direct">直销单</button>
- </div>
- <div class="toolbar">
- <button class="btn" type="button">复制</button>
- <button class="btn" type="button">安排运输</button>
- <button class="btn" type="button">等通知</button>
- <button class="btn" type="button">打印</button>
- <button class="btn btn-danger" type="button">作废</button>
- </div>
- <div class="list" id="plan-list">
- <!-- cards injected -->
- </div>
- <div class="fab-bar">
- <button class="btn" type="button">三方人车</button>
- <button class="btn btn-primary" type="button" onclick="showDetail()">查看选中计划</button>
- </div>
- </div>
- </div>
- <!-- DETAIL -->
- <div>
- <div class="phone-label">② 详情 / 操作(点卡片进入)</div>
- <div class="phone" id="phone-detail">
- <div class="status-bar"><span>09:41</span><span>WebView</span></div>
- <header class="header">
- <div class="header-row">
- <span class="back" style="cursor:pointer" onclick="showList()">← 列表</span>
- <span class="tag tag-warn">待安排</span>
- </div>
- <h1>JH20260914003</h1>
- <div class="hint">出库单 · 计划日期 2026-09-14</div>
- </header>
- <div class="detail-body">
- <div class="section">
- <h3>基本信息</h3>
- <div class="kv"><span>跟进状态</span><span><b>待安排</b></span></div>
- <div class="kv"><span>送货时间</span><span>09-14 14:00</span></div>
- <div class="kv"><span>车牌号</span><span>皖H·D1234 / 挂 皖H·G88</span></div>
- <div class="kv"><span>人员</span><span>司机 张伟 · 押运 李强</span></div>
- <div class="kv"><span>跟进人</span><span>王调度</span></div>
- </div>
- <div class="section">
- <h3>产品摘要</h3>
- <div class="products" style="margin:0">
- 甲醇 32 吨 · 包装吨袋<br />
- 供方:安庆山峡 · 需方:合肥某化
- </div>
- <div class="note">移动端以卡片摘要为主;完整编辑走「编辑计划」全屏表单(同管理端字段,分步/分区展示)。</div>
- </div>
- <div class="section">
- <h3>快捷操作(对齐管理端工具栏)</h3>
- <div class="actions-grid">
- <button class="btn btn-primary" type="button">安排运输</button>
- <button class="btn" type="button">编辑计划</button>
- <button class="btn" type="button">复制计划</button>
- <button class="btn" type="button">等客户通知</button>
- <button class="btn" type="button">打印单据</button>
- <button class="btn btn-danger" type="button">作废</button>
- </div>
- </div>
- </div>
- <div class="fab-bar">
- <button class="btn" type="button" onclick="showList()">返回列表</button>
- <button class="btn btn-primary" type="button">安排运输</button>
- </div>
- </div>
- </div>
- </div>
- <div class="choice-hint">
- <strong>请确认 Demo 方向(回复编号即可)</strong>
- <ol>
- <li><b>A</b> — 列表用「卡片流」如左图(推荐,适合手机一屏信息)</li>
- <li><b>B</b> — 列表尽量仿桌面表格(横滑多列,信息更全但操作更重)</li>
- <li><b>C</b> — 先只做列表+查看+安排运输,其余打印/作废/三方人车二期再上</li>
- </ol>
- 也可直接说要改哪里(Tab、按钮优先级、字段展示等)。
- </div>
- </div>
- <script>
- const plans = [
- {
- no: 'JH20260914003',
- type: '出库单',
- status: '待安排',
- tag: 'tag-warn',
- date: '2026-09-14',
- plate: '未派车',
- people: '—',
- product: '甲醇 32 吨 · 安庆山峡 → 合肥某化',
- tab: 'pending'
- },
- {
- no: 'JH20260914001',
- type: '入库单',
- status: '已安排',
- tag: 'tag-ok',
- date: '2026-09-14',
- plate: '皖H·D1234',
- people: '张伟 / 李强',
- product: '乙醇 28 吨 · 张家港 → 安庆仓',
- tab: 'arranged'
- },
- {
- no: 'JH20260913018',
- type: '直销单',
- status: '等通知',
- tag: 'tag-wait',
- date: '2026-09-13',
- plate: '苏E·5M892',
- people: '陈师傅',
- product: '冰醋酸 20 吨 · 南通 → 芜湖',
- tab: 'pending'
- },
- {
- no: 'JH20260912007',
- type: '出库单',
- status: '草稿中',
- tag: 'tag-mute',
- date: '2026-09-12',
- plate: '—',
- people: '—',
- product: '待完善产品行',
- tab: 'draft'
- }
- ]
- const listEl = document.getElementById('plan-list')
- let activeTab = 'pending'
- function renderList() {
- const rows = activeTab === 'all'
- ? plans
- : plans.filter((p) => {
- if (activeTab === 'pending') return p.status === '待安排' || p.status === '等通知'
- if (activeTab === 'arranged') return p.status === '已安排'
- if (activeTab === 'draft') return p.status === '草稿中'
- if (activeTab === 'inbound') return p.type === '入库单'
- if (activeTab === 'outbound') return p.type === '出库单'
- if (activeTab === 'direct') return p.type === '直销单'
- return true
- })
- listEl.innerHTML = rows.map((p) => `
- <article class="card" onclick="showDetail()">
- <div class="card-head">
- <div>
- <div class="plan-no">${p.no}</div>
- <div class="sub">${p.type} · ${p.date}</div>
- </div>
- <span class="tag ${p.tag}">${p.status}</span>
- </div>
- <div class="meta">
- <div>车牌:<b>${p.plate}</b></div>
- <div>人员:<b>${p.people}</b></div>
- </div>
- <div class="products">${p.product}</div>
- <div class="card-foot">
- <button class="btn" type="button" onclick="event.stopPropagation()">复制</button>
- <button class="btn btn-primary" type="button" onclick="event.stopPropagation()">安排运输</button>
- </div>
- </article>
- `).join('') || '<div style="padding:24px;text-align:center;color:#6b7b74">该 Tab 暂无数据</div>'
- }
- document.getElementById('list-tabs').addEventListener('click', (e) => {
- const btn = e.target.closest('.tab')
- if (!btn) return
- document.querySelectorAll('#list-tabs .tab').forEach((t) => t.classList.remove('active'))
- btn.classList.add('active')
- activeTab = btn.dataset.tab
- renderList()
- })
- document.querySelectorAll('.date-row .chip').forEach((chip) => {
- chip.addEventListener('click', () => {
- document.querySelectorAll('.date-row .chip').forEach((c) => c.classList.remove('active'))
- chip.classList.add('active')
- })
- })
- function showDetail() {
- document.getElementById('phone-list').classList.add('hidden')
- document.getElementById('phone-detail').classList.remove('hidden')
- // on dual layout keep both; on narrow, scroll to detail
- document.getElementById('phone-detail').scrollIntoView({ behavior: 'smooth', block: 'start' })
- }
- function showList() {
- document.getElementById('phone-list').classList.remove('hidden')
- document.getElementById('phone-list').scrollIntoView({ behavior: 'smooth', block: 'start' })
- }
- renderList()
- </script>
- </body>
- </html>
|