Files
workspace/code/fms/test.html
T
2026-09-13 23:16:08 +08:00

972 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FMS Advanced Search Demo</title>
<style>
* {
box-sizing: border-box;
}
:root {
--primary: #2563eb;
--primary-soft: color-mix(in srgb, var(--primary) 8%, white);
--border: #dcdfe6;
--border-light: #ebeef5;
--text: #303133;
--text-secondary: #606266;
--text-placeholder: #a8abb2;
--bg: #f5f7fa;
--white: #fff;
--danger: #f56c6c;
--control-height: 32px;
}
body {
margin: 0;
font-family:
Inter,
"Microsoft YaHei",
"PingFang SC",
"Noto Sans JP",
Arial,
sans-serif;
color: var(--text);
background: var(--bg);
font-size: 13px;
}
/* ---------------- page ---------------- */
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
height: 52px;
background: #fff;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 18px;
gap: 14px;
}
.header-title {
font-size: 15px;
font-weight: 600;
}
.header-subtitle {
color: var(--text-secondary);
}
.header-spacer {
flex: 1;
}
.btn {
height: var(--control-height);
padding: 0 12px;
border: 1px solid var(--border);
border-radius: 4px;
background: #fff;
color: var(--text);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 5px;
}
.btn:hover {
border-color: var(--primary);
color: var(--primary);
}
.btn-primary {
background: var(--primary);
border-color: var(--primary);
color: #fff;
}
.btn-primary:hover {
background: #1d4ed8;
color: #fff;
}
.btn-text {
border-color: transparent;
background: transparent;
color: var(--text-secondary);
}
.content {
flex: 1;
padding: 14px 18px;
overflow: hidden;
}
/* ---------------- search ---------------- */
.search-panel {
background: #fff;
border: 1px solid var(--border);
padding: 12px;
border-radius: 4px;
}
.search-row {
display: grid;
grid-template-columns: repeat(4, minmax(180px, 1fr));
gap: 10px 14px;
}
.field {
display: flex;
align-items: center;
min-width: 0;
}
.field-label {
flex: 0 0 auto;
margin-right: 8px;
white-space: nowrap;
color: var(--text-secondary);
}
.input,
.select {
height: var(--control-height);
min-width: 0;
width: 100%;
border: 1px solid var(--border);
border-radius: 4px;
background: #fff;
padding: 0 9px;
outline: none;
color: var(--text);
}
.input:focus,
.select:focus {
border-color: var(--primary);
}
.search-actions {
display: flex;
justify-content: flex-end;
margin-top: 10px;
gap: 6px;
}
/* ---------------- table ---------------- */
.table-panel {
margin-top: 12px;
background: #fff;
border: 1px solid var(--border);
border-radius: 4px;
height: calc(100% - 125px);
overflow: hidden;
}
table {
width: 100%;
border-collapse: collapse;
}
th {
height: 38px;
background: #fafafa;
color: var(--text-secondary);
font-weight: 500;
text-align: left;
border-bottom: 1px solid var(--border);
padding: 0 12px;
}
td {
height: 40px;
padding: 0 12px;
border-bottom: 1px solid var(--border-light);
}
.status {
display: inline-flex;
align-items: center;
padding: 2px 7px;
border-radius: 3px;
background: #f0f9eb;
color: #67c23a;
}
/* ---------------- drawer mask ---------------- */
.mask {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, .08);
opacity: 0;
pointer-events: none;
transition: .2s;
}
.mask.open {
opacity: 1;
pointer-events: auto;
}
/* ---------------- drawer ---------------- */
.drawer {
position: fixed;
top: 0;
right: 0;
width: 540px;
max-width: 90vw;
height: 100vh;
background: #fff;
box-shadow: -4px 0 14px rgba(0,0,0,.12);
transform: translateX(100%);
transition: transform .22s ease;
display: flex;
flex-direction: column;
}
.drawer.open {
transform: translateX(0);
}
.drawer-header {
height: 54px;
flex: 0 0 54px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 16px;
}
.drawer-title {
font-size: 15px;
font-weight: 600;
}
.drawer-spacer {
flex: 1;
}
.close {
width: 30px;
height: 30px;
border: 0;
background: transparent;
cursor: pointer;
font-size: 20px;
color: var(--text-secondary);
}
.drawer-body {
flex: 1;
overflow: auto;
padding: 14px 16px 80px;
}
/* ---------------- saved query ---------------- */
.query-scheme {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.query-scheme-label {
white-space: nowrap;
color: var(--text-secondary);
}
.query-scheme .select {
width: 190px;
}
.save-btn {
margin-left: auto;
}
/* ---------------- query group ---------------- */
.group {
border: 1px solid var(--border);
border-radius: 4px;
}
.group-header {
height: 38px;
display: flex;
align-items: center;
padding: 0 10px;
background: #fafafa;
border-bottom: 1px solid var(--border-light);
}
.group-title {
font-weight: 500;
}
.group-actions {
margin-left: auto;
display: flex;
gap: 8px;
}
.link-btn {
border: 0;
background: transparent;
padding: 0;
cursor: pointer;
color: var(--primary);
font-size: 13px;
}
.conditions {
padding: 10px;
}
/* ---------------- condition ---------------- */
.condition {
display: grid;
grid-template-columns: 125px 115px minmax(110px, 1fr) 26px;
gap: 7px;
align-items: center;
min-height: 42px;
}
.condition + .condition {
margin-top: 5px;
}
.condition .select,
.condition .input {
width: 100%;
}
.remove-condition {
width: 26px;
height: 26px;
border: 0;
background: transparent;
color: #a8abb2;
cursor: pointer;
font-size: 16px;
}
.remove-condition:hover {
color: var(--danger);
}
/* ---------------- connector ---------------- */
.connector {
height: 28px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.connector::before {
content: "";
position: absolute;
left: 18px;
right: 18px;
top: 50%;
height: 1px;
background: var(--border-light);
}
.connector span {
position: relative;
background: #fff;
padding: 0 7px;
color: var(--text-secondary);
font-size: 12px;
}
/* ---------------- group add ---------------- */
.add-condition {
margin-top: 8px;
}
.add-group {
margin-top: 10px;
display: flex;
justify-content: center;
}
/* ---------------- nested group ---------------- */
.nested-group {
margin-top: 10px;
margin-left: 12px;
border: 1px dashed #cfd3dc;
border-radius: 4px;
}
.nested-header {
height: 34px;
display: flex;
align-items: center;
padding: 0 10px;
background: #fafafa;
}
.nested-title {
color: var(--text-secondary);
}
/* ---------------- footer ---------------- */
.drawer-footer {
height: 58px;
flex: 0 0 58px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
padding: 0 16px;
background: #fff;
}
/* ---------------- active filters ---------------- */
.active-filters {
display: flex;
align-items: center;
gap: 6px;
margin-top: 10px;
flex-wrap: wrap;
}
.active-label {
color: var(--text-secondary);
}
.tag {
height: 26px;
display: inline-flex;
align-items: center;
gap: 5px;
padding: 0 8px;
border: 1px solid #d9ecff;
border-radius: 3px;
background: #f4f9ff;
color: #409eff;
}
.tag-close {
cursor: pointer;
color: #79bbff;
}
/* ---------------- responsive ---------------- */
@media (max-width: 900px) {
.search-row {
grid-template-columns: repeat(2, 1fr);
}
.drawer {
width: 520px;
}
}
@media (max-width: 600px) {
.search-row {
grid-template-columns: 1fr;
}
.condition {
grid-template-columns: 1fr 1fr;
}
.condition .value {
grid-column: 1 / 3;
}
.condition .remove-condition {
position: absolute;
right: 10px;
}
}
</style>
</head>
<body>
<div class="page">
<!-- Header -->
<div class="header">
<div class="header-title">订舱管理</div>
<div class="header-subtitle">Booking Orders</div>
<div class="header-spacer"></div>
<button class="btn">新增</button>
<button class="btn">导出</button>
<button class="btn" onclick="openDrawer()">高级搜索</button>
</div>
<!-- Content -->
<div class="content">
<!-- Simple search -->
<div class="search-panel">
<div class="search-row">
<div class="field">
<div class="field-label">订舱号</div>
<input class="input" placeholder="请输入">
</div>
<div class="field">
<div class="field-label">客户</div>
<input class="input" placeholder="请输入">
</div>
<div class="field">
<div class="field-label">业务员</div>
<input class="input" placeholder="请输入">
</div>
<div class="field">
<div class="field-label">状态</div>
<select class="select">
<option>全部</option>
<option>草稿</option>
<option>已确认</option>
<option>已完成</option>
</select>
</div>
</div>
<div class="search-actions">
<button class="btn">重置</button>
<button class="btn btn-primary">查询</button>
</div>
</div>
<!-- Active conditions -->
<div class="active-filters">
<span class="active-label">当前条件:</span>
<span class="tag">
客户 = ABC Logistics
<span class="tag-close">×</span>
</span>
<span class="tag">
金额 &gt; 10000
<span class="tag-close">×</span>
</span>
<span class="tag">
日期 ≥ 2026-09-01
<span class="tag-close">×</span>
</span>
</div>
<!-- Table -->
<div class="table-panel">
<table>
<thead>
<tr>
<th width="150">订舱号</th>
<th>客户</th>
<th>业务员</th>
<th>金额</th>
<th>开船日期</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>BK202609001</td>
<td>ABC Logistics</td>
<td>张三</td>
<td>25,800.00</td>
<td>2026-09-05</td>
<td><span class="status">已确认</span></td>
</tr>
<tr>
<td>BK202609002</td>
<td>XYZ Shipping</td>
<td>李四</td>
<td>18,600.00</td>
<td>2026-09-08</td>
<td><span class="status">已完成</span></td>
</tr>
<tr>
<td>BK202609003</td>
<td>ABC Logistics</td>
<td>王五</td>
<td>12,500.00</td>
<td>2026-09-12</td>
<td><span class="status">已确认</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Mask -->
<div id="mask" class="mask" onclick="closeDrawer()"></div>
<!-- Drawer -->
<div id="drawer" class="drawer">
<div class="drawer-header">
<div class="drawer-title">高级搜索</div>
<div class="drawer-spacer"></div>
<button class="close" onclick="closeDrawer()">×</button>
</div>
<div class="drawer-body">
<!-- Query scheme -->
<div class="query-scheme">
<span class="query-scheme-label">查询方案</span>
<select class="select">
<option>我的查询</option>
<option>最近一个月</option>
<option>未完成订单</option>
<option>高金额订单</option>
<option>系统默认</option>
</select>
<button class="btn save-btn">保存</button>
</div>
<!-- Main group -->
<div class="group">
<div class="group-header">
<span class="group-title">
满足以下全部条件
</span>
<div class="group-actions">
<button class="link-btn">全部</button>
<button class="link-btn">任一</button>
</div>
</div>
<div class="conditions" id="conditions">
<!-- condition 1 -->
<div class="condition">
<select class="select field-select">
<option value="customer">客户</option>
<option value="bookingNo">订舱号</option>
<option value="sales">业务员</option>
<option value="amount">金额</option>
<option value="date">开船日期</option>
<option value="status">状态</option>
</select>
<select class="select operator">
<option>=</option>
<option>≠</option>
<option>包含</option>
<option>不包含</option>
</select>
<input class="input value" value="ABC Logistics">
<button class="remove-condition">×</button>
</div>
<!-- connector -->
<div class="connector">
<span>AND</span>
</div>
<!-- condition 2 -->
<div class="condition">
<select class="select field-select">
<option value="amount">金额</option>
<option value="customer">客户</option>
<option value="bookingNo">订舱号</option>
<option value="sales">业务员</option>
<option value="date">开船日期</option>
<option value="status">状态</option>
</select>
<select class="select operator">
<option>&gt;</option>
<option>&gt;=</option>
<option>=</option>
<option>&lt;</option>
<option>&lt;=</option>
<option>≠</option>
</select>
<input class="input value" value="10000">
<button class="remove-condition">×</button>
</div>
<!-- connector -->
<div class="connector">
<span>AND</span>
</div>
<!-- condition 3 -->
<div class="condition">
<select class="select field-select">
<option value="date">开船日期</option>
<option value="customer">客户</option>
<option value="bookingNo">订舱号</option>
<option value="sales">业务员</option>
<option value="amount">金额</option>
<option value="status">状态</option>
</select>
<select class="select operator">
<option>&gt;=</option>
<option>&gt;</option>
<option>=</option>
<option>&lt;</option>
<option>&lt;=</option>
</select>
<input class="input value" type="date" value="2026-09-01">
<button class="remove-condition">×</button>
</div>
</div>
<div style="padding:0 10px 12px;">
<button class="link-btn" onclick="addCondition()">
+ 添加条件
</button>
</div>
</div>
<!-- Nested group -->
<div class="nested-group">
<div class="nested-header">
<span class="nested-title">
满足以下任一条件
</span>
<div class="group-actions">
<button class="link-btn">删除条件组</button>
</div>
</div>
<div class="conditions">
<div class="condition">
<select class="select">
<option>港口</option>
<option>客户</option>
<option>业务员</option>
</select>
<select class="select">
<option>=</option>
<option>包含</option>
</select>
<input class="input" value="Shanghai">
<button class="remove-condition">×</button>
</div>
<div class="connector">
<span>OR</span>
</div>
<div class="condition">
<select class="select">
<option>港口</option>
<option>客户</option>
<option>业务员</option>
</select>
<select class="select">
<option>=</option>
<option>包含</option>
</select>
<input class="input" value="Ningbo">
<button class="remove-condition">×</button>
</div>
</div>
</div>
<div class="add-group">
<button class="link-btn">
+ 添加条件组
</button>
</div>
</div>
<div class="drawer-footer">
<button class="btn">重置</button>
<button class="btn">取消</button>
<button class="btn btn-primary" onclick="doSearch()">查询</button>
</div>
</div>
<script>
function openDrawer() {
document.getElementById("drawer").classList.add("open");
document.getElementById("mask").classList.add("open");
}
function closeDrawer() {
document.getElementById("drawer").classList.remove("open");
document.getElementById("mask").classList.remove("open");
}
function addCondition() {
const container = document.getElementById("conditions");
const connector = document.createElement("div");
connector.className = "connector";
connector.innerHTML = "<span>AND</span>";
const condition = document.createElement("div");
condition.className = "condition";
condition.innerHTML = `
<select class="select">
<option>客户</option>
<option>订舱号</option>
<option>业务员</option>
<option>金额</option>
<option>开船日期</option>
<option>状态</option>
</select>
<select class="select">
<option>=</option>
<option>≠</option>
<option>包含</option>
<option>不包含</option>
<option>&gt;</option>
<option>&gt;=</option>
<option>&lt;</option>
<option>&lt;=</option>
</select>
<input class="input" placeholder="请输入">
<button class="remove-condition"
onclick="this.parentElement.remove()">×</button>
`;
container.appendChild(connector);
container.appendChild(condition);
}
function doSearch() {
/*
* 实际项目中这里不直接拼 SQL。
*
* UI 最终转换成统一 Query AST,例如:
*
* {
* type: "group",
* operator: "AND",
* children: [
* {
* field: "customer",
* operator: "=",
* value: "ABC Logistics"
* },
* {
* field: "amount",
* operator: ">",
* value: 10000
* },
* {
* field: "date",
* operator: ">=",
* value: "2026-09-01"
* },
* {
* type: "group",
* operator: "OR",
* children: [
* {
* field: "port",
* operator: "=",
* value: "Shanghai"
* },
* {
* field: "port",
* operator: "=",
* value: "Ningbo"
* }
* ]
* ]
* }
*/
closeDrawer();
alert("查询条件已应用");
}
</script>
</body>
</html>
```