20260811165111
This commit is contained in:
1 parent
5adbf59425
commit
ce78653207
34 files changed
+3793
-366
No files matched your search
@@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Demo 1 —— 方案 A:GitHub / Stripe 式「左侧竖向分区导航」
|
||||
结构:模块树(far-left) | 竖向分区导航(mid-left) | 内容(right)
|
||||
特点:分区再多也不裁切、不换行;树被拖宽后仍能保住表单横向空间。
|
||||
-->
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>模块管理布局 Demo 1 · 左侧竖向分区导航</title>
|
||||
<style>
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--border: oklch(0.922 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--radius: 8px;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html, body { height: 100%; margin: 0; }
|
||||
body {
|
||||
font-family: Inter, system-ui, -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-size: 13px;
|
||||
}
|
||||
.app { display: flex; height: 100vh; min-width: 0; }
|
||||
|
||||
/* 左侧模块树 */
|
||||
.tree {
|
||||
width: 240px; flex: none; display: flex; flex-direction: column;
|
||||
border-right: 1px solid var(--border);
|
||||
}
|
||||
.tree .search { padding: 12px 8px 8px; }
|
||||
.tree .search input {
|
||||
width: 100%; height: 32px; padding: 0 10px; font-size: 13px;
|
||||
border: 1px solid var(--border); border-radius: 6px; outline: none;
|
||||
background: var(--background); color: var(--foreground);
|
||||
}
|
||||
.tree .tree-body { flex: 1; min-height: 0; overflow: auto; padding: 0 4px 8px; }
|
||||
.node { display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 8px; border-radius: 6px; color: var(--foreground); cursor: pointer; }
|
||||
.node:hover { background: var(--accent); }
|
||||
.node.group { color: var(--muted-foreground); font-weight: 500; }
|
||||
.node.active { background: var(--accent); font-weight: 600; }
|
||||
.node .tw { width: 14px; text-align: center; color: var(--muted-foreground); }
|
||||
.indent { padding-left: 16px; }
|
||||
|
||||
/* 右侧主区 */
|
||||
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
||||
.header {
|
||||
flex: none; display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 10px 20px; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.header .title { font-size: 14px; font-weight: 600; }
|
||||
.header .badge { margin-left: 8px; font-size: 10px; padding: 1px 6px; border-radius: 4px; background: var(--muted); color: var(--muted-foreground); letter-spacing: .05em; }
|
||||
.header .actions { display: flex; align-items: center; gap: 14px; }
|
||||
.switch { display: flex; align-items: center; gap: 6px; color: var(--muted-foreground); cursor: pointer; }
|
||||
.switch .track { width: 30px; height: 18px; border-radius: 999px; background: var(--border); position: relative; }
|
||||
.switch .track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: left .15s; }
|
||||
.switch.on .track { background: var(--primary); }
|
||||
.switch.on .track::after { left: 14px; }
|
||||
.btn { height: 28px; padding: 0 14px; font-size: 12px; border-radius: 6px; border: 1px solid transparent; background: var(--primary); color: var(--primary-foreground); cursor: pointer; }
|
||||
.btn:hover { opacity: .9; }
|
||||
|
||||
/* 内容区:竖向分区导航 + 面板 */
|
||||
.body { flex: 1; min-height: 0; display: flex; }
|
||||
.sections {
|
||||
width: 168px; flex: none; border-right: 1px solid var(--border);
|
||||
padding: 10px 8px; overflow: auto;
|
||||
}
|
||||
.sec { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; border-radius: 6px; color: var(--muted-foreground); cursor: pointer; }
|
||||
.sec:hover { background: var(--accent); color: var(--foreground); }
|
||||
.sec.active { background: var(--accent); color: var(--foreground); font-weight: 600; }
|
||||
.sec .ico { width: 15px; text-align: center; opacity: .8; }
|
||||
|
||||
.panel-wrap { flex: 1; min-width: 0; overflow: auto; padding: 20px; }
|
||||
.panel { display: none; max-width: 920px; margin: 0 auto; }
|
||||
.panel.active { display: block; }
|
||||
.panel h3 { font-size: 13px; font-weight: 600; margin: 0 0 12px; }
|
||||
|
||||
.field { display: grid; grid-template-columns: 110px 1fr; align-items: center; gap: 12px; margin-bottom: 12px; }
|
||||
.field label { color: var(--muted-foreground); }
|
||||
.field input { height: 32px; padding: 0 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--background); color: var(--foreground); }
|
||||
.card { border: 1px solid var(--border); border-radius: 8px; padding: 16px; color: var(--muted-foreground); }
|
||||
|
||||
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||
table.tbl th, table.tbl td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
|
||||
table.tbl th { color: var(--muted-foreground); font-weight: 500; background: var(--muted); }
|
||||
.empty { color: var(--muted-foreground); padding: 24px; text-align: center; border: 1px dashed var(--border); border-radius: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<!-- 左:模块树 -->
|
||||
<aside class="tree">
|
||||
<div class="search"><input placeholder="搜索模块…" /></div>
|
||||
<div class="tree-body">
|
||||
<div class="node group"><span class="tw">▾</span> 系统管理</div>
|
||||
<div class="node indent">用户管理</div>
|
||||
<div class="node indent">角色管理</div>
|
||||
<div class="node indent">部门管理</div>
|
||||
<div class="node group"><span class="tw">▾</span> 业务模块</div>
|
||||
<div class="node indent active">订单</div>
|
||||
<div class="node indent">商品</div>
|
||||
<div class="node indent">库存</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 右:主区 -->
|
||||
<main class="main">
|
||||
<div class="header">
|
||||
<div><span class="title">订单</span><span class="badge">数据模块</span></div>
|
||||
<div class="actions">
|
||||
<label class="switch on"><span class="track"></span>启用</label>
|
||||
<button class="btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
<!-- 中:竖向分区导航 -->
|
||||
<nav class="sections" id="sections">
|
||||
<div class="sec active" data-key="basic"><span class="ico">●</span> 基础信息</div>
|
||||
<div class="sec" data-key="fields"><span class="ico">●</span> 字段定义</div>
|
||||
<div class="sec" data-key="list"><span class="ico">●</span> 列表配置</div>
|
||||
<div class="sec" data-key="edit"><span class="ico">●</span> 编辑配置</div>
|
||||
<div class="sec" data-key="query"><span class="ico">●</span> 查询配置</div>
|
||||
<div class="sec" data-key="auto"><span class="ico">●</span> 自动编码</div>
|
||||
<div class="sec" data-key="i18n"><span class="ico">●</span> 多语言</div>
|
||||
</nav>
|
||||
|
||||
<!-- 右:面板 -->
|
||||
<div class="panel-wrap">
|
||||
<section class="panel active" data-key="basic">
|
||||
<h3>基础信息</h3>
|
||||
<div class="field"><label>模块名称</label><input value="订单" /></div>
|
||||
<div class="field"><label>模块编码</label><input value="m_order" /></div>
|
||||
<div class="field"><label>模块类型</label><input value="数据模块" /></div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-key="fields">
|
||||
<h3>字段定义</h3>
|
||||
<table class="tbl">
|
||||
<thead><tr><th>字段</th><th>名称</th><th>类型</th><th>必填</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>b_id</td><td>主键</td><td>bigint</td><td>是</td></tr>
|
||||
<tr><td>b_name</td><td>名称</td><td>nvarchar</td><td>是</td></tr>
|
||||
<tr><td>b_status</td><td>状态</td><td>int</td><td>否</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-key="list"><h3>列表配置</h3><div class="card">列表列 / 分页 / 排序配置区</div></section>
|
||||
<section class="panel" data-key="edit"><h3>编辑配置</h3><div class="card">编辑表单字段布局配置区</div></section>
|
||||
<section class="panel" data-key="query"><h3>查询配置</h3><div class="card">查询条件配置区</div></section>
|
||||
<section class="panel" data-key="auto"><h3>自动编码</h3><div class="card">编码规则配置区</div></section>
|
||||
<section class="panel" data-key="i18n"><h3>多语言</h3><div class="card">翻译键 / 多语言文案配置区</div></section>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const sections = document.getElementById('sections');
|
||||
const secs = [...sections.querySelectorAll('.sec')];
|
||||
const panels = [...document.querySelectorAll('.panel')];
|
||||
function activate(key) {
|
||||
secs.forEach(s => s.classList.toggle('active', s.dataset.key === key));
|
||||
panels.forEach(p => p.classList.toggle('active', p.dataset.key === key));
|
||||
}
|
||||
secs.forEach(s => s.addEventListener('click', () => activate(s.dataset.key)));
|
||||
|
||||
// 模拟启用开关
|
||||
document.querySelectorAll('.switch').forEach(sw => sw.addEventListener('click', () => sw.classList.toggle('on')));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,190 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Demo 2 —— 方案 B:IDE / 数据库工具式「顶部可滚动 Tab 条 + 溢出下拉」
|
||||
结构:模块树(far-left) | 内容(right,顶部横排 Tab,多了出 ▾ 展开)
|
||||
特点:保留你现在的顶部横 Tab 习惯,但溢出时可横向滚动 / 点 ▾ 列出全部,绝不裁切。
|
||||
-->
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>模块管理布局 Demo 2 · 顶部可滚动 Tab</title>
|
||||
<style>
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--border: oklch(0.922 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--radius: 8px;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html, body { height: 100%; margin: 0; }
|
||||
body {
|
||||
font-family: Inter, system-ui, -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-size: 13px;
|
||||
}
|
||||
.app { display: flex; height: 100vh; min-width: 0; }
|
||||
|
||||
.tree { width: 240px; flex: none; display: flex; flex-direction: column; border-right: 1px solid var(--border); }
|
||||
.tree .search { padding: 12px 8px 8px; }
|
||||
.tree .search input { width: 100%; height: 32px; padding: 0 10px; font-size: 13px; border: 1px solid var(--border); border-radius: 6px; outline: none; background: var(--background); color: var(--foreground); }
|
||||
.tree .tree-body { flex: 1; min-height: 0; overflow: auto; padding: 0 4px 8px; }
|
||||
.node { display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 8px; border-radius: 6px; cursor: pointer; }
|
||||
.node:hover { background: var(--accent); }
|
||||
.node.group { color: var(--muted-foreground); font-weight: 500; }
|
||||
.node.active { background: var(--accent); font-weight: 600; }
|
||||
.node .tw { width: 14px; text-align: center; color: var(--muted-foreground); }
|
||||
.indent { padding-left: 16px; }
|
||||
|
||||
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
||||
.header { flex: none; display: flex; align-items: center; justify-content: space-between; padding: 10px 20px; border-bottom: 1px solid var(--border); }
|
||||
.header .title { font-size: 14px; font-weight: 600; }
|
||||
.header .badge { margin-left: 8px; font-size: 10px; padding: 1px 6px; border-radius: 4px; background: var(--muted); color: var(--muted-foreground); letter-spacing: .05em; }
|
||||
.header .actions { display: flex; align-items: center; gap: 14px; }
|
||||
.switch { display: flex; align-items: center; gap: 6px; color: var(--muted-foreground); cursor: pointer; }
|
||||
.switch .track { width: 30px; height: 18px; border-radius: 999px; background: var(--border); position: relative; }
|
||||
.switch .track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: left .15s; }
|
||||
.switch.on .track { background: var(--primary); }
|
||||
.switch.on .track::after { left: 14px; }
|
||||
.btn { height: 28px; padding: 0 14px; font-size: 12px; border-radius: 6px; border: 1px solid transparent; background: var(--primary); color: var(--primary-foreground); cursor: pointer; }
|
||||
.btn:hover { opacity: .9; }
|
||||
|
||||
/* 顶部 Tab 条(可横向滚动 + 溢出下拉) */
|
||||
.tabsbar { flex: none; display: flex; align-items: stretch; border-bottom: 1px solid var(--border); position: relative; }
|
||||
.tabs { display: flex; flex: 1; min-width: 0; overflow-x: auto; scrollbar-width: none; }
|
||||
.tabs::-webkit-scrollbar { display: none; }
|
||||
.tab {
|
||||
flex: none; display: flex; align-items: center; gap: 6px; height: 36px; padding: 0 14px;
|
||||
border-bottom: 2px solid transparent; color: var(--muted-foreground); cursor: pointer; white-space: nowrap;
|
||||
}
|
||||
.tab:hover { color: var(--foreground); }
|
||||
.tab.active { color: var(--foreground); border-bottom-color: var(--primary); font-weight: 600; }
|
||||
.overflow-btn { flex: none; width: 36px; border: none; border-left: 1px solid var(--border); background: var(--background); color: var(--muted-foreground); cursor: pointer; font-size: 14px; }
|
||||
.overflow-btn:hover { background: var(--accent); }
|
||||
.overflow-menu { display: none; position: absolute; top: 37px; right: 0; min-width: 160px; background: var(--background); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgb(0 0 0 / .08); z-index: 20; padding: 4px; }
|
||||
.overflow-menu.open { display: block; }
|
||||
.overflow-menu .item { display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px; border-radius: 6px; color: var(--foreground); cursor: pointer; }
|
||||
.overflow-menu .item:hover { background: var(--accent); }
|
||||
.overflow-menu .item.active { font-weight: 600; }
|
||||
|
||||
.panel-wrap { flex: 1; min-height: 0; overflow: auto; padding: 20px; }
|
||||
.panel { display: none; max-width: 920px; margin: 0 auto; }
|
||||
.panel.active { display: block; }
|
||||
.panel h3 { font-size: 13px; font-weight: 600; margin: 0 0 12px; }
|
||||
.field { display: grid; grid-template-columns: 110px 1fr; align-items: center; gap: 12px; margin-bottom: 12px; }
|
||||
.field label { color: var(--muted-foreground); }
|
||||
.field input { height: 32px; padding: 0 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--background); color: var(--foreground); }
|
||||
.card { border: 1px solid var(--border); border-radius: 8px; padding: 16px; color: var(--muted-foreground); }
|
||||
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||
table.tbl th, table.tbl td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
|
||||
table.tbl th { color: var(--muted-foreground); font-weight: 500; background: var(--muted); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="tree">
|
||||
<div class="search"><input placeholder="搜索模块…" /></div>
|
||||
<div class="tree-body">
|
||||
<div class="node group"><span class="tw">▾</span> 系统管理</div>
|
||||
<div class="node indent">用户管理</div>
|
||||
<div class="node indent">角色管理</div>
|
||||
<div class="node indent">部门管理</div>
|
||||
<div class="node group"><span class="tw">▾</span> 业务模块</div>
|
||||
<div class="node indent active">订单</div>
|
||||
<div class="node indent">商品</div>
|
||||
<div class="node indent">库存</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="header">
|
||||
<div><span class="title">订单</span><span class="badge">数据模块</span></div>
|
||||
<div class="actions">
|
||||
<label class="switch on"><span class="track"></span>启用</label>
|
||||
<button class="btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabsbar">
|
||||
<div class="tabs" id="tabs">
|
||||
<div class="tab active" data-key="basic">基础信息</div>
|
||||
<div class="tab" data-key="fields">字段定义</div>
|
||||
<div class="tab" data-key="list">列表配置</div>
|
||||
<div class="tab" data-key="edit">编辑配置</div>
|
||||
<div class="tab" data-key="query">查询配置</div>
|
||||
<div class="tab" data-key="auto">自动编码</div>
|
||||
<div class="tab" data-key="i18n">多语言</div>
|
||||
</div>
|
||||
<button class="overflow-btn" id="overflowBtn" title="展开全部分区">▾</button>
|
||||
<div class="overflow-menu" id="overflowMenu">
|
||||
<div class="item active" data-key="basic">基础信息</div>
|
||||
<div class="item" data-key="fields">字段定义</div>
|
||||
<div class="item" data-key="list">列表配置</div>
|
||||
<div class="item" data-key="edit">编辑配置</div>
|
||||
<div class="item" data-key="query">查询配置</div>
|
||||
<div class="item" data-key="auto">自动编码</div>
|
||||
<div class="item" data-key="i18n">多语言</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-wrap">
|
||||
<section class="panel active" data-key="basic">
|
||||
<h3>基础信息</h3>
|
||||
<div class="field"><label>模块名称</label><input value="订单" /></div>
|
||||
<div class="field"><label>模块编码</label><input value="m_order" /></div>
|
||||
<div class="field"><label>模块类型</label><input value="数据模块" /></div>
|
||||
</section>
|
||||
<section class="panel" data-key="fields">
|
||||
<h3>字段定义</h3>
|
||||
<table class="tbl">
|
||||
<thead><tr><th>字段</th><th>名称</th><th>类型</th><th>必填</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>b_id</td><td>主键</td><td>bigint</td><td>是</td></tr>
|
||||
<tr><td>b_name</td><td>名称</td><td>nvarchar</td><td>是</td></tr>
|
||||
<tr><td>b_status</td><td>状态</td><td>int</td><td>否</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section class="panel" data-key="list"><h3>列表配置</h3><div class="card">列表列 / 分页 / 排序配置区</div></section>
|
||||
<section class="panel" data-key="edit"><h3>编辑配置</h3><div class="card">编辑表单字段布局配置区</div></section>
|
||||
<section class="panel" data-key="query"><h3>查询配置</h3><div class="card">查询条件配置区</div></section>
|
||||
<section class="panel" data-key="auto"><h3>自动编码</h3><div class="card">编码规则配置区</div></section>
|
||||
<section class="panel" data-key="i18n"><h3>多语言</h3><div class="card">翻译键 / 多语言文案配置区</div></section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const tabs = document.getElementById('tabs');
|
||||
const tabEls = [...tabs.querySelectorAll('.tab')];
|
||||
const menu = document.getElementById('overflowMenu');
|
||||
const menuEls = [...menu.querySelectorAll('.item')];
|
||||
const panels = [...document.querySelectorAll('.panel')];
|
||||
|
||||
function activate(key) {
|
||||
tabEls.forEach(t => t.classList.toggle('active', t.dataset.key === key));
|
||||
menuEls.forEach(m => m.classList.toggle('active', m.dataset.key === key));
|
||||
panels.forEach(p => p.classList.toggle('active', p.dataset.key === key));
|
||||
// 让激活的 tab 滚入可视区
|
||||
const activeTab = tabEls.find(t => t.dataset.key === key);
|
||||
if (activeTab) activeTab.scrollIntoView({ inline: 'nearest', block: 'nearest' });
|
||||
}
|
||||
|
||||
tabEls.forEach(t => t.addEventListener('click', () => { activate(t.dataset.key); menu.classList.remove('open'); }));
|
||||
menuEls.forEach(m => m.addEventListener('click', () => { activate(m.dataset.key); menu.classList.remove('open'); }));
|
||||
|
||||
const overflowBtn = document.getElementById('overflowBtn');
|
||||
overflowBtn.addEventListener('click', (e) => { e.stopPropagation(); menu.classList.toggle('open'); });
|
||||
document.addEventListener('click', (e) => { if (!menu.contains(e.target) && e.target !== overflowBtn) menu.classList.remove('open'); });
|
||||
|
||||
document.querySelectorAll('.switch').forEach(sw => sw.addEventListener('click', () => sw.classList.toggle('on')));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user