Files
zkxw/docs/mockups/oa-receive-account-demo.html
T

744 lines
23 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" />
<title>收款账户管理 · Demo(Fresh Mint)</title>
<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=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
--primary: #10b981;
--primary-dark: #059669;
--primary-bg: #ecfdf5;
--text: #1e293b;
--text-muted: #64748b;
--border: #d9e8e2;
--bg-page: #fefefe;
--surface: #ffffff;
--table-head: #f8fafc;
--row-alt: #fafafa;
--row-hover: #f1f5f9;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
--radius: 10px;
--content-padding: 24px;
--backdrop: rgba(15, 23, 42, 0.35);
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
font-family: Inter, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
font-size: 14px;
line-height: 1.5;
color: var(--text);
background: var(--bg-page);
}
.layout { display: flex; min-height: 100vh; }
.sidebar {
width: 220px;
flex-shrink: 0;
background: var(--surface);
border-right: 1px solid var(--border);
padding: 24px 16px;
}
.logo {
font-size: 16px;
font-weight: 700;
padding: 0 12px 20px;
margin-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.logo span { color: var(--primary); }
.nav-group {
margin: 0 0 4px;
padding: 8px 12px;
font-size: 12px;
font-weight: 700;
color: var(--text-muted);
letter-spacing: 0.02em;
}
.nav a {
display: block;
padding: 8px 12px 8px 14px;
margin: 2px 0;
border-radius: var(--radius);
color: var(--text-muted);
text-decoration: none;
font-weight: 500;
font-size: 13px;
}
.nav a:hover { background: var(--row-alt); color: var(--text); }
.nav a.active {
background: var(--primary-bg);
color: var(--primary-dark);
font-weight: 600;
}
.main {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.header {
height: 56px;
padding: 0 var(--content-padding);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--surface);
border-bottom: 1px solid var(--border);
}
.crumb { font-size: 13px; color: var(--text-muted); }
.crumb b { color: var(--text); font-weight: 600; }
.demo-hint {
font-size: 12px;
color: var(--primary-dark);
background: var(--primary-bg);
padding: 4px 10px;
border-radius: 999px;
font-weight: 600;
}
.content {
flex: 1;
padding: var(--content-padding);
}
.panel {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow);
overflow: hidden;
}
.panel-top {
padding: 16px 20px 12px;
}
.title-bar-heading {
margin: 0;
font-size: 16px;
font-weight: 700;
display: flex;
align-items: center;
gap: 10px;
}
.title-bar-heading::before {
content: "";
width: 3px;
height: 16px;
border-radius: 2px;
background: var(--primary);
flex-shrink: 0;
}
.filter-block {
padding: 0 20px 16px;
}
.filter-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px 16px;
}
.field label {
display: block;
font-size: 11px;
color: var(--text-muted);
margin-bottom: 6px;
font-weight: 500;
}
.field input,
.field select,
.field textarea {
width: 100%;
height: 36px;
padding: 0 12px;
border: 1px solid var(--border);
border-radius: 8px;
font: inherit;
color: var(--text);
background: var(--surface);
outline: none;
}
.field textarea {
height: auto;
min-height: 72px;
padding: 10px 12px;
resize: vertical;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
border-color: var(--primary);
box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2);
}
.filter-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 12px;
}
.btn {
appearance: none;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
height: 36px;
padding: 0 14px;
border-radius: 8px;
font: inherit;
font-weight: 600;
font-size: 13px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
}
.btn:hover { background: var(--row-alt); }
.btn-main {
background: var(--primary);
border-color: var(--primary);
color: #fff;
}
.btn-main:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.btn-ghost { color: var(--text-muted); }
.list-toolbar {
padding: 12px 20px;
background: var(--table-head);
border-top: 1px solid var(--border);
display: flex;
align-items: center;
gap: 12px;
}
.sel-num { color: var(--primary-dark); font-weight: 700; }
.list-body { border-top: 1px solid var(--border); }
table.list-table {
width: 100%;
border-collapse: collapse;
}
.list-table th {
background: var(--table-head);
color: var(--text-muted);
font-weight: 600;
font-size: 13px;
text-align: left;
padding: 12px 14px;
border-bottom: 1px solid var(--border);
white-space: nowrap;
}
.list-table td {
padding: 12px 14px;
border-bottom: 1px solid var(--border);
vertical-align: middle;
}
.list-table tbody tr:nth-child(even) td { background: var(--row-alt); }
.list-table tbody tr:hover td { background: var(--row-hover); }
.list-table .ops { white-space: nowrap; }
.btn-op {
appearance: none;
border: none;
background: transparent;
color: var(--primary-dark);
font: inherit;
font-size: 13px;
font-weight: 600;
cursor: pointer;
padding: 4px 6px;
border-radius: 6px;
}
.btn-op:hover { background: var(--primary-bg); }
.btn-op.danger { color: #dc2626; }
.btn-op.danger:hover { background: #fef2f2; }
.tag {
display: inline-flex;
align-items: center;
height: 22px;
padding: 0 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
white-space: nowrap;
}
.tag.alipay { background: var(--primary-bg); color: var(--primary-dark); }
.tag.personal { background: #eff6ff; color: #2563eb; }
.tag.corporate { background: #fff7ed; color: #c2410c; }
.tag.muted { background: var(--table-head); color: var(--text-muted); }
.pagination {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 20px;
border-top: 1px solid var(--border);
color: var(--text-muted);
font-size: 13px;
}
.pager-btns { display: flex; gap: 6px; }
.pager-btns button {
min-width: 32px;
height: 32px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--surface);
cursor: pointer;
font: inherit;
}
.pager-btns button.active {
background: var(--primary);
border-color: var(--primary);
color: #fff;
font-weight: 600;
}
/* Dialog */
.backdrop {
position: fixed;
inset: 0;
background: var(--backdrop);
backdrop-filter: none;
display: none;
align-items: flex-start;
justify-content: center;
padding: 16px;
z-index: 1000;
overflow: auto;
}
.backdrop.is-open { display: flex; }
.dialog {
width: min(720px, 100%);
margin: auto;
background: var(--surface);
border-radius: var(--radius);
box-shadow: 0 20px 40px rgba(15, 23, 42, 0.15);
max-height: calc(100vh - 100px);
display: flex;
flex-direction: column;
overflow: hidden;
}
.dialog-header {
padding: 16px 20px;
border-bottom: 1px solid var(--border);
font-size: 16px;
font-weight: 700;
flex-shrink: 0;
}
.dialog-body {
padding: 20px;
overflow-y: auto;
flex: 1;
min-height: 0;
}
.dialog-footer {
padding: 12px 20px;
border-top: 1px solid var(--border);
background: var(--table-head);
display: flex;
justify-content: flex-end;
gap: 8px;
flex-shrink: 0;
}
.form-grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.form-col-span-2 { grid-column: 1 / -1; }
.form-item label {
display: block;
font-size: 13px;
font-weight: 600;
margin-bottom: 6px;
}
.form-item label .req { color: #dc2626; margin-right: 2px; }
.type-hint {
margin: 0 0 16px;
padding: 10px 12px;
background: var(--primary-bg);
border-radius: 8px;
color: var(--primary-dark);
font-size: 13px;
}
.bank-only { display: none; }
.bank-only.is-show { display: contents; }
.view-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px 20px;
}
.view-item .k {
font-size: 12px;
color: var(--text-muted);
margin-bottom: 4px;
}
.view-item .v { font-weight: 500; word-break: break-all; }
.view-item.full { grid-column: 1 / -1; }
.snapshot-full {
display: flex;
flex-direction: column;
gap: 8px;
}
.snapshot-full .line {
padding: 10px 12px;
background: var(--row-alt);
border-radius: 8px;
border: 1px solid var(--border);
line-height: 1.6;
word-break: break-word;
}
.snapshot-full .line .muted {
color: var(--text-muted);
font-size: 12px;
}
@media (max-width: 960px) {
.sidebar { display: none; }
.filter-grid { grid-template-columns: 1fr 1fr; }
.form-grid-2, .view-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="layout">
<aside class="sidebar">
<div class="logo">中科兴皖 · <span>OA</span></div>
<div class="nav">
<div class="nav-group">OA审批</div>
<a href="#">审批管理</a>
<a href="#">工作流角色</a>
<a href="#">发起审批</a>
<a href="#">待办中心</a>
<a href="#">已办中心</a>
<a href="#">我发起的</a>
<a href="#">抄送我的</a>
<a class="active" href="#">收款账户管理</a>
</div>
</aside>
<div class="main">
<header class="header">
<div class="crumb">OA审批 / <b>收款账户管理</b></div>
<span class="demo-hint">Demo · 可点新增/编辑/查看;下方「审批展示」为完整字段快照</span>
</header>
<div class="content">
<section class="panel">
<div class="panel-top">
<h2 class="title-bar-heading">收款账户管理</h2>
</div>
<div class="filter-block">
<div class="filter-grid">
<div class="field">
<label>关键词</label>
<input placeholder="户名 / 账号 / 银行" />
</div>
<div class="field">
<label>账户类型</label>
<select id="filterType">
<option value="">全部</option>
<option value="alipay">支付宝</option>
<option value="personal">个人银行卡</option>
<option value="corporate">对公银行账户</option>
</select>
</div>
</div>
<div class="filter-actions">
<button class="btn btn-ghost" type="button">重置</button>
<button class="btn btn-main" type="button">搜索</button>
</div>
</div>
<div class="list-toolbar">
<div>已选 <span class="sel-num">0</span> 项</div>
<button class="btn btn-main" type="button" onclick="openForm('add')">+ 新增账户</button>
<button class="btn" type="button">批量删除</button>
</div>
<div class="list-body">
<table class="list-table">
<thead>
<tr>
<th style="width:48px"><input type="checkbox" /></th>
<th style="width:64px">序号</th>
<th>账户类型</th>
<th>户名</th>
<th>账号</th>
<th>银行</th>
<th>开户地 / 支行</th>
<th>备注</th>
<th style="min-width:200px">操作</th>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
</div>
<div class="pagination">
<span>共 3 条</span>
<div class="pager-btns">
<button type="button">‹</button>
<button class="active" type="button">1</button>
<button type="button">›</button>
</div>
</div>
</section>
<section class="panel" style="margin-top:16px">
<div class="panel-top">
<h2 class="title-bar-heading">审批单 · 收款账户完整展示(只读快照)</h2>
</div>
<div style="padding:0 20px 20px">
<div class="field" style="margin-bottom:8px">
<label style="font-size:13px;font-weight:600;color:var(--text)">收款账户</label>
</div>
<div class="snapshot-full" id="snapshotPreview"></div>
</div>
</section>
</div>
</div>
</div>
<!-- 新增 / 编辑 -->
<div class="backdrop" id="formBackdrop" onclick="if(event.target===this)closeForm()">
<div class="dialog" role="dialog" aria-modal="true">
<div class="dialog-header" id="formTitle">新增收款账户</div>
<div class="dialog-body">
<p class="type-hint" id="typeHint">支付宝仅需填写户名、账号与备注。</p>
<div class="form-grid-2">
<div class="form-item form-col-span-2">
<label><span class="req">*</span>账户类型</label>
<select id="accountType" onchange="onTypeChange()">
<option value="alipay">支付宝</option>
<option value="personal">个人银行卡</option>
<option value="corporate">对公银行账户</option>
</select>
</div>
<div class="form-item">
<label><span class="req">*</span>户名</label>
<input id="accountName" placeholder="请输入户名" />
</div>
<div class="form-item">
<label><span class="req">*</span>账号</label>
<input id="accountNo" placeholder="请输入账号" />
</div>
<div class="bank-only" id="bankFields">
<div class="form-item">
<label><span class="req">*</span>银行</label>
<input id="bankName" placeholder="如:中国工商银行" />
</div>
<div class="form-item">
<label><span class="req">*</span>银行所在省 / 市</label>
<div style="display:flex;gap:8px">
<select id="bankProvince" style="flex:1">
<option value="">请选择省</option>
<option>安徽省</option>
<option>江苏省</option>
<option>浙江省</option>
</select>
<select id="bankCity" style="flex:1">
<option value="">请选择市</option>
<option>合肥市</option>
<option>芜湖市</option>
<option>南京市</option>
</select>
</div>
</div>
<div class="form-item form-col-span-2">
<label><span class="req">*</span>银行支行</label>
<input id="bankBranch" placeholder="请输入开户支行全称" />
</div>
</div>
<div class="form-item form-col-span-2">
<label>备注</label>
<textarea id="remark" placeholder="选填"></textarea>
</div>
</div>
</div>
<div class="dialog-footer">
<button class="btn" type="button" onclick="closeForm()">✕ 取消</button>
<button class="btn btn-main" type="button" onclick="closeForm()">✓ 确定</button>
</div>
</div>
</div>
<!-- 查看 -->
<div class="backdrop" id="viewBackdrop" onclick="if(event.target===this)closeView()">
<div class="dialog" style="width:min(640px,100%)">
<div class="dialog-header">查看收款账户</div>
<div class="dialog-body">
<div class="view-grid" id="viewBody"></div>
</div>
<div class="dialog-footer">
<button class="btn btn-main" type="button" onclick="closeView()">关闭</button>
</div>
</div>
</div>
<script>
const TYPE_META = {
alipay: { label: '支付宝', tag: 'alipay', hint: '支付宝仅需填写户名、账号与备注。' },
personal: { label: '个人银行卡', tag: 'personal', hint: '个人银行卡需填写户名、账号、银行、省/市、支行与备注。' },
corporate: { label: '对公银行账户', tag: 'corporate', hint: '对公银行账户需填写户名、账号、银行、省/市、支行与备注。' }
}
const rows = [
{
id: 1,
type: 'alipay',
accountName: '张三',
accountNo: '138****8888',
bankName: '—',
region: '—',
bankBranch: '—',
remark: '日常报销收款'
},
{
id: 2,
type: 'personal',
accountName: '李四',
accountNo: '6222 **** **** 1234',
bankName: '中国工商银行',
region: '安徽省 / 合肥市',
bankBranch: '工行合肥长江中路支行',
remark: ''
},
{
id: 3,
type: 'corporate',
accountName: '中科兴皖生物科技有限公司',
accountNo: '3401 **** **** 5678',
bankName: '中国建设银行',
region: '安徽省 / 合肥市',
bankBranch: '建行合肥高新支行',
remark: '对公付款默认账户'
}
]
function formatFullLine(r) {
const meta = TYPE_META[r.type]
const parts = [meta.label, r.accountName, r.accountNo]
if (r.type !== 'alipay') {
parts.push(r.bankName, r.region, r.bankBranch)
}
if (r.remark) parts.push(r.remark)
return parts.filter(Boolean).join(' · ')
}
function renderSnapshotPreview() {
const el = document.getElementById('snapshotPreview')
el.innerHTML = rows.map((r) =>
`<div class="line">${formatFullLine(r)}<div class="muted">快照 id=${r.id} · 主数据后续修改不影响本行</div></div>`
).join('')
}
function renderTable() {
const tbody = document.getElementById('tableBody')
tbody.innerHTML = rows.map((r, i) => {
const meta = TYPE_META[r.type]
return `<tr>
<td><input type="checkbox" /></td>
<td>${i + 1}</td>
<td><span class="tag ${meta.tag}">${meta.label}</span></td>
<td>${r.accountName}</td>
<td>${r.accountNo}</td>
<td>${r.bankName}</td>
<td>${r.type === 'alipay' ? '—' : `${r.region}<div style="color:var(--text-muted);font-size:12px;margin-top:2px">${r.bankBranch}</div>`}</td>
<td>${r.remark || '<span class="tag muted">无</span>'}</td>
<td class="ops">
<button class="btn-op" type="button" onclick="openView(${r.id})">查看</button>
<button class="btn-op" type="button" onclick="openForm('edit', ${r.id})">编辑</button>
<button class="btn-op danger" type="button">删除</button>
</td>
</tr>`
}).join('')
renderSnapshotPreview()
}
function onTypeChange() {
const type = document.getElementById('accountType').value
const meta = TYPE_META[type]
document.getElementById('typeHint').textContent = meta.hint
const bank = document.getElementById('bankFields')
if (type === 'alipay') bank.classList.remove('is-show')
else bank.classList.add('is-show')
}
function openForm(mode, id) {
document.getElementById('formTitle').textContent = mode === 'add' ? '新增收款账户' : '编辑收款账户'
const row = rows.find(r => r.id === id)
if (row) {
document.getElementById('accountType').value = row.type
document.getElementById('accountName').value = row.accountName
document.getElementById('accountNo').value = row.accountNo.replace(/\s|\*/g, '') || row.accountNo
document.getElementById('bankName').value = row.bankName === '—' ? '' : row.bankName
document.getElementById('bankBranch').value = row.bankBranch === '—' ? '' : row.bankBranch
document.getElementById('remark').value = row.remark || ''
} else {
document.getElementById('accountType').value = 'alipay'
document.getElementById('accountName').value = ''
document.getElementById('accountNo').value = ''
document.getElementById('bankName').value = ''
document.getElementById('bankBranch').value = ''
document.getElementById('remark').value = ''
document.getElementById('bankProvince').value = ''
document.getElementById('bankCity').value = ''
}
onTypeChange()
document.getElementById('formBackdrop').classList.add('is-open')
}
function closeForm() {
document.getElementById('formBackdrop').classList.remove('is-open')
}
function openView(id) {
const row = rows.find(r => r.id === id)
if (!row) return
const meta = TYPE_META[row.type]
const isBank = row.type !== 'alipay'
const items = [
{ k: '账户类型', v: `<span class="tag ${meta.tag}">${meta.label}</span>` },
{ k: '户名', v: row.accountName },
{ k: '账号', v: row.accountNo },
]
if (isBank) {
items.push(
{ k: '银行', v: row.bankName },
{ k: '银行所在省 / 市', v: row.region },
{ k: '银行支行', v: row.bankBranch, full: true }
)
}
items.push({ k: '备注', v: row.remark || '—', full: true })
document.getElementById('viewBody').innerHTML = items.map(it =>
`<div class="view-item${it.full ? ' full' : ''}"><div class="k">${it.k}</div><div class="v">${it.v}</div></div>`
).join('')
document.getElementById('viewBackdrop').classList.add('is-open')
}
function closeView() {
document.getElementById('viewBackdrop').classList.remove('is-open')
}
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') { closeForm(); closeView() }
})
renderTable()
</script>
</body>
</html>