|
|
@@ -0,0 +1,1057 @@
|
|
|
+<!doctype html>
|
|
|
+<html lang="zh-CN">
|
|
|
+ <head>
|
|
|
+ <meta charset="UTF-8" />
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
+ <title>质检工单 · 同样本多工单 Tab 选型 · 第二组(强对比)</title>
|
|
|
+ <link
|
|
|
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
|
+ rel="stylesheet"
|
|
|
+ />
|
|
|
+ <link rel="stylesheet" href="_shared.css" />
|
|
|
+ <style>
|
|
|
+ .batch-note {
|
|
|
+ max-width: 960px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 0 24px 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .batch-note-inner {
|
|
|
+ padding: 12px 16px;
|
|
|
+ background: var(--primary-bg);
|
|
|
+ border: 1px solid #a7f3d0;
|
|
|
+ border-radius: 10px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #065f46;
|
|
|
+ line-height: 1.55;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ═══ N1 · 双色分栏顶栏 ═══ */
|
|
|
+ .n1-switcher {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ border-bottom: 3px solid var(--border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 6px;
|
|
|
+ min-height: 72px;
|
|
|
+ padding: 14px 16px;
|
|
|
+ border: none;
|
|
|
+ font-family: inherit;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: filter 0.15s, transform 0.1s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half:active {
|
|
|
+ transform: scale(0.98);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half--reception {
|
|
|
+ background: linear-gradient(180deg, #d1fae5 0%, var(--reception-bg) 100%);
|
|
|
+ color: var(--reception);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half--production {
|
|
|
+ background: linear-gradient(180deg, #fef3c7 0%, var(--production-bg) 100%);
|
|
|
+ color: var(--production);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half:not(.is-active) {
|
|
|
+ filter: saturate(0.35) brightness(1.08);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half:not(.is-active)::after {
|
|
|
+ content: '👆 点击切换';
|
|
|
+ position: absolute;
|
|
|
+ bottom: 6px;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 600;
|
|
|
+ opacity: 0.85;
|
|
|
+ animation: nudge 2s ease-in-out infinite;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes nudge {
|
|
|
+ 0%,
|
|
|
+ 100% {
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+ 50% {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half.is-active {
|
|
|
+ box-shadow: inset 0 -4px 0 currentColor;
|
|
|
+ filter: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half.is-active::before {
|
|
|
+ content: '当前查看';
|
|
|
+ position: absolute;
|
|
|
+ top: 6px;
|
|
|
+ right: 8px;
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 700;
|
|
|
+ padding: 2px 8px;
|
|
|
+ border-radius: 999px;
|
|
|
+ background: rgb(255 255 255 / 75%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half__title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ letter-spacing: 0.02em;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-half__sub {
|
|
|
+ font-size: 11px;
|
|
|
+ font-family: ui-monospace, Menlo, monospace;
|
|
|
+ opacity: 0.9;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-divider {
|
|
|
+ position: absolute;
|
|
|
+ left: 50%;
|
|
|
+ top: 12px;
|
|
|
+ bottom: 12px;
|
|
|
+ width: 2px;
|
|
|
+ background: rgb(15 23 42 / 12%);
|
|
|
+ transform: translateX(-50%);
|
|
|
+ pointer-events: none;
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n1-switcher-wrap {
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ═══ N2 · 双行清单 ═══ */
|
|
|
+ .n2-list {
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-list__head {
|
|
|
+ padding: 10px 16px 6px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ width: 100%;
|
|
|
+ padding: 12px 16px;
|
|
|
+ border: none;
|
|
|
+ border-top: 1px solid var(--border);
|
|
|
+ background: #fff;
|
|
|
+ font-family: inherit;
|
|
|
+ text-align: left;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background 0.15s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row:hover:not(.is-active) {
|
|
|
+ background: #f8fafc;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active {
|
|
|
+ background: var(--primary-bg);
|
|
|
+ box-shadow: inset 4px 0 0 var(--primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active[data-source='reception'] {
|
|
|
+ background: var(--reception-bg);
|
|
|
+ box-shadow: inset 4px 0 0 var(--reception);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active[data-source='production'] {
|
|
|
+ background: var(--production-bg);
|
|
|
+ box-shadow: inset 4px 0 0 var(--production);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row__radio {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ border-radius: 50%;
|
|
|
+ border: 2px solid #cbd5e1;
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active .n2-row__radio {
|
|
|
+ border-color: var(--primary);
|
|
|
+ background: var(--primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active[data-source='reception'] .n2-row__radio {
|
|
|
+ border-color: var(--reception);
|
|
|
+ background: var(--reception);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active[data-source='production'] .n2-row__radio {
|
|
|
+ border-color: var(--production);
|
|
|
+ background: var(--production);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active .n2-row__radio::after {
|
|
|
+ content: '';
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row__main {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row__type {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row__no {
|
|
|
+ font-size: 12px;
|
|
|
+ font-family: ui-monospace, Menlo, monospace;
|
|
|
+ color: var(--text-muted);
|
|
|
+ margin-top: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row:not(.is-active) .n2-row__action {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--primary-dark);
|
|
|
+ padding: 4px 10px;
|
|
|
+ border-radius: 6px;
|
|
|
+ background: var(--primary-bg);
|
|
|
+ border: 1px solid #a7f3d0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n2-row.is-active .n2-row__action {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ═══ N3 · 大开关 Toggle ═══ */
|
|
|
+ .n3-zone {
|
|
|
+ padding: 16px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ background: #f1f5f9;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-label {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle {
|
|
|
+ display: flex;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 420px;
|
|
|
+ padding: 5px;
|
|
|
+ border-radius: 14px;
|
|
|
+ background: #e2e8f0;
|
|
|
+ border: 2px solid #cbd5e1;
|
|
|
+ box-shadow: inset 0 2px 4px rgb(15 23 42 / 8%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle__btn {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+ padding: 14px 12px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 10px;
|
|
|
+ background: transparent;
|
|
|
+ font-family: inherit;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text-muted);
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle__btn.is-active[data-source='reception'] {
|
|
|
+ background: #fff;
|
|
|
+ color: var(--reception);
|
|
|
+ box-shadow: 0 2px 8px rgb(4 120 87 / 20%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle__btn.is-active[data-source='production'] {
|
|
|
+ background: #fff;
|
|
|
+ color: var(--production);
|
|
|
+ box-shadow: 0 2px 8px rgb(180 83 9 / 20%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle__btn:not(.is-active):hover {
|
|
|
+ color: var(--text);
|
|
|
+ background: rgb(255 255 255 / 50%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle__icon {
|
|
|
+ font-size: 22px;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-toggle__hint {
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 500;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n3-current {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ font-family: ui-monospace, Menlo, monospace;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ═══ N4 · 图标宫格二选一 ═══ */
|
|
|
+ .n4-zone {
|
|
|
+ padding: 16px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-head {
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-head__title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: var(--text);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-head__sub {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ margin-top: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 20px 16px 16px;
|
|
|
+ border: 3px solid var(--border);
|
|
|
+ border-radius: 14px;
|
|
|
+ background: #fff;
|
|
|
+ font-family: inherit;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: border-color 0.15s, transform 0.1s, box-shadow 0.15s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile:hover:not(.is-active) {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ box-shadow: 0 6px 16px rgb(15 23 42 / 10%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='reception']:not(.is-active) {
|
|
|
+ border-color: var(--reception-border);
|
|
|
+ border-style: dashed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='production']:not(.is-active) {
|
|
|
+ border-color: var(--production-border);
|
|
|
+ border-style: dashed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='reception'].is-active {
|
|
|
+ border-color: var(--reception);
|
|
|
+ border-style: solid;
|
|
|
+ background: var(--reception-bg);
|
|
|
+ box-shadow: 0 4px 12px rgb(4 120 87 / 15%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='production'].is-active {
|
|
|
+ border-color: var(--production);
|
|
|
+ border-style: solid;
|
|
|
+ background: var(--production-bg);
|
|
|
+ box-shadow: 0 4px 12px rgb(180 83 9 / 15%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile__icon {
|
|
|
+ width: 56px;
|
|
|
+ height: 56px;
|
|
|
+ border-radius: 16px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='reception'] .n4-tile__icon {
|
|
|
+ background: #fff;
|
|
|
+ color: var(--reception);
|
|
|
+ border: 2px solid var(--reception-border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='production'] .n4-tile__icon {
|
|
|
+ background: #fff;
|
|
|
+ color: var(--production);
|
|
|
+ border: 2px solid var(--production-border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile__name {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile__cta {
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ padding: 6px 14px;
|
|
|
+ border-radius: 999px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile:not(.is-active) .n4-tile__cta {
|
|
|
+ background: #f1f5f9;
|
|
|
+ color: var(--text);
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='reception']:not(.is-active) .n4-tile__cta {
|
|
|
+ background: var(--reception-bg);
|
|
|
+ color: var(--reception);
|
|
|
+ border: 1px solid var(--reception-border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile[data-source='production']:not(.is-active) .n4-tile__cta {
|
|
|
+ background: var(--production-bg);
|
|
|
+ color: var(--production);
|
|
|
+ border: 1px solid var(--production-border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile.is-active .n4-tile__cta {
|
|
|
+ background: rgb(255 255 255 / 80%);
|
|
|
+ color: inherit;
|
|
|
+ border: 1px solid rgb(0 0 0 / 8%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n4-tile__meta {
|
|
|
+ font-size: 11px;
|
|
|
+ font-family: ui-monospace, Menlo, monospace;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ═══ N5 · 双摘要条(两条始终可见) ═══ */
|
|
|
+ .n5-zone {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ background: #f8fafc;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-banner {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-banner strong {
|
|
|
+ color: var(--primary-dark);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-strip {
|
|
|
+ display: flex;
|
|
|
+ align-items: stretch;
|
|
|
+ gap: 8px;
|
|
|
+ min-height: 56px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 10px 12px;
|
|
|
+ border: 2px solid var(--border);
|
|
|
+ border-radius: 10px;
|
|
|
+ background: #fff;
|
|
|
+ font-family: inherit;
|
|
|
+ text-align: left;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.15s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip:not(.is-active) {
|
|
|
+ opacity: 0.72;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip:not(.is-active):hover {
|
|
|
+ opacity: 1;
|
|
|
+ border-color: #94a3b8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip.is-active[data-source='reception'] {
|
|
|
+ opacity: 1;
|
|
|
+ border-color: var(--reception);
|
|
|
+ background: var(--reception-bg);
|
|
|
+ box-shadow: 0 0 0 1px var(--reception);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip.is-active[data-source='production'] {
|
|
|
+ opacity: 1;
|
|
|
+ border-color: var(--production);
|
|
|
+ background: var(--production-bg);
|
|
|
+ box-shadow: 0 0 0 1px var(--production);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip__dot {
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip[data-source='reception'] .n5-chip__dot {
|
|
|
+ background: var(--reception);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip[data-source='production'] .n5-chip__dot {
|
|
|
+ background: var(--production);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip__body {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip__type {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 700;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip__status {
|
|
|
+ font-size: 11px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ margin-top: 1px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip:not(.is-active) .n5-chip__switch {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #fff;
|
|
|
+ padding: 4px 10px;
|
|
|
+ border-radius: 6px;
|
|
|
+ background: var(--primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n5-chip.is-active .n5-chip__switch {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 700;
|
|
|
+ padding: 3px 8px;
|
|
|
+ border-radius: 999px;
|
|
|
+ background: rgb(255 255 255 / 70%);
|
|
|
+ color: inherit;
|
|
|
+ border: 1px solid rgb(0 0 0 / 10%);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ═══ N6 · 左导航 + 右内容预览 ═══ */
|
|
|
+ .n6-layout {
|
|
|
+ display: flex;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ min-height: 120px;
|
|
|
+ }
|
|
|
+
|
|
|
+ @media (max-width: 560px) {
|
|
|
+ .n6-layout {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav {
|
|
|
+ width: 200px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ background: #f1f5f9;
|
|
|
+ border-right: 1px solid var(--border);
|
|
|
+ padding: 10px 8px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ @media (max-width: 560px) {
|
|
|
+ .n6-nav {
|
|
|
+ width: 100%;
|
|
|
+ flex-direction: row;
|
|
|
+ border-right: none;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__label {
|
|
|
+ padding: 4px 8px 6px;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: var(--text-muted);
|
|
|
+ text-transform: uppercase;
|
|
|
+ letter-spacing: 0.04em;
|
|
|
+ }
|
|
|
+
|
|
|
+ @media (max-width: 560px) {
|
|
|
+ .n6-nav__label {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__btn {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
+ padding: 12px 10px;
|
|
|
+ border: 2px solid transparent;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #fff;
|
|
|
+ font-family: inherit;
|
|
|
+ text-align: left;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.15s;
|
|
|
+ }
|
|
|
+
|
|
|
+ @media (max-width: 560px) {
|
|
|
+ .n6-nav__btn {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__btn:not(.is-active):hover {
|
|
|
+ border-color: #cbd5e1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__btn.is-active[data-source='reception'] {
|
|
|
+ border-color: var(--reception);
|
|
|
+ background: var(--reception-bg);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__btn.is-active[data-source='production'] {
|
|
|
+ border-color: var(--production);
|
|
|
+ background: var(--production-bg);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__btn:not(.is-active)::after {
|
|
|
+ content: '点击';
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__type {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 700;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-nav__no {
|
|
|
+ font-size: 10px;
|
|
|
+ font-family: ui-monospace, Menlo, monospace;
|
|
|
+ color: var(--text-muted);
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-preview {
|
|
|
+ flex: 1;
|
|
|
+ padding: 12px 16px;
|
|
|
+ background: #fff;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-preview__label {
|
|
|
+ font-size: 11px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-preview__title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-preview__no {
|
|
|
+ font-family: ui-monospace, Menlo, monospace;
|
|
|
+ font-size: 13px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .n6-preview__hint {
|
|
|
+ margin-top: 10px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--primary-dark);
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <header class="demo-banner">
|
|
|
+ <div>
|
|
|
+ <h1>第二组 · 强对比方案(6 套)</h1>
|
|
|
+ <p>
|
|
|
+ 上一组反馈「不够明显」。本组加大触控面积、始终展示两条工单、强化未选中态的视觉提示(虚线边框、👆 动画、Radio
|
|
|
+ 清单、大 Toggle 等)。<a href="compare-all.html" style="color: var(--primary-dark)">← 第一组</a>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="demo-banner__actions">
|
|
|
+ <a class="demo-link" href="index.html">索引</a>
|
|
|
+ </div>
|
|
|
+ </header>
|
|
|
+
|
|
|
+ <div class="batch-note">
|
|
|
+ <div class="batch-note-inner">
|
|
|
+ 设计原则:<strong>两条工单信息始终可见</strong>、<strong>未选中必须有明确「可点击」 affordance</strong>、<strong>来源类别用大面积色块区分</strong>(绿=样本接收,琥珀=生产过程)。
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="page-container">
|
|
|
+ <div class="compare-stack">
|
|
|
+ <section class="compare-block">
|
|
|
+ <div class="compare-block__label">
|
|
|
+ <h2>
|
|
|
+ <span class="variant-tag variant-tag--rec">推荐</span>
|
|
|
+ <span class="variant-tag">N1</span>
|
|
|
+ 双色分栏顶栏(整宽可点)
|
|
|
+ </h2>
|
|
|
+ <p>卡片顶部 50/50 分栏:左绿「样本接收」、右琥珀「生产过程」。未选中侧降饱和 + 底部「👆 点击切换」动画;选中侧底部色条 +「当前查看」角标。</p>
|
|
|
+ <div class="pros-cons">
|
|
|
+ <div class="pro">✓ 类别与可点击性一眼可见,占用高度适中</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="compare-block__body" id="block-n1"></div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="compare-block">
|
|
|
+ <div class="compare-block__label">
|
|
|
+ <h2><span class="variant-tag">N2</span> 双行 Radio 清单</h2>
|
|
|
+ <p>两条工单以列表行始终展示:Radio 圆点 + 类型 + 工单号。未选中行右侧绿色「切换至此」按钮;选中行左侧 4px 色条高亮。</p>
|
|
|
+ <div class="pros-cons">
|
|
|
+ <div class="pro">✓ 类似表单单选,学习成本最低</div>
|
|
|
+ <div class="pro">✓ 两条工单信息完整可见</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="compare-block__body" id="block-n2"></div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="compare-block">
|
|
|
+ <div class="compare-block__label">
|
|
|
+ <h2>
|
|
|
+ <span class="variant-tag variant-tag--rec">推荐</span>
|
|
|
+ <span class="variant-tag">N3</span>
|
|
|
+ 大开关 Toggle(二选一)
|
|
|
+ </h2>
|
|
|
+ <p>居中 oversized 分段开关,emoji 图标 + 15px 粗体类别名。切换时白底滑块 + 阴影动效,下方显示当前工单号。</p>
|
|
|
+ <div class="pros-cons">
|
|
|
+ <div class="pro">✓ 二选一语义最直白</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="compare-block__body" id="block-n3"></div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="compare-block">
|
|
|
+ <div class="compare-block__label">
|
|
|
+ <h2><span class="variant-tag">N4</span> 图标宫格(虚线 = 可点)</h2>
|
|
|
+ <p>两个 56px 大图标方块并排:未选中虚线边框 +「点击查看」圆角按钮;选中实线边框 + 整卡染色 + 阴影浮起。</p>
|
|
|
+ <div class="pros-cons">
|
|
|
+ <div class="pro">✓ 视觉重量最大,最难被忽略</div>
|
|
|
+ <div class="con">✗ 垂直空间占用较多</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="compare-block__body" id="block-n4"></div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="compare-block">
|
|
|
+ <div class="compare-block__label">
|
|
|
+ <h2><span class="variant-tag">N5</span> 双摘要条 + 切换按钮</h2>
|
|
|
+ <p>顶部提示「本样本有 2 条质检工单,请点击切换」;下方两条摘要 Chip 并排,未选中带绿色「切换」实心按钮。</p>
|
|
|
+ </div>
|
|
|
+ <div class="compare-block__body" id="block-n5"></div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="compare-block">
|
|
|
+ <div class="compare-block__label">
|
|
|
+ <h2><span class="variant-tag">N6</span> 左导航 + 右预览</h2>
|
|
|
+ <p>左侧固定 200px 导航列列出两条工单(未选中显示「点击」),右侧预览当前选中工单摘要——Master-Detail 模式。</p>
|
|
|
+ <div class="pros-cons">
|
|
|
+ <div class="pro">✓ 适合 3 条以上工单扩展</div>
|
|
|
+ <div class="con">✗ 横向空间占用大</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="compare-block__body" id="block-n6"></div>
|
|
|
+ </section>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ const MOCK = {
|
|
|
+ sampleCode: 'YB-2025-0618-0042',
|
|
|
+ subtitle: '张三 · 间充质干细胞 · 5×10⁶/支',
|
|
|
+ workOrders: [
|
|
|
+ {
|
|
|
+ id: 'wo-reception',
|
|
|
+ source: 'reception',
|
|
|
+ label: '样本接收',
|
|
|
+ emoji: '📦',
|
|
|
+ no: 'QC-IN-20250618-0012',
|
|
|
+ statusLabel: '已完成',
|
|
|
+ statusClass: 'tag--success'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'wo-production',
|
|
|
+ source: 'production',
|
|
|
+ label: '生产过程',
|
|
|
+ emoji: '⚙️',
|
|
|
+ no: 'QC-IN-20250620-0038',
|
|
|
+ statusLabel: '已配置',
|
|
|
+ statusClass: 'tag--warning'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ const ICONS = {
|
|
|
+ reception: `<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>`,
|
|
|
+ production: `<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>`
|
|
|
+ }
|
|
|
+
|
|
|
+ function ctxHeader() {
|
|
|
+ return `
|
|
|
+ <div class="qc-sample-row__ctx">
|
|
|
+ <span class="qc-sample-row__idx">1</span>
|
|
|
+ <span class="qc-sample-row__code">${MOCK.sampleCode}</span>
|
|
|
+ <span class="qc-sample-row__sub">${MOCK.subtitle}</span>
|
|
|
+ <span class="qc-sample-row__badge">${MOCK.workOrders.length} 条质检</span>
|
|
|
+ </div>`
|
|
|
+ }
|
|
|
+
|
|
|
+ function cardPlaceholder(wo) {
|
|
|
+ return `
|
|
|
+ <div class="qc-card-placeholder">
|
|
|
+ <div class="qc-card-placeholder__head">
|
|
|
+ <span class="qc-card-placeholder__no">${wo.no}</span>
|
|
|
+ <span class="tag ${wo.statusClass}">${wo.statusLabel}</span>
|
|
|
+ <span class="tag tag--${wo.source}">${wo.label}</span>
|
|
|
+ </div>
|
|
|
+ <div class="qc-card-placeholder__meta">
|
|
|
+ <span><strong>触发来源</strong>${wo.label}</span>
|
|
|
+ <span><strong>细胞类型</strong>间充质干细胞</span>
|
|
|
+ <span><strong>创建时间</strong>2025-06-18 14:32</span>
|
|
|
+ </div>
|
|
|
+ <div class="qc-card-placeholder__tasks">▼ 质检任务列表(${wo.label})</div>
|
|
|
+ </div>`
|
|
|
+ }
|
|
|
+
|
|
|
+ function wrap(inner, activeWo) {
|
|
|
+ return `<article class="qc-sample-row">${ctxHeader()}${inner}${cardPlaceholder(activeWo)}</article>`
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderN1(id) {
|
|
|
+ const active = MOCK.workOrders.find((w) => w.id === id)
|
|
|
+ const [a, b] = MOCK.workOrders
|
|
|
+ return wrap(
|
|
|
+ `<div class="n1-switcher-wrap">
|
|
|
+ <div class="n1-switcher" role="tablist">
|
|
|
+ <button type="button" class="n1-half n1-half--reception tab-btn ${a.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${a.id}" role="tab">
|
|
|
+ <span class="n1-half__title">${a.emoji} ${a.label}</span>
|
|
|
+ <span class="n1-half__sub">${a.no}</span>
|
|
|
+ </button>
|
|
|
+ <button type="button" class="n1-half n1-half--production tab-btn ${b.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${b.id}" role="tab">
|
|
|
+ <span class="n1-half__title">${b.emoji} ${b.label}</span>
|
|
|
+ <span class="n1-half__sub">${b.no}</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="n1-divider"></div>
|
|
|
+ </div>`,
|
|
|
+ active
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderN2(id) {
|
|
|
+ const active = MOCK.workOrders.find((w) => w.id === id)
|
|
|
+ const rows = MOCK.workOrders.map(
|
|
|
+ (wo) => `
|
|
|
+ <button type="button" class="n2-row tab-btn ${wo.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${wo.id}" data-source="${wo.source}" role="tab">
|
|
|
+ <span class="n2-row__radio"></span>
|
|
|
+ <span class="n2-row__main">
|
|
|
+ <div class="n2-row__type">${wo.label}</div>
|
|
|
+ <div class="n2-row__no">${wo.no}</div>
|
|
|
+ </span>
|
|
|
+ <span class="tag ${wo.statusClass}">${wo.statusLabel}</span>
|
|
|
+ <span class="n2-row__action">${wo.id === id ? '正在查看' : '切换至此'}</span>
|
|
|
+ </button>`
|
|
|
+ ).join('')
|
|
|
+ return wrap(
|
|
|
+ `<div class="n2-list">
|
|
|
+ <div class="n2-list__head">请选择要查看的质检工单(共 ${MOCK.workOrders.length} 条)</div>
|
|
|
+ ${rows}
|
|
|
+ </div>`,
|
|
|
+ active
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderN3(id) {
|
|
|
+ const active = MOCK.workOrders.find((w) => w.id === id)
|
|
|
+ const btns = MOCK.workOrders.map(
|
|
|
+ (wo) => `
|
|
|
+ <button type="button" class="n3-toggle__btn tab-btn ${wo.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${wo.id}" data-source="${wo.source}" role="tab">
|
|
|
+ <span class="n3-toggle__icon">${wo.emoji}</span>
|
|
|
+ <span>${wo.label}</span>
|
|
|
+ ${wo.id !== id ? '<span class="n3-toggle__hint">点击切换</span>' : ''}
|
|
|
+ </button>`
|
|
|
+ ).join('')
|
|
|
+ return wrap(
|
|
|
+ `<div class="n3-zone">
|
|
|
+ <div class="n3-label">本样本有两条质检工单,请选择查看:</div>
|
|
|
+ <div class="n3-toggle" role="tablist">${btns}</div>
|
|
|
+ <div class="n3-current">当前:${active.no} · ${active.statusLabel}</div>
|
|
|
+ </div>`,
|
|
|
+ active
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderN4(id) {
|
|
|
+ const active = MOCK.workOrders.find((w) => w.id === id)
|
|
|
+ const tiles = MOCK.workOrders.map(
|
|
|
+ (wo) => `
|
|
|
+ <button type="button" class="n4-tile tab-btn ${wo.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${wo.id}" data-source="${wo.source}" role="tab">
|
|
|
+ <span class="n4-tile__icon">${ICONS[wo.source]}</span>
|
|
|
+ <span class="n4-tile__name">${wo.label}</span>
|
|
|
+ <span class="n4-tile__meta">${wo.no}</span>
|
|
|
+ <span class="tag ${wo.statusClass}">${wo.statusLabel}</span>
|
|
|
+ <span class="n4-tile__cta">${wo.id === id ? '✓ 当前查看' : '点击查看'}</span>
|
|
|
+ </button>`
|
|
|
+ ).join('')
|
|
|
+ return wrap(
|
|
|
+ `<div class="n4-zone">
|
|
|
+ <div class="n4-head">
|
|
|
+ <div class="n4-head__title">选择质检工单类型</div>
|
|
|
+ <div class="n4-head__sub">虚线边框 = 可点击切换 · 实线 = 当前查看</div>
|
|
|
+ </div>
|
|
|
+ <div class="n4-grid">${tiles}</div>
|
|
|
+ </div>`,
|
|
|
+ active
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderN5(id) {
|
|
|
+ const active = MOCK.workOrders.find((w) => w.id === id)
|
|
|
+ const chips = MOCK.workOrders.map(
|
|
|
+ (wo) => `
|
|
|
+ <button type="button" class="n5-chip tab-btn ${wo.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${wo.id}" data-source="${wo.source}" role="tab">
|
|
|
+ <span class="n5-chip__dot"></span>
|
|
|
+ <span class="n5-chip__body">
|
|
|
+ <div class="n5-chip__type">${wo.label}</div>
|
|
|
+ <div class="n5-chip__status">${wo.no} · ${wo.statusLabel}</div>
|
|
|
+ </span>
|
|
|
+ <span class="n5-chip__switch">${wo.id === id ? '查看中' : '切换'}</span>
|
|
|
+ </button>`
|
|
|
+ ).join('')
|
|
|
+ return wrap(
|
|
|
+ `<div class="n5-zone">
|
|
|
+ <div class="n5-banner">
|
|
|
+ 💡 本样本有 <strong>2 条</strong>质检工单(样本接收 + 生产过程),请点击下方切换查看
|
|
|
+ </div>
|
|
|
+ <div class="n5-strip">${chips}</div>
|
|
|
+ </div>`,
|
|
|
+ active
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderN6(id) {
|
|
|
+ const active = MOCK.workOrders.find((w) => w.id === id)
|
|
|
+ const nav = MOCK.workOrders.map(
|
|
|
+ (wo) => `
|
|
|
+ <button type="button" class="n6-nav__btn tab-btn ${wo.id === id ? 'is-active' : ''}"
|
|
|
+ data-id="${wo.id}" data-source="${wo.source}" role="tab">
|
|
|
+ <span class="n6-nav__type">${wo.label}</span>
|
|
|
+ <span class="n6-nav__no">${wo.no}</span>
|
|
|
+ <span class="tag ${wo.statusClass}" style="margin-top:4px;height:20px;padding:0 6px;font-size:10px">${wo.statusLabel}</span>
|
|
|
+ </button>`
|
|
|
+ ).join('')
|
|
|
+ return wrap(
|
|
|
+ `<div class="n6-layout">
|
|
|
+ <nav class="n6-nav">
|
|
|
+ <div class="n6-nav__label">工单列表</div>
|
|
|
+ ${nav}
|
|
|
+ </nav>
|
|
|
+ <div class="n6-preview">
|
|
|
+ <div class="n6-preview__label">当前选中</div>
|
|
|
+ <div class="n6-preview__title">${active.label}</div>
|
|
|
+ <div class="n6-preview__no">${active.no}</div>
|
|
|
+ <span class="tag ${active.statusClass}">${active.statusLabel}</span>
|
|
|
+ <div class="n6-preview__hint">← 点击左侧另一条工单可切换</div>
|
|
|
+ </div>
|
|
|
+ </div>`,
|
|
|
+ active
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ const VARIANTS = {
|
|
|
+ n1: renderN1,
|
|
|
+ n2: renderN2,
|
|
|
+ n3: renderN3,
|
|
|
+ n4: renderN4,
|
|
|
+ n5: renderN5,
|
|
|
+ n6: renderN6
|
|
|
+ }
|
|
|
+
|
|
|
+ const state = Object.fromEntries(Object.keys(VARIANTS).map((k) => [k, 'wo-reception']))
|
|
|
+
|
|
|
+ function mount(key) {
|
|
|
+ const el = document.getElementById(`block-${key}`)
|
|
|
+ el.innerHTML = VARIANTS[key](state[key])
|
|
|
+ el.querySelectorAll('[data-id]').forEach((btn) => {
|
|
|
+ btn.addEventListener('click', () => {
|
|
|
+ state[key] = btn.dataset.id
|
|
|
+ mount(key)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ Object.keys(VARIANTS).forEach(mount)
|
|
|
+ </script>
|
|
|
+ </body>
|
|
|
+</html>
|