b90a89790f
统一 nav(5 个链接含支持、auth-aware 用户下拉菜单)、 docs 页补充面包屑/搜索/版本栏三栏布局、 footer 完整 5 列、所有内链替换为生产绝对路径。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1168 lines
41 KiB
HTML
1168 lines
41 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>文档 · 岩美酒库管理系统</title>
|
||
<link rel="stylesheet" href="assets/colors_and_type.css" />
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||
<script src="https://unpkg.com/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||
<style>
|
||
* { box-sizing: border-box; }
|
||
html, body {
|
||
margin: 0; padding: 0;
|
||
font-family: var(--font-sans);
|
||
color: var(--fg-default);
|
||
background: var(--bg-surface);
|
||
-webkit-font-smoothing: antialiased;
|
||
text-rendering: optimizeLegibility;
|
||
font-feature-settings: "tnum" 1;
|
||
scroll-behavior: smooth;
|
||
}
|
||
img, svg { display: block; max-width: 100%; }
|
||
a { color: inherit; text-decoration: none; }
|
||
button { font-family: inherit; cursor: pointer; }
|
||
|
||
/* ---------------- Buttons (shared) ---------------- */
|
||
.btn {
|
||
display: inline-flex; align-items: center; gap: 8px;
|
||
height: 40px; padding: 0 18px;
|
||
border-radius: var(--radius-md);
|
||
font-size: var(--text-md); font-weight: 500;
|
||
border: 1px solid transparent;
|
||
transition: background var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.btn-primary { background: var(--brand-500); color: #fff; }
|
||
.btn-primary:hover { background: var(--brand-600); }
|
||
.btn-secondary { background: var(--gray-0); color: var(--brand-900); border-color: var(--border-default); }
|
||
.btn-secondary:hover { background: var(--gray-50); border-color: var(--border-strong); }
|
||
.btn-ghost { background: transparent; color: var(--fg-default); }
|
||
.btn-ghost:hover { background: var(--gray-100); }
|
||
.btn .icon { width: 18px; height: 18px; }
|
||
|
||
/* ---------------- Top Nav (shared) ---------------- */
|
||
.topnav {
|
||
position: sticky; top: 0; z-index: 50;
|
||
background: rgba(255,255,255,0.85);
|
||
backdrop-filter: blur(12px);
|
||
-webkit-backdrop-filter: blur(12px);
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
.topnav-inner {
|
||
height: 64px;
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
max-width: 1440px; margin: 0 auto; padding: 0 32px;
|
||
}
|
||
.topnav-brand { display: flex; align-items: center; gap: 10px; }
|
||
.topnav-brand img { height: 32px; }
|
||
.topnav-links { display: flex; align-items: center; gap: 4px; font-size: var(--text-md); color: var(--gray-700); }
|
||
.topnav-links a {
|
||
padding: 8px 14px;
|
||
border-radius: var(--radius-md);
|
||
transition: background var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.topnav-links a:hover { background: var(--gray-100); color: var(--brand-900); }
|
||
.topnav-links a.active { color: var(--brand-500); background: var(--brand-50); }
|
||
.topnav-cta { display: flex; gap: 10px; align-items: center; }
|
||
|
||
/* nav user dropdown */
|
||
.nav-user { position: relative; }
|
||
.nav-user-btn { display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 12px; background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-pill); cursor: pointer; font-size: var(--text-md); color: var(--gray-800); font-weight: 500; transition: border-color var(--duration-fast) var(--ease-standard); }
|
||
.nav-user-btn:hover { border-color: var(--border-strong); }
|
||
.nav-avatar { width: 22px; height: 22px; border-radius: 50%; background: var(--brand-500); color: #fff; display: grid; place-items: center; font-size: 10px; font-weight: 700; flex-shrink: 0; }
|
||
.nav-user-btn .icon { width: 14px; height: 14px; color: var(--fg-muted); }
|
||
.nav-dropdown { display: none; position: absolute; top: calc(100% + 8px); right: 0; min-width: 160px; background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden; z-index: 100; }
|
||
.nav-dropdown.open { display: block; }
|
||
.nav-dropdown a, .nav-dropdown button { display: flex; align-items: center; gap: 8px; width: 100%; padding: 10px 14px; font-size: var(--text-sm); color: var(--gray-800); background: none; border: none; cursor: pointer; text-decoration: none; font-family: inherit; transition: background var(--duration-fast) var(--ease-standard); }
|
||
.nav-dropdown a:hover, .nav-dropdown button:hover { background: var(--gray-50); }
|
||
.nav-dropdown .icon { width: 14px; height: 14px; color: var(--fg-muted); }
|
||
.nav-dropdown-divider { height: 1px; background: var(--border-subtle); margin: 4px 0; }
|
||
.nav-dropdown .logout { color: var(--danger-600); }
|
||
|
||
/* ====================================================================
|
||
DOCS SUB-HEADER
|
||
==================================================================== */
|
||
.docs-subnav {
|
||
background: var(--gray-25);
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
position: sticky;
|
||
top: 64px;
|
||
z-index: 40;
|
||
}
|
||
.docs-subnav-inner {
|
||
max-width: 1440px;
|
||
margin: 0 auto;
|
||
padding: 12px 32px;
|
||
display: flex; align-items: center; gap: 24px;
|
||
}
|
||
.breadcrumb {
|
||
display: flex; align-items: center; gap: 8px;
|
||
font-size: var(--text-sm);
|
||
color: var(--fg-muted);
|
||
}
|
||
.breadcrumb .sep { color: var(--gray-300); }
|
||
.breadcrumb a { color: var(--fg-muted); }
|
||
.breadcrumb a:hover { color: var(--brand-500); }
|
||
.breadcrumb .current { color: var(--gray-900); font-weight: 500; }
|
||
|
||
.docs-search {
|
||
flex: 1; max-width: 480px;
|
||
position: relative;
|
||
}
|
||
.docs-search input {
|
||
width: 100%;
|
||
height: 36px;
|
||
padding: 0 12px 0 38px;
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-md);
|
||
background: var(--gray-0);
|
||
font-family: inherit;
|
||
font-size: var(--text-sm);
|
||
color: var(--gray-800);
|
||
outline: none;
|
||
transition: border-color var(--duration-fast) var(--ease-standard),
|
||
box-shadow var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.docs-search input:focus { border-color: var(--brand-500); box-shadow: var(--ring-focus); }
|
||
.docs-search input::placeholder { color: var(--fg-subtle); }
|
||
.docs-search .search-icon {
|
||
position: absolute;
|
||
left: 12px; top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 16px; height: 16px;
|
||
color: var(--fg-subtle);
|
||
}
|
||
.docs-search .kbd {
|
||
position: absolute;
|
||
right: 8px; top: 50%;
|
||
transform: translateY(-50%);
|
||
background: var(--gray-100);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: 3px;
|
||
padding: 2px 6px;
|
||
font-size: 11px;
|
||
color: var(--fg-muted);
|
||
font-family: var(--font-mono);
|
||
}
|
||
|
||
.docs-version {
|
||
display: flex; align-items: center; gap: 6px;
|
||
background: var(--gray-0);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-md);
|
||
padding: 6px 12px;
|
||
font-size: var(--text-sm);
|
||
color: var(--gray-700);
|
||
}
|
||
.docs-version .icon { width: 14px; height: 14px; }
|
||
.docs-version-label { color: var(--fg-subtle); font-size: var(--text-xs); }
|
||
|
||
/* ====================================================================
|
||
DOCS LAYOUT
|
||
==================================================================== */
|
||
.docs-layout {
|
||
max-width: 1440px;
|
||
margin: 0 auto;
|
||
padding: 32px;
|
||
display: grid;
|
||
grid-template-columns: 240px 1fr 240px;
|
||
gap: 48px;
|
||
align-items: start;
|
||
}
|
||
|
||
/* Left TOC */
|
||
.docs-toc {
|
||
position: sticky;
|
||
top: 132px;
|
||
max-height: calc(100vh - 152px);
|
||
overflow-y: auto;
|
||
font-size: var(--text-sm);
|
||
}
|
||
.toc-section {
|
||
margin-bottom: 18px;
|
||
}
|
||
.toc-section-title {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.06em;
|
||
color: var(--fg-subtle);
|
||
text-transform: uppercase;
|
||
margin: 0 0 10px;
|
||
padding-left: 12px;
|
||
}
|
||
.toc-link {
|
||
display: flex; align-items: center; gap: 10px;
|
||
padding: 7px 12px;
|
||
border-radius: var(--radius-sm);
|
||
color: var(--gray-700);
|
||
font-weight: 400;
|
||
transition: background var(--duration-fast) var(--ease-standard),
|
||
color var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.toc-link:hover { background: var(--gray-100); color: var(--brand-900); }
|
||
.toc-link .toc-num {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--fg-subtle);
|
||
min-width: 16px;
|
||
font-weight: 500;
|
||
}
|
||
.toc-link.active {
|
||
background: var(--brand-50);
|
||
color: var(--brand-700);
|
||
font-weight: 500;
|
||
}
|
||
.toc-link.active .toc-num { color: var(--brand-500); }
|
||
.toc-sub {
|
||
margin: 4px 0 4px 28px;
|
||
padding-left: 12px;
|
||
border-left: 1px solid var(--border-subtle);
|
||
display: flex; flex-direction: column;
|
||
gap: 1px;
|
||
}
|
||
.toc-sub a {
|
||
display: block;
|
||
padding: 5px 10px;
|
||
border-radius: var(--radius-sm);
|
||
font-size: 13px;
|
||
color: var(--fg-muted);
|
||
}
|
||
.toc-sub a:hover { color: var(--brand-700); background: var(--gray-50); }
|
||
.toc-sub a.active {
|
||
color: var(--brand-700);
|
||
font-weight: 500;
|
||
border-left: 2px solid var(--brand-500);
|
||
margin-left: -14px;
|
||
padding-left: 12px;
|
||
border-radius: 0;
|
||
}
|
||
|
||
/* ====================================================================
|
||
MAIN CONTENT
|
||
==================================================================== */
|
||
.docs-main { min-width: 0; max-width: 760px; }
|
||
.docs-main h1 {
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
letter-spacing: var(--tracking-cn-display);
|
||
color: var(--brand-900);
|
||
margin: 0 0 12px;
|
||
line-height: 1.2;
|
||
}
|
||
.docs-main .doc-section-num {
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-md);
|
||
font-weight: 500;
|
||
color: var(--brand-500);
|
||
margin-bottom: 8px;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
.docs-main .lead {
|
||
font-size: var(--text-lg);
|
||
color: var(--gray-600);
|
||
line-height: 1.65;
|
||
margin: 0 0 32px;
|
||
padding-bottom: 24px;
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
.docs-main h2 {
|
||
font-size: var(--text-2xl);
|
||
font-weight: 600;
|
||
color: var(--brand-900);
|
||
margin: 56px 0 16px;
|
||
letter-spacing: 0.02em;
|
||
scroll-margin-top: 132px;
|
||
display: flex; align-items: center; gap: 12px;
|
||
}
|
||
.docs-main h2 .anchor {
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-md);
|
||
font-weight: 500;
|
||
color: var(--brand-500);
|
||
}
|
||
.docs-main h2:first-of-type { margin-top: 0; }
|
||
.docs-main h3 {
|
||
font-size: var(--text-lg);
|
||
font-weight: 600;
|
||
color: var(--gray-900);
|
||
margin: 36px 0 12px;
|
||
}
|
||
.docs-main p {
|
||
font-size: var(--text-md);
|
||
color: var(--gray-700);
|
||
line-height: 1.75;
|
||
margin: 0 0 16px;
|
||
}
|
||
.docs-main strong { color: var(--brand-900); font-weight: 600; }
|
||
.docs-main em { color: var(--brand-700); font-style: normal; font-weight: 500; }
|
||
.docs-main code {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.92em;
|
||
background: var(--gray-100);
|
||
color: var(--brand-700);
|
||
padding: 1px 6px;
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
.docs-main a {
|
||
color: var(--brand-500);
|
||
font-weight: 500;
|
||
border-bottom: 1px solid var(--brand-200);
|
||
}
|
||
.docs-main a:hover { color: var(--brand-700); border-color: var(--brand-500); }
|
||
|
||
.docs-main ol, .docs-main ul {
|
||
margin: 0 0 16px;
|
||
padding-left: 24px;
|
||
}
|
||
.docs-main li {
|
||
font-size: var(--text-md);
|
||
color: var(--gray-700);
|
||
line-height: 1.75;
|
||
margin-bottom: 6px;
|
||
}
|
||
.docs-main ol li::marker {
|
||
color: var(--brand-500);
|
||
font-weight: 600;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
/* Callouts */
|
||
.callout {
|
||
display: grid;
|
||
grid-template-columns: 24px 1fr;
|
||
gap: 14px;
|
||
padding: 16px 20px;
|
||
border-radius: var(--radius-md);
|
||
margin: 24px 0;
|
||
border-left: 3px solid;
|
||
}
|
||
.callout .icon { width: 20px; height: 20px; margin-top: 2px; }
|
||
.callout-title {
|
||
font-weight: 600;
|
||
font-size: var(--text-sm);
|
||
margin-bottom: 4px;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
.callout p { font-size: var(--text-sm); color: var(--gray-700); margin: 0; line-height: 1.6; }
|
||
.callout.info { background: var(--info-50); border-color: var(--info-500); }
|
||
.callout.info .icon, .callout.info .callout-title { color: var(--info-700); }
|
||
.callout.warning { background: var(--warning-50); border-color: var(--warning-500); }
|
||
.callout.warning .icon, .callout.warning .callout-title { color: var(--warning-700); }
|
||
.callout.danger { background: var(--danger-50); border-color: var(--danger-500); }
|
||
.callout.danger .icon, .callout.danger .callout-title { color: var(--danger-700); }
|
||
.callout.success { background: var(--success-50); border-color: var(--success-500); }
|
||
.callout.success .icon, .callout.success .callout-title { color: var(--success-700); }
|
||
|
||
/* Code block */
|
||
.code-block {
|
||
background: var(--gray-900);
|
||
color: #DCE2EB;
|
||
padding: 18px 20px;
|
||
border-radius: var(--radius-md);
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-sm);
|
||
line-height: 1.7;
|
||
margin: 16px 0 24px;
|
||
overflow-x: auto;
|
||
position: relative;
|
||
white-space: pre;
|
||
}
|
||
.code-block .copy {
|
||
position: absolute;
|
||
top: 12px; right: 12px;
|
||
background: rgba(255,255,255,0.06);
|
||
border: 1px solid rgba(255,255,255,0.10);
|
||
color: #ADC9EA;
|
||
border-radius: var(--radius-sm);
|
||
padding: 4px 10px;
|
||
font-size: 11px;
|
||
font-family: inherit;
|
||
cursor: pointer;
|
||
}
|
||
.code-block .copy:hover { background: rgba(255,255,255,0.12); color: #fff; }
|
||
|
||
/* Tables */
|
||
.docs-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 16px 0 24px;
|
||
font-size: var(--text-sm);
|
||
background: var(--gray-0);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-md);
|
||
overflow: hidden;
|
||
}
|
||
.docs-table th, .docs-table td {
|
||
padding: 12px 16px;
|
||
text-align: left;
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
line-height: 1.55;
|
||
}
|
||
.docs-table thead th {
|
||
background: var(--gray-50);
|
||
font-size: var(--text-xs);
|
||
font-weight: 600;
|
||
color: var(--gray-700);
|
||
letter-spacing: 0.02em;
|
||
text-transform: uppercase;
|
||
border-bottom: 1px solid var(--border-default);
|
||
}
|
||
.docs-table tbody tr:last-child td { border-bottom: none; }
|
||
.docs-table tbody tr:hover { background: var(--gray-25); }
|
||
.docs-table td code { font-size: 12px; }
|
||
.docs-table .status-pill {
|
||
display: inline-block;
|
||
padding: 2px 10px;
|
||
border-radius: var(--radius-pill);
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
}
|
||
.docs-table .status-pill.draft { background: var(--gray-100); color: var(--gray-700); }
|
||
.docs-table .status-pill.pending { background: var(--info-50); color: var(--info-700); }
|
||
.docs-table .status-pill.approved { background: var(--success-50); color: var(--success-700); }
|
||
.docs-table .status-pill.rejected { background: var(--danger-50); color: var(--danger-700); }
|
||
|
||
/* Status flow visual */
|
||
.status-flow {
|
||
background: var(--gray-25);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-md);
|
||
padding: 24px 20px;
|
||
margin: 16px 0 24px;
|
||
overflow-x: auto;
|
||
}
|
||
.status-flow-track {
|
||
display: flex; align-items: center; gap: 0;
|
||
min-width: max-content;
|
||
justify-content: center;
|
||
}
|
||
.flow-node {
|
||
display: flex; flex-direction: column;
|
||
align-items: center; gap: 6px;
|
||
padding: 0 4px;
|
||
}
|
||
.flow-node .badge {
|
||
padding: 6px 14px;
|
||
background: var(--gray-0);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-pill);
|
||
font-size: var(--text-sm);
|
||
font-weight: 500;
|
||
color: var(--gray-800);
|
||
}
|
||
.flow-node.draft .badge { color: var(--gray-700); }
|
||
.flow-node.pending .badge { background: var(--info-50); border-color: var(--info-500); color: var(--info-700); }
|
||
.flow-node.approved .badge { background: var(--success-50); border-color: var(--success-500); color: var(--success-700); font-weight: 600; }
|
||
.flow-node.rejected .badge { background: var(--danger-50); border-color: var(--danger-500); color: var(--danger-700); }
|
||
.flow-node small { font-size: 11px; color: var(--fg-subtle); }
|
||
|
||
.flow-arrow {
|
||
color: var(--gray-300);
|
||
padding: 0 8px;
|
||
display: flex; align-items: center;
|
||
}
|
||
.flow-arrow .icon { width: 18px; height: 18px; }
|
||
.flow-arrow.fork {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 0 12px;
|
||
position: relative;
|
||
}
|
||
.flow-fork-wrap { display: flex; flex-direction: column; gap: 12px; }
|
||
|
||
/* Steps list */
|
||
.steps {
|
||
counter-reset: step;
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 16px 0 24px;
|
||
}
|
||
.steps li {
|
||
counter-increment: step;
|
||
display: grid;
|
||
grid-template-columns: 32px 1fr;
|
||
gap: 16px;
|
||
margin-bottom: 14px;
|
||
align-items: flex-start;
|
||
}
|
||
.steps li::before {
|
||
content: counter(step);
|
||
width: 28px; height: 28px;
|
||
background: var(--brand-50);
|
||
color: var(--brand-700);
|
||
border-radius: 50%;
|
||
display: grid; place-items: center;
|
||
font-size: var(--text-sm);
|
||
font-weight: 600;
|
||
font-variant-numeric: tabular-nums;
|
||
margin-top: 1px;
|
||
}
|
||
.steps li > div { font-size: var(--text-md); color: var(--gray-700); line-height: 1.7; }
|
||
.steps li strong { color: var(--brand-900); font-weight: 600; }
|
||
|
||
/* Field reference list */
|
||
.field-list {
|
||
background: var(--gray-25);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-md);
|
||
padding: 4px 0;
|
||
margin: 16px 0 24px;
|
||
}
|
||
.field-row {
|
||
display: grid;
|
||
grid-template-columns: 120px 80px 1fr;
|
||
gap: 16px;
|
||
padding: 10px 20px;
|
||
align-items: baseline;
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
.field-row:last-child { border-bottom: none; }
|
||
.field-name { font-family: var(--font-mono); font-size: 13px; color: var(--brand-700); font-weight: 500; }
|
||
.field-required {
|
||
display: inline-block;
|
||
font-size: 10px;
|
||
background: var(--danger-50);
|
||
color: var(--danger-700);
|
||
padding: 1px 8px;
|
||
border-radius: var(--radius-pill);
|
||
font-weight: 500;
|
||
text-align: center;
|
||
}
|
||
.field-required.optional { background: var(--gray-100); color: var(--gray-700); }
|
||
.field-desc { font-size: var(--text-sm); color: var(--gray-700); line-height: 1.55; }
|
||
|
||
/* Section divider with anchor */
|
||
.section-anchor {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
color: var(--fg-subtle); margin-left: 8px;
|
||
opacity: 0; transition: opacity var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.docs-main h2:hover .section-anchor, .docs-main h3:hover .section-anchor { opacity: 1; }
|
||
|
||
/* Prev/Next nav */
|
||
.docs-pager {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 16px;
|
||
margin-top: 64px;
|
||
padding-top: 32px;
|
||
border-top: 1px solid var(--border-subtle);
|
||
}
|
||
.pager-link {
|
||
display: flex; flex-direction: column;
|
||
padding: 18px 22px;
|
||
background: var(--gray-0);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-lg);
|
||
transition: border-color var(--duration-base) var(--ease-standard),
|
||
box-shadow var(--duration-base) var(--ease-standard);
|
||
}
|
||
.pager-link:hover { border-color: var(--brand-300); box-shadow: var(--shadow-sm); }
|
||
.pager-label {
|
||
font-size: var(--text-xs);
|
||
color: var(--fg-muted);
|
||
display: flex; align-items: center; gap: 6px;
|
||
margin-bottom: 6px;
|
||
}
|
||
.pager-label .icon { width: 14px; height: 14px; }
|
||
.pager-title { font-size: var(--text-md); font-weight: 600; color: var(--brand-900); }
|
||
.pager-link.next { text-align: right; }
|
||
.pager-link.next .pager-label { justify-content: flex-end; }
|
||
|
||
/* Feedback widget */
|
||
.docs-feedback {
|
||
margin-top: 40px;
|
||
padding: 24px;
|
||
background: var(--gray-25);
|
||
border-radius: var(--radius-lg);
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
}
|
||
.feedback-q { font-size: var(--text-md); color: var(--gray-800); }
|
||
.feedback-actions { display: flex; gap: 8px; }
|
||
.feedback-btn {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
background: var(--gray-0);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-md);
|
||
padding: 6px 14px;
|
||
font-size: var(--text-sm);
|
||
color: var(--gray-700);
|
||
}
|
||
.feedback-btn:hover { border-color: var(--brand-500); color: var(--brand-700); }
|
||
.feedback-btn .icon { width: 14px; height: 14px; }
|
||
|
||
/* ====================================================================
|
||
RIGHT RAIL — On this page
|
||
==================================================================== */
|
||
.docs-rail {
|
||
position: sticky;
|
||
top: 132px;
|
||
font-size: var(--text-sm);
|
||
}
|
||
.rail-title {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.06em;
|
||
color: var(--fg-subtle);
|
||
text-transform: uppercase;
|
||
margin: 0 0 12px;
|
||
}
|
||
.rail-list { display: flex; flex-direction: column; gap: 2px; }
|
||
.rail-list a {
|
||
padding: 5px 10px;
|
||
border-radius: var(--radius-sm);
|
||
color: var(--fg-muted);
|
||
font-size: 13px;
|
||
border-left: 2px solid transparent;
|
||
}
|
||
.rail-list a:hover { color: var(--brand-700); }
|
||
.rail-list a.active {
|
||
color: var(--brand-700);
|
||
border-left-color: var(--brand-500);
|
||
font-weight: 500;
|
||
}
|
||
.rail-actions {
|
||
margin-top: 24px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid var(--border-subtle);
|
||
display: flex; flex-direction: column; gap: 6px;
|
||
}
|
||
.rail-action {
|
||
display: flex; align-items: center; gap: 8px;
|
||
padding: 6px 10px;
|
||
font-size: 13px;
|
||
color: var(--fg-muted);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
.rail-action:hover { background: var(--gray-50); color: var(--brand-700); }
|
||
.rail-action .icon { width: 14px; height: 14px; }
|
||
|
||
/* ====================================================================
|
||
FOOTER (shared)
|
||
==================================================================== */
|
||
footer {
|
||
background: var(--gray-25);
|
||
border-top: 1px solid var(--border-subtle);
|
||
padding: 64px 0 32px;
|
||
color: var(--fg-muted);
|
||
font-size: var(--text-sm);
|
||
margin-top: 96px;
|
||
}
|
||
.footer-grid {
|
||
display: grid;
|
||
grid-template-columns: 1.5fr repeat(4, 1fr);
|
||
gap: 48px;
|
||
margin-bottom: 48px;
|
||
max-width: 1280px; margin-left: auto; margin-right: auto; padding: 0 32px;
|
||
}
|
||
.footer-brand img { height: 32px; margin-bottom: 16px; }
|
||
.footer-brand p { margin: 0 0 16px; max-width: 320px; line-height: 1.6; color: var(--fg-muted); }
|
||
.footer-contact { font-size: var(--text-sm); color: var(--gray-700); line-height: 1.8; }
|
||
.footer-col h5 {
|
||
font-size: var(--text-xs); font-weight: 600;
|
||
color: var(--brand-900); letter-spacing: 0.06em;
|
||
margin: 0 0 16px; text-transform: uppercase;
|
||
}
|
||
.footer-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
|
||
.footer-col li a { color: var(--gray-600); }
|
||
.footer-col li a:hover { color: var(--brand-500); }
|
||
.footer-bottom {
|
||
border-top: 1px solid var(--border-subtle);
|
||
padding: 24px 32px 0;
|
||
display: flex; justify-content: space-between;
|
||
font-size: var(--text-xs);
|
||
color: var(--fg-subtle);
|
||
max-width: 1280px; margin: 0 auto;
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
.docs-layout { grid-template-columns: 220px 1fr; gap: 32px; }
|
||
.docs-rail { display: none; }
|
||
}
|
||
@media (max-width: 880px) {
|
||
.docs-layout { grid-template-columns: 1fr; gap: 24px; padding: 16px; }
|
||
.docs-toc { position: static; max-height: none; }
|
||
.footer-grid { grid-template-columns: 1fr 1fr; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- =========================== TOP NAV =========================== -->
|
||
<nav class="topnav">
|
||
<div class="topnav-inner">
|
||
<a href="/" class="topnav-brand">
|
||
<img src="assets/logo-full.svg" alt="岩美" />
|
||
</a>
|
||
<div class="topnav-links">
|
||
<a href="/#modules">产品</a>
|
||
<a href="/#pricing">价格</a>
|
||
<a href="/download.html">下载</a>
|
||
<a href="/docs.html" class="active">文档</a>
|
||
<a href="/#faq">支持</a>
|
||
</div>
|
||
<div class="topnav-cta" id="nav-cta"></div>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- =========================== DOCS SUB-NAV =========================== -->
|
||
<div class="docs-subnav">
|
||
<div class="docs-subnav-inner">
|
||
<div class="breadcrumb">
|
||
<a href="/docs.html">用户手册</a>
|
||
<span class="sep">/</span>
|
||
<a href="#">业务操作</a>
|
||
<span class="sep">/</span>
|
||
<span class="current">入库管理</span>
|
||
</div>
|
||
<div class="docs-search">
|
||
<i data-lucide="search" class="icon search-icon"></i>
|
||
<input type="text" placeholder="搜索文档(如:盘点、审核、API)" />
|
||
<span class="kbd">⌘ K</span>
|
||
</div>
|
||
<div class="docs-version">
|
||
<i data-lucide="book-open" class="icon"></i>
|
||
<span class="docs-version-label">手册版本</span>
|
||
<strong>v1.6.2</strong>
|
||
<i data-lucide="chevron-down" class="icon"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- =========================== DOCS LAYOUT =========================== -->
|
||
<div class="docs-layout">
|
||
|
||
<!-- ============ LEFT TOC ============ -->
|
||
<aside class="docs-toc">
|
||
<div class="toc-section">
|
||
<h6 class="toc-section-title">快速开始</h6>
|
||
<a href="#" class="toc-link"><span class="toc-num">01</span>系统概述</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">02</span>登录与退出</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">03</span>界面说明</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">04</span>角色与权限</a>
|
||
</div>
|
||
|
||
<div class="toc-section">
|
||
<h6 class="toc-section-title">业务操作</h6>
|
||
<a href="#" class="toc-link active"><span class="toc-num">05</span>入库管理</a>
|
||
<div class="toc-sub">
|
||
<a href="#status">5.1 状态说明</a>
|
||
<a href="#create" class="active">5.2 新建入库单</a>
|
||
<a href="#submit">5.3 提交审核</a>
|
||
<a href="#approve">5.4 审批入库单</a>
|
||
<a href="#detail">5.5 查看详情</a>
|
||
<a href="#print">5.6 打印单据</a>
|
||
<a href="#labels">5.7 商品标签</a>
|
||
<a href="#settle">5.8 结清账款</a>
|
||
<a href="#filter">5.9 筛选与导出</a>
|
||
</div>
|
||
<a href="#" class="toc-link"><span class="toc-num">06</span>出库管理</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">07</span>库存管理</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">08</span>财务管理</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">09</span>往来单位</a>
|
||
</div>
|
||
|
||
<div class="toc-section">
|
||
<h6 class="toc-section-title">基础与设置</h6>
|
||
<a href="#" class="toc-link"><span class="toc-num">10</span>基础数据</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">11</span>系统设置</a>
|
||
<a href="#" class="toc-link"><span class="toc-num">12</span>常见问题</a>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ============ MAIN CONTENT ============ -->
|
||
<main class="docs-main">
|
||
<div class="doc-section-num">第 5 章</div>
|
||
<h1>入库管理</h1>
|
||
<p class="lead">
|
||
入库管理是货物进入门店的起点。本章介绍如何录入入库单、提交审核、审批通过自动更新库存与应付账款的完整流程。所有入库操作均需<strong>审核驱动</strong>,单据状态不可跳过、不可撤销。
|
||
</p>
|
||
|
||
<h2 id="status"><span class="anchor">5.1</span> 入库单状态说明</h2>
|
||
<p>每张入库单都在一个固定的状态流中流转。状态变化由系统记录,不可手动跳过。</p>
|
||
|
||
<div class="status-flow">
|
||
<div class="status-flow-track">
|
||
<div class="flow-node draft">
|
||
<div class="badge">草稿</div>
|
||
<small>可编辑</small>
|
||
</div>
|
||
<div class="flow-arrow"><i data-lucide="arrow-right" class="icon"></i></div>
|
||
<div class="flow-node pending">
|
||
<div class="badge">待审核</div>
|
||
<small>已锁定</small>
|
||
</div>
|
||
<div class="flow-arrow"><i data-lucide="arrow-right" class="icon"></i></div>
|
||
<div class="flow-fork-wrap">
|
||
<div class="flow-node approved">
|
||
<div class="badge"><i data-lucide="check" class="icon" style="width:14px;height:14px;display:inline-block;vertical-align:middle;margin-right:4px;"></i>已审批</div>
|
||
<small>库存 +N · 应付生成</small>
|
||
</div>
|
||
<div class="flow-node rejected">
|
||
<div class="badge">已拒绝</div>
|
||
<small>库存不变</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<table class="docs-table">
|
||
<thead>
|
||
<tr><th>状态</th><th>含义</th><th>可执行操作</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><span class="status-pill draft">草稿</span></td>
|
||
<td>已保存但未提交</td>
|
||
<td>编辑、删除、提交审核</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="status-pill pending">待审核</span></td>
|
||
<td>已提交等待审批,不可再编辑</td>
|
||
<td>审批通过、审批拒绝</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="status-pill approved">已审批</span></td>
|
||
<td>库存已增加,并生成应付账款</td>
|
||
<td>查看详情、打印、打标签、结清</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="status-pill rejected">已拒绝</span></td>
|
||
<td>审批不通过,库存与账款不变</td>
|
||
<td>查看详情</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<div class="callout warning">
|
||
<i data-lucide="alert-triangle" class="icon"></i>
|
||
<div>
|
||
<div class="callout-title">审批通过不可撤销</div>
|
||
<p>「已审批」状态的单据无法回退到「草稿」或「待审核」。如发现错误,请由具备权限的用户新建反向调整单据(红冲入库)进行修正,以保留完整审计链。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 id="create"><span class="anchor">5.2</span> 新建入库单</h2>
|
||
<p>新建入库单的入口在<strong>「入库管理 → 入库审核」</strong>标签页,点击右上角<code>新建入库审核单</code>按钮即可打开录入面板。</p>
|
||
|
||
<ol class="steps">
|
||
<li><div>点击左侧「入库管理」,切换到 <strong>入库审核</strong> 标签页。</div></li>
|
||
<li><div>点击右上角 <strong>新建入库审核单</strong> 按钮,弹出录入面板。</div></li>
|
||
<li><div>填写<strong>表头信息</strong>(见下方字段说明)。</div></li>
|
||
<li><div>在商品明细区逐行录入商品。点击 <code>添加商品</code> 增加新行,行末 <code>删除</code> 移除。</div></li>
|
||
<li><div>完成后可<strong>保存草稿</strong>(继续修改)或<strong>保存并提交审核</strong>(进入待审核)。</div></li>
|
||
</ol>
|
||
|
||
<h3>表头字段</h3>
|
||
<div class="field-list">
|
||
<div class="field-row">
|
||
<span class="field-name">仓库</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">货物入库的目标仓库。系统默认选中设置中的「默认仓库」。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">供应商</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">供货的往来单位。需提前在「往来单位 → 供应商」中维护。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">入库日期</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">默认为当天,可修改为历史日期(不能晚于今天)。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">备注</span>
|
||
<span class="field-required optional">选填</span>
|
||
<span class="field-desc">本批次入库的说明,最多 200 字符。</span>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>商品明细字段</h3>
|
||
<div class="field-list">
|
||
<div class="field-row">
|
||
<span class="field-name">商品名称</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">从「基础数据 → 商品名称」字典中选择,支持模糊搜索。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">系列</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">商品所属的系列或品牌线,如「飞天系列」。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">规格</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">包装规格,如 <code>500ml×6</code>。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">生产日期</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">点击日历图标选择,用于批次追溯与过期预警。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">批次号</span>
|
||
<span class="field-required optional">选填</span>
|
||
<span class="field-desc">用于后续追踪、出库时按批次先进先出。</span>
|
||
</div>
|
||
<div class="field-row">
|
||
<span class="field-name">数量 · 单价</span>
|
||
<span class="field-required">必填</span>
|
||
<span class="field-desc">入库数量与进货单价,系统自动计算金额 = 数量 × 单价。</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="callout info">
|
||
<i data-lucide="info" class="icon"></i>
|
||
<div>
|
||
<div class="callout-title">小技巧:复制上一行</div>
|
||
<p>从 v1.6.2 起,明细行右侧出现 <code>复制</code> 按钮,可快速复制上一行的商品 / 规格 / 单价,连续录入同系列商品更快。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 id="approve"><span class="anchor">5.4</span> 审批入库单</h2>
|
||
<p>具有<strong>操作员</strong>及以上权限的用户均可审批。审批通过后,系统会自动完成两件事:</p>
|
||
<ol>
|
||
<li>将所有商品按数量加入对应仓库的库存;</li>
|
||
<li>按供应商生成一笔<strong>应付账款</strong>,金额等于入库单合计。</li>
|
||
</ol>
|
||
|
||
<h3>审批接口示例</h3>
|
||
<p>若需通过 API 触发审批,使用如下请求:</p>
|
||
<div class="code-block"><button class="copy">复制</button>POST /api/v1/stockin/{id}/approve
|
||
Content-Type: application/json
|
||
Authorization: Bearer {token}
|
||
|
||
{
|
||
"decision": "approve", // approve | reject
|
||
"operator": "李建国",
|
||
"remark": "已核对数量与单价"
|
||
}</div>
|
||
|
||
<p>审批成功后返回:</p>
|
||
<div class="code-block"><button class="copy">复制</button>{
|
||
"ok": true,
|
||
"stockin_no": "RK20260523000007",
|
||
"status": "approved",
|
||
"effects": {
|
||
"inventory_delta": 36,
|
||
"payable_id": "AP20260523000012",
|
||
"payable_amount": 48400.00
|
||
}
|
||
}</div>
|
||
|
||
<div class="callout danger">
|
||
<i data-lucide="shield-alert" class="icon"></i>
|
||
<div>
|
||
<div class="callout-title">审批前请核对数量与单价</div>
|
||
<p>审批一旦通过即不可撤销,库存与应付账款将立即变动。如确实需要修正,唯一的合法路径是新建反向调整单(红冲入库),原始单据将完整保留以供审计。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 id="labels"><span class="anchor">5.7</span> 打印商品标签</h2>
|
||
<p>审批通过的入库单,可批量打印商品标签。标签内容包括:</p>
|
||
<ul>
|
||
<li>商品名称、编码、系列、规格</li>
|
||
<li>批次号、生产日期</li>
|
||
<li>酒行名称、地址、联系电话</li>
|
||
<li>商品二维码(扫码可访问公开信息页)</li>
|
||
</ul>
|
||
|
||
<p>操作步骤:</p>
|
||
<ol class="steps">
|
||
<li><div>在入库单列表中找到对应行,点击 <code>打标签</code> 按钮。</div></li>
|
||
<li><div>弹出对话框列出本次入库的所有商品,默认全部勾选。</div></li>
|
||
<li><div>勾选需打印的商品(可批量取消),点击 <strong>打印选中</strong>。</div></li>
|
||
<li><div>系统依次将每张标签发送给已连接的标签打印机。</div></li>
|
||
</ol>
|
||
|
||
<div class="callout success">
|
||
<i data-lucide="check-circle" class="icon"></i>
|
||
<div>
|
||
<div class="callout-title">支持的标签打印机</div>
|
||
<p>已验证支持佳博 GP-1124T、芯烨 XP-365B、汉印 N31。蓝牙打印机需先在系统设置 → 外设管理中配对。完整型号见 <a href="#">硬件支持文档</a>。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Prev / Next pager -->
|
||
<div class="docs-pager">
|
||
<a href="#" class="pager-link">
|
||
<div class="pager-label"><i data-lucide="arrow-left" class="icon"></i>上一章</div>
|
||
<div class="pager-title">04 · 角色与权限</div>
|
||
</a>
|
||
<a href="#" class="pager-link next">
|
||
<div class="pager-label">下一章<i data-lucide="arrow-right" class="icon"></i></div>
|
||
<div class="pager-title">06 · 出库管理</div>
|
||
</a>
|
||
</div>
|
||
|
||
<!-- Feedback -->
|
||
<div class="docs-feedback">
|
||
<div class="feedback-q">这一节对你有帮助吗?</div>
|
||
<div class="feedback-actions">
|
||
<button class="feedback-btn">
|
||
<i data-lucide="thumbs-up" class="icon"></i>有帮助
|
||
</button>
|
||
<button class="feedback-btn">
|
||
<i data-lucide="thumbs-down" class="icon"></i>需要改进
|
||
</button>
|
||
<button class="feedback-btn">
|
||
<i data-lucide="message-square" class="icon"></i>留言反馈
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- ============ RIGHT RAIL ============ -->
|
||
<aside class="docs-rail">
|
||
<h6 class="rail-title">本节内容</h6>
|
||
<div class="rail-list">
|
||
<a href="#status">5.1 状态说明</a>
|
||
<a href="#create" class="active">5.2 新建入库单</a>
|
||
<a href="#submit">5.3 提交审核</a>
|
||
<a href="#approve">5.4 审批入库单</a>
|
||
<a href="#detail">5.5 查看详情</a>
|
||
<a href="#print">5.6 打印单据</a>
|
||
<a href="#labels">5.7 商品标签</a>
|
||
<a href="#settle">5.8 结清账款</a>
|
||
<a href="#filter">5.9 筛选与导出</a>
|
||
</div>
|
||
<div class="rail-actions">
|
||
<a href="#" class="rail-action">
|
||
<i data-lucide="github" class="icon"></i>在 GitHub 上编辑
|
||
</a>
|
||
<a href="#" class="rail-action">
|
||
<i data-lucide="printer" class="icon"></i>打印本节
|
||
</a>
|
||
<a href="#" class="rail-action">
|
||
<i data-lucide="file-down" class="icon"></i>下载 PDF
|
||
</a>
|
||
<a href="#" class="rail-action">
|
||
<i data-lucide="link" class="icon"></i>复制链接
|
||
</a>
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
|
||
<!-- =========================== FOOTER =========================== -->
|
||
<footer>
|
||
<div class="footer-grid">
|
||
<div class="footer-brand">
|
||
<img src="assets/logo-full.svg" alt="岩美" />
|
||
<p>为酒行与酒店设计的库存、审核、财务一体化管理平台。</p>
|
||
<div class="footer-contact">
|
||
<div>support@yanmei.app</div>
|
||
<div>400-880-8888</div>
|
||
</div>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>产品</h5>
|
||
<ul>
|
||
<li><a href="/#modules">核心模块</a></li>
|
||
<li><a href="/#platforms">多端覆盖</a></li>
|
||
<li><a href="/#reports">数据洞察</a></li>
|
||
<li><a href="/#pricing">价格方案</a></li>
|
||
<li><a href="/download.html">下载客户端</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>资源</h5>
|
||
<ul>
|
||
<li><a href="/docs.html">使用手册</a></li>
|
||
<li><a href="#">API 文档</a></li>
|
||
<li><a href="#">视频教程</a></li>
|
||
<li><a href="#">数据导入模板</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>客户支持</h5>
|
||
<ul>
|
||
<li><a href="/#faq">常见问题</a></li>
|
||
<li><a href="#">提交工单</a></li>
|
||
<li><a href="#">技术支持</a></li>
|
||
<li><a href="#">服务等级</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>公司</h5>
|
||
<ul>
|
||
<li><a href="#">关于岩美</a></li>
|
||
<li><a href="#">客户案例</a></li>
|
||
<li><a href="#">招贤纳士</a></li>
|
||
<li><a href="#">联系我们</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="footer-bottom">
|
||
<div>© 2026 岩美科技 · 保留所有权利</div>
|
||
<div>沪 ICP 备 2026000000 号 · 沪公网安备 31010000000000 号</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
function getAuthUser() {
|
||
var token = localStorage.getItem('flutter.access_token');
|
||
var username = localStorage.getItem('flutter.username');
|
||
var realName = localStorage.getItem('flutter.real_name') || '';
|
||
var role = localStorage.getItem('flutter.role') || '';
|
||
var shopNo = localStorage.getItem('flutter.shop_no') || '';
|
||
if (!token || !username) return null;
|
||
return { username: username, realName: realName, role: role, shopNo: shopNo };
|
||
}
|
||
function doLogout() {
|
||
['access_token','refresh_token','username','real_name','shop_no','shop_id','role']
|
||
.forEach(function(k) { localStorage.removeItem('flutter.' + k); });
|
||
location.reload();
|
||
}
|
||
function toggleUserMenu() {
|
||
var el = document.getElementById('userDropdown');
|
||
if (el) el.classList.toggle('open');
|
||
}
|
||
document.addEventListener('click', function(e) {
|
||
var menu = document.getElementById('userDropdown');
|
||
if (menu) {
|
||
var navUser = menu.closest('.nav-user');
|
||
if (navUser && !navUser.contains(e.target)) menu.classList.remove('open');
|
||
}
|
||
});
|
||
function renderNav() {
|
||
var cta = document.getElementById('nav-cta');
|
||
if (!cta) return;
|
||
var user = getAuthUser();
|
||
if (user) {
|
||
var display = user.realName || user.username;
|
||
var initial = display.charAt(0).toUpperCase();
|
||
var roleMap = { admin: '管理员', user: '成员', readonly: '只读' };
|
||
var roleLabel = roleMap[user.role] || user.role;
|
||
cta.innerHTML = '<div class="nav-user">'
|
||
+ '<button class="nav-user-btn" onclick="toggleUserMenu()">'
|
||
+ '<div class="nav-avatar">' + initial + '</div>'
|
||
+ '<span>' + display + '</span>'
|
||
+ '<i data-lucide="chevron-down" class="icon"></i>'
|
||
+ '</button>'
|
||
+ '<div class="nav-dropdown" id="userDropdown">'
|
||
+ '<div style="padding:10px 14px 6px;border-bottom:1px solid var(--border-subtle);margin-bottom:4px">'
|
||
+ '<div style="font-size:13px;font-weight:600;color:var(--brand-900)">' + display + '</div>'
|
||
+ '<div style="font-size:11px;color:var(--fg-muted);margin-top:2px">' + (user.shopNo ? user.shopNo + ' · ' : '') + roleLabel + '</div>'
|
||
+ '</div>'
|
||
+ '<a href="/app/"><i data-lucide="layout-dashboard" class="icon"></i>进入管理端</a>'
|
||
+ '<div class="nav-dropdown-divider"></div>'
|
||
+ '<button class="logout" onclick="doLogout()"><i data-lucide="log-out" class="icon"></i>退出登录</button>'
|
||
+ '</div></div>';
|
||
} else {
|
||
cta.innerHTML = '<a href="/app/" class="btn btn-ghost">登录</a>'
|
||
+ '<a href="/app/" class="btn btn-primary">免费试用</a>';
|
||
}
|
||
if (window.lucide) lucide.createIcons();
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
renderNav();
|
||
if (window.lucide) lucide.createIcons();
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|