优化付款交货待办展示并支持列表快捷登记

This commit is contained in:
reddaniel110
2026-09-17 15:20:39 +08:00
parent 000f4198a8
commit 0e45a58e5b
16 changed files with 591 additions and 103 deletions
+70
View File
@@ -130,6 +130,58 @@ table.grid tr.row-off .btn { opacity: .8; }
.badge.track-partial { background: #e6f0ff; color: #14509b; }
.badge.track-received, .badge.track-delivered, .badge.track-paid { background: #e8f6ee; color: #12703f; }
.mobile-only { display: none; }
/* Payment / delivery workspace: independent states, task-first rows. */
.tracking-dashboard .card-head { align-items: flex-start; }
.tracking-dashboard .card-head > a { flex-shrink: 0; white-space: nowrap; }
.tracking-dashboard .card-head p { margin: 6px 0 0; }
.tracking-focus .stat { position: relative; border-top: 3px solid #d99a30; padding-right: 28px; }
.tracking-focus .focus-paid_undelivered { border-top-color: #1668dc; }
.tracking-focus .focus-recheck { border-top-color: #a65d26; }
.tracking-focus .stat.selected { background: #eef5ff; border-color: #1668dc; }
.tracking-focus .stat .k { color: #42526a; }
.stat-arrow { position: absolute; right: 12px; top: 24px; color: #697a91; }
.tracking-board-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
.tracking-board-head h3 { margin: 0; }
.tracking-filter { margin: 0 0 10px; flex-wrap: nowrap; }
.tracking-filter select { width: auto; max-width: 240px; }
.tracking-filter label { white-space: nowrap; }
.status-steps { display: flex; list-style: none; margin: 0; padding: 0; gap: 3px; }
.status-steps li { flex: 1; white-space: nowrap; text-align: center; padding: 6px 3px; border: 1px solid #e2e6ea; border-radius: 4px; font-size: 11px; color: #7b8490; background: #f7f8fa; }
.status-steps .current { font-weight: 600; border-color: currentColor; }
.status-steps .track-unpaid, .status-steps .track-pending { background: #fff4e0; color: #935100; }
.status-steps .track-partial { background: #e6f0ff; color: #14509b; }
.status-steps .track-paid, .status-steps .track-delivered { background: #e8f6ee; color: #12703f; }
.order-progress { min-width: 154px; }
.order-progress .badge, .order-progress .tracking-warning { display: inline-block; margin-bottom: 5px; }
.order-progress.is-stale .current { color: #777; background: #eef0f2; }
.tracking-tasks { display: flex; flex-wrap: wrap; gap: 4px; margin: 5px 0 9px; }
.task-tag { color: #586577; font-size: 12px; line-height: 1.6; }
.task-tag + .task-tag::before { content: '·'; margin-right: 4px; }
.task-prepayment, .task-invoice_due, .task-recheck { color: #935100; font-weight: 600; }
.task-closed { color: #12703f; }
.tracking-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.tracking-actions .btn { white-space: nowrap; }
.tracking-detail-link { font-size: 12px; display: inline-block; padding: 4px 0; }
.supplier-name { margin: 5px 0; overflow-wrap: anywhere; }
.order-identity { max-width: 240px; }
.tracking-table td, .orders-table td { padding-top: 12px !important; padding-bottom: 12px !important; }
.tracking-completed-link { border-top: 1px solid #e2e6ea; margin-top: 12px; padding-top: 12px; font-size: 12px; }
.completed-toggle { display: flex; align-items: center; gap: 4px; margin: 0; color: #555; }
.tracking-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 12px 0 20px; }
.tracking-panel { padding: 16px; border: 1px solid #dfe5ec; border-radius: 6px; min-width: 0; }
.tracking-panel h3 { margin: 0 0 12px; }
.tracking-panel .status-steps li { font-size: 13px; padding: 9px 3px; }
.follow-note { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.7; }
.update-meta { color: #637187; font-size: 12px; margin-bottom: 0; }
#tracking-dialog { width: 540px; max-width: calc(100% - 24px); max-height: calc(100% - 32px); padding: 0; border: 0; border-radius: 10px; box-shadow: 0 16px 60px #0004; }
#tracking-dialog::backdrop { background: #15253b80; }
#tracking-dialog .modal-head { position: sticky; top: 0; background: white; z-index: 1; }
#tracking-dialog h3 { margin: 14px 0; font-size: 15px; }
#tracking-reload { margin-bottom: 12px; }
.editor-order { line-height: 1.8; margin: 0; overflow-wrap: anywhere; }
.tracking-editor-page { max-width: 600px; }
.btn:disabled { opacity: .55; cursor: wait; }
[hidden] { display: none !important; }
@media (max-width: 800px) {
.topbar { height: auto; min-height: 52px; flex-wrap: wrap; gap: 12px; padding: 12px 16px; }
.topbar .brand { width: 100%; }
@@ -143,6 +195,24 @@ table.grid tr.row-off .btn { opacity: .8; }
.stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.tracking-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tracking-forms { grid-template-columns: minmax(0, 1fr); }
.tracking-panels { grid-template-columns: minmax(0, 1fr); }
table.grid.order-cards { display: block; min-width: 0; }
table.order-cards thead { display: none; }
table.order-cards tbody { display: block; }
table.order-cards tr { display: block; border: 1px solid #dfe5ec; border-radius: 8px; padding: 10px 12px; margin-bottom: 12px; background: #fff; }
table.order-cards td { display: flex; gap: 10px; align-items: center; justify-content: space-between; border: 0; padding: 7px 0 !important; text-align: left; min-width: 0; max-width: none; }
table.order-cards td::before { content: attr(data-label); font-size: 12px; color: #637187; flex: 0 0 55px; }
table.order-cards .order-identity { display: block; padding-bottom: 10px !important; border-bottom: 1px solid #edf0f4; margin-bottom: 5px; }
table.order-cards .order-identity::before, table.order-cards .order-next::before { display: none; }
table.order-cards .order-next { display: block; border-top: 1px solid #edf0f4; margin-top: 5px; padding-top: 10px !important; }
table.order-cards .order-progress { flex: 1; min-width: 0; max-width: 320px; }
table.order-cards .tracking-tasks { flex: 1; }
table.order-cards td[data-label="收票 / 待办"] { flex-wrap: wrap; }
table.order-cards .empty-row td { display: block; }
.tracking-actions .btn { display: inline-flex; align-items: center; }
.tracking-filter { width: 100%; }
.tracking-filter select { flex: 1; max-width: none; min-width: 0; }
.tracking-panel { padding: 12px; }
table.grid { min-width: 680px; }
table.approval-flow { min-width: 0; }
.mobile-only { display: block; }
+85
View File
@@ -0,0 +1,85 @@
/* Reuse server forms and existing permissions; keep edits on the current list. */
(function () {
'use strict';
var dialog = document.getElementById('tracking-dialog');
if (!dialog || typeof dialog.showModal !== 'function' || !window.fetch) return;
var content = document.getElementById('tracking-dialog-content');
var errorBox = document.getElementById('tracking-dialog-error');
var reload = document.getElementById('tracking-reload');
var close = dialog.querySelector('[data-tracking-close]');
var editorUrl = '', serial = 0, saving = false, opener;
function showError(message) {
errorBox.textContent = message;
errorBox.hidden = false;
reload.hidden = false;
}
function errorText(html) {
var doc = new DOMParser().parseFromString(html, 'text/html');
var message = doc.querySelector('.wrap .card p, body > p');
return message ? message.textContent : '暂时无法完成操作,请重新读取当前状态后再试。';
}
async function loadEditor() {
var current = ++serial;
errorBox.hidden = reload.hidden = true;
content.textContent = '正在读取最新状态…';
try {
var response = await fetch(editorUrl + '?fragment=1', {cache: 'no-store', credentials: 'same-origin'});
var html = await response.text();
if (current !== serial || !dialog.open) return;
if (response.redirected) { window.location.assign(response.url); return; }
if (!response.ok) { content.textContent = ''; showError(errorText(html)); return; }
content.innerHTML = html;
var field = content.querySelector('select, input:not([type=hidden])');
if (field) field.focus();
} catch (error) {
if (current === serial && dialog.open) { content.textContent = ''; showError('读取失败,请检查连接后重试。'); }
}
}
document.addEventListener('click', function (event) {
var link = event.target.closest('[data-quick-tracking]');
if (!link || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
event.preventDefault();
opener = link;
editorUrl = link.href;
dialog.showModal();
loadEditor();
});
close.addEventListener('click', function () { if (!saving) dialog.close(); });
dialog.addEventListener('cancel', function (event) { if (saving) event.preventDefault(); });
dialog.addEventListener('close', function () {
++serial;
content.textContent = '';
if (opener) opener.focus();
});
reload.addEventListener('click', loadEditor);
dialog.addEventListener('submit', async function (event) {
var form = event.target;
event.preventDefault();
if (saving) return;
var data = new FormData(form);
var submit = form.querySelector('[type=submit]');
saving = true;
close.disabled = reload.disabled = submit.disabled = true;
errorBox.hidden = reload.hidden = true;
var retry = true;
try {
var response = await fetch(form.action, {method: 'POST', body: data,
credentials: 'same-origin', headers: {'X-Tracking-Modal': '1'}});
if (response.redirected) { window.location.assign(response.url); return; }
if (response.ok && (response.headers.get('Content-Type') || '').indexOf('application/json') >= 0) {
var result = await response.json();
if (result.ok) { window.location.reload(); return; }
}
retry = response.status === 400;
showError(errorText(await response.text()));
} catch (error) {
retry = false;
showError('连接中断,无法确认是否保存成功。请重新读取当前状态,核对后再操作。');
} finally {
saving = false;
close.disabled = reload.disabled = false;
submit.disabled = !retry;
}
});
})();