Files
shanxia2.0/bak/mobile-ui/shanxia-mp-pl-transport-history-calendar-demo.html
T
2026-09-12 19:42:20 +08:00

588 lines
14 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>司机端 · 运输记录 · 日历筛选 Demo</title>
<style>
:root {
--green: #059669;
--green-soft: #ecfdf5;
--green-border: #a7f3d0;
--text: #0f172a;
--muted: #64748b;
--border: #e2e8f0;
--page-bg: #f1f5f9;
--danger: #dc2626;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
background: #cbd5e1;
color: var(--text);
}
.frame {
max-width: 390px;
margin: 24px auto;
background: var(--page-bg);
border-radius: 24px;
overflow: hidden;
box-shadow: 0 18px 50px rgba(15, 23, 42, 0.18);
min-height: 720px;
display: flex;
flex-direction: column;
}
.note {
max-width: 390px;
margin: 0 auto 12px;
padding: 0 8px;
font-size: 13px;
color: #334155;
line-height: 1.5;
}
.note code {
font-size: 12px;
background: #e2e8f0;
padding: 1px 6px;
border-radius: 4px;
}
.nav {
background: var(--green);
color: #fff;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
font-size: 16px;
font-weight: 600;
}
.nav .back {
position: absolute;
left: 12px;
top: 0;
bottom: 0;
display: flex;
align-items: center;
color: #fff;
text-decoration: none;
font-size: 22px;
line-height: 1;
opacity: 0.95;
}
.body {
padding: 12px 16px 24px;
flex: 1;
}
.calendar-card {
background: #fff;
border: 1px solid var(--border);
border-radius: 12px;
padding: 8px 8px 6px;
margin-bottom: 12px;
}
.cal-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 4px;
padding: 0 2px;
}
.cal-title {
font-size: 13px;
font-weight: 700;
color: var(--text);
}
.cal-nav-btn {
width: 28px;
height: 28px;
border: 1px solid var(--border);
border-radius: 6px;
background: #fff;
color: var(--muted);
font-size: 15px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
}
.cal-nav-btn:active {
background: var(--green-soft);
border-color: var(--green-border);
color: var(--green);
}
.weekday {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 0;
margin-bottom: 2px;
}
.weekday span {
text-align: center;
font-size: 11px;
color: var(--muted);
font-weight: 600;
padding: 2px 0;
line-height: 1.2;
}
.days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 2px 0;
}
.day {
height: 28px;
border: none;
background: transparent;
border-radius: 6px;
font-size: 12px;
color: var(--text);
cursor: pointer;
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
line-height: 1;
}
.day.muted {
color: #cbd5e1;
cursor: default;
}
.day.today:not(.selected)::after {
content: "";
position: absolute;
bottom: 2px;
width: 3px;
height: 3px;
border-radius: 50%;
background: var(--green);
}
.day.selected {
background: var(--green);
color: #fff;
font-weight: 700;
}
.day:not(.muted):not(.selected):hover {
background: var(--green-soft);
}
.selected-hint {
margin-top: 6px;
text-align: center;
font-size: 11px;
color: var(--muted);
}
.selected-hint strong {
color: var(--green);
font-weight: 700;
}
.record-card {
position: relative;
margin-bottom: 10px;
padding: 16px 14px 14px;
border-radius: 12px;
background: #fff;
border: 1px solid var(--border);
}
.index-tag {
position: absolute;
top: 0;
left: 0;
min-width: 24px;
height: 22px;
padding: 0 8px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 12px 0 10px 0;
background: var(--green);
color: #fff;
font-size: 12px;
font-weight: 700;
}
.record-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-bottom: 8px;
padding-left: 4px;
}
.plan-no {
font-size: 15px;
font-weight: 700;
}
.tag {
font-size: 11px;
font-weight: 600;
padding: 2px 8px;
border-radius: 999px;
color: #fff;
background: var(--green);
}
.tag.danger { background: var(--danger); }
.meta {
font-size: 13px;
color: var(--muted);
line-height: 1.45;
}
.meta + .meta { margin-top: 4px; }
.empty {
text-align: center;
padding: 40px 16px;
color: var(--muted);
font-size: 14px;
background: #fff;
border: 1px solid var(--border);
border-radius: 12px;
}
.compare {
max-width: 820px;
margin: 16px auto 40px;
padding: 0 12px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 760px) {
.compare { grid-template-columns: 1fr; }
}
.compare h2 {
grid-column: 1 / -1;
font-size: 15px;
margin: 8px 0 0;
color: #334155;
}
.mini-phone {
background: #fff;
border-radius: 16px;
border: 1px solid #94a3b8;
overflow: hidden;
font-size: 12px;
}
.mini-phone .bar {
background: var(--green);
color: #fff;
text-align: center;
padding: 8px;
font-weight: 600;
font-size: 13px;
}
.mini-phone .pad { padding: 10px; background: var(--page-bg); }
.old-filters {
background: #fff;
border: 1px solid var(--border);
border-radius: 10px;
padding: 8px;
display: flex;
gap: 6px;
align-items: center;
}
.old-field {
flex: 1;
border: 1px solid #cbd5e1;
border-radius: 6px;
padding: 8px;
color: #1e293b;
background: #fff;
}
.chip {
height: 28px;
padding: 0 8px;
border-radius: 999px;
border: 1px solid #d1fae5;
background: #ecfdf5;
color: #047857;
font-size: 11px;
font-weight: 600;
white-space: nowrap;
}
.chip.on {
background: var(--green);
border-color: var(--green);
color: #fff;
}
.caption {
text-align: center;
font-size: 12px;
color: #64748b;
margin-top: 8px;
padding-bottom: 4px;
}
</style>
</head>
<body>
<p class="note">
交互 Demo:顶部内嵌月历,默认当天,点日期即时过滤,左右切换月份。
文件路径:<code>mobile-ui/shanxia-mp-pl-transport-history-calendar-demo.html</code>
</p>
<div class="frame" id="app">
<div class="nav">
<a class="back" href="javascript:void(0)" aria-label="返回">‹</a>
运输记录
</div>
<div class="body">
<div class="calendar-card">
<div class="cal-head">
<button class="cal-nav-btn" type="button" id="prevMonth" aria-label="上一月">‹</button>
<div class="cal-title" id="calTitle">2026年8月</div>
<button class="cal-nav-btn" type="button" id="nextMonth" aria-label="下一月">›</button>
</div>
<div class="weekday">
<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>
</div>
<div class="days" id="days"></div>
<div class="selected-hint">当前筛选:<strong id="selectedLabel">今天</strong></div>
</div>
<div id="list"></div>
</div>
</div>
<section class="compare">
<h2>改前 / 改后对比(示意)</h2>
<div>
<div class="mini-phone">
<div class="bar">运输记录(改前)</div>
<div class="pad">
<div class="old-filters">
<div class="old-field">2026-08-21 ›</div>
<span class="chip on">今日</span>
<span class="chip">明日</span>
<span class="chip">后天</span>
</div>
</div>
</div>
<div class="caption">日期输入框 + 今日/明日/后天快捷</div>
</div>
<div>
<div class="mini-phone">
<div class="bar">运输记录(改后)</div>
<div class="pad">
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:10px;padding:8px;text-align:center;color:#64748b">
顶部完整月历 · 可切月 · 点选即过滤
</div>
</div>
</div>
<div class="caption">去掉快捷 chips,日历常驻顶部</div>
</div>
</section>
<script>
const MOCK = {
'2026-08-21': [
{
planNo: 'PL-20260821-01',
status: '进行中',
pickup: '2026-08-21',
delivery: '2026-08-21',
route: '张家港仓库 → 南通港区'
},
{
planNo: 'PL-20260820-18',
status: '进行中',
pickup: '2026-08-20',
delivery: '2026-08-21',
route: '上海石化 → 合肥仓'
}
],
'2026-08-20': [
{
planNo: 'PL-20260820-07',
status: '已归档',
pickup: '2026-08-20',
delivery: '2026-08-20',
route: '太仓码头 → 常州厂区'
}
],
'2026-08-22': [
{
planNo: 'PL-20260822-03',
status: '进行中',
pickup: '2026-08-22',
delivery: '2026-08-23',
route: '江阴仓 → 南京港'
}
],
'2026-07-15': [
{
planNo: 'PL-20260715-02',
status: '已作废',
pickup: '2026-07-15',
delivery: '2026-07-15',
route: '仪征 → 镇江'
}
]
}
function pad(n) { return String(n).padStart(2, '0') }
function ymd(d) {
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
}
function sameDay(a, b) {
return a.getFullYear() === b.getFullYear()
&& a.getMonth() === b.getMonth()
&& a.getDate() === b.getDate()
}
const today = new Date()
today.setHours(0, 0, 0, 0)
let viewYear = today.getFullYear()
let viewMonth = today.getMonth()
let selected = new Date(today)
const daysEl = document.getElementById('days')
const listEl = document.getElementById('list')
const calTitle = document.getElementById('calTitle')
const selectedLabel = document.getElementById('selectedLabel')
function renderCalendar() {
calTitle.textContent = viewYear + '年' + (viewMonth + 1) + '月'
daysEl.innerHTML = ''
const first = new Date(viewYear, viewMonth, 1)
const startWeekday = first.getDay()
const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate()
const prevDays = new Date(viewYear, viewMonth, 0).getDate()
for (let i = 0; i < startWeekday; i++) {
const dayNum = prevDays - startWeekday + 1 + i
const btn = document.createElement('button')
btn.type = 'button'
btn.className = 'day muted'
btn.textContent = dayNum
btn.disabled = true
daysEl.appendChild(btn)
}
for (let d = 1; d <= daysInMonth; d++) {
const date = new Date(viewYear, viewMonth, d)
const btn = document.createElement('button')
btn.type = 'button'
btn.className = 'day'
if (sameDay(date, today)) btn.classList.add('today')
if (sameDay(date, selected)) btn.classList.add('selected')
btn.textContent = d
btn.addEventListener('click', () => {
selected = date
render()
})
daysEl.appendChild(btn)
}
const filled = startWeekday + daysInMonth
const trail = (7 - (filled % 7)) % 7
for (let i = 1; i <= trail; i++) {
const btn = document.createElement('button')
btn.type = 'button'
btn.className = 'day muted'
btn.textContent = i
btn.disabled = true
daysEl.appendChild(btn)
}
}
function renderList() {
const key = ymd(selected)
if (sameDay(selected, today)) {
selectedLabel.textContent = '今天(' + key + ')'
} else {
selectedLabel.textContent = key
}
const rows = MOCK[key] || []
if (!rows.length) {
listEl.innerHTML = '<div class="empty">暂无运输记录</div>'
return
}
listEl.innerHTML = rows.map((row, i) => {
const tagClass = row.status === '已作废' ? 'tag danger' : 'tag'
return (
'<div class="record-card">' +
'<span class="index-tag">' + (i + 1) + '</span>' +
'<div class="record-top">' +
'<span class="plan-no">' + row.planNo + '</span>' +
'<span class="' + tagClass + '">' + row.status + '</span>' +
'</div>' +
'<div class="meta">取货:' + row.pickup + ' · 送货:' + row.delivery + '</div>' +
'<div class="meta">线路:' + row.route + '</div>' +
'</div>'
)
}).join('')
}
function render() {
renderCalendar()
renderList()
}
document.getElementById('prevMonth').addEventListener('click', () => {
viewMonth -= 1
if (viewMonth < 0) {
viewMonth = 11
viewYear -= 1
}
renderCalendar()
})
document.getElementById('nextMonth').addEventListener('click', () => {
viewMonth += 1
if (viewMonth > 11) {
viewMonth = 0
viewYear += 1
}
renderCalendar()
})
render()
</script>
</body>
</html>