feat: add multiple arrival batch rows
This commit is contained in:
parent
7aeb35595e
commit
8c229bc162
@ -20075,7 +20075,7 @@ function showOrderDetail(encodedStr, title) {
|
||||
html += '</tr></thead><tbody id="unfinishedOrderBody"><tr><td colspan="6" style="border:1.5px solid #b0b0b0;padding:20px;text-align:center;color:#bbb">加载中...</td></tr></tbody></table>';
|
||||
} else {
|
||||
html += '<div style="display:flex;align-items:center;margin:0 0 8px 0">';
|
||||
html += '<div style="margin-left:auto"><button id="addBatchBtn" class="btn btn-sm btn-outline" onclick="addArrivalBatchRow(this)" data-order-id="' + row.id + '" data-order-type="' + orderType + '" style="font-size:12px">➕ 添加一行</button></div>';
|
||||
html += '<div style="margin-left:auto;display:flex;align-items:center;gap:6px"><button id="addMultiBatchBtn" class="btn btn-sm btn-outline" onclick="promptAddArrivalBatchRows(this)" data-order-id="' + row.id + '" data-order-type="' + orderType + '" style="font-size:12px">➕ 添加多行</button><button id="addBatchBtn" class="btn btn-sm btn-outline" onclick="addArrivalBatchRow(this)" data-order-id="' + row.id + '" data-order-type="' + orderType + '" style="font-size:12px">➕ 添加一行</button></div>';
|
||||
html += '</div>';
|
||||
var showDefectiveQty = orderType === 'packaging';
|
||||
html += '<table id="arrivalBatchTable" style="width:100%;border-collapse:collapse;font-size:13px;table-layout:fixed" data-order-qty="' + (parseInt(row['数量']) || 0) + '"><thead><tr>';
|
||||
@ -20256,19 +20256,17 @@ function showOrderDetail(encodedStr, title) {
|
||||
})();
|
||||
}
|
||||
|
||||
function addArrivalBatchRow(btn) {
|
||||
btn.disabled = true;
|
||||
btn.textContent = '⋯';
|
||||
function appendArrivalBatchEditingRow(btn) {
|
||||
var overlay = btn.closest('.modal-overlay');
|
||||
if (!overlay) {
|
||||
var tbl = btn.closest('table');
|
||||
if (tbl) overlay = tbl.closest('.modal-overlay');
|
||||
}
|
||||
if (!overlay) return null;
|
||||
var orderId = btn.getAttribute('data-order-id');
|
||||
var orderType = btn.getAttribute('data-order-type') || 'domestic';
|
||||
var tbody = overlay.querySelector('#arrivalBatchBody');
|
||||
if (!tbody) { btn.disabled = false; btn.textContent = '➕ 添加一行'; return; }
|
||||
if (tbody.querySelector('.batch-editing')) { btn.disabled = false; btn.textContent = '➕ 添加一行'; return; }
|
||||
if (!tbody) return null;
|
||||
|
||||
// 计算下一个批次编号
|
||||
var lastNum = 0;
|
||||
@ -20299,10 +20297,37 @@ function addArrivalBatchRow(btn) {
|
||||
// 追加到表格末尾(合计行上方)
|
||||
tbody.appendChild(tr);
|
||||
recalcArrivalUnfinished();
|
||||
return tr;
|
||||
}
|
||||
|
||||
function addArrivalBatchRow(btn) {
|
||||
var tr = appendArrivalBatchEditingRow(btn);
|
||||
if (!tr) return;
|
||||
var inp = tr.querySelector('input[type="date"]');
|
||||
if (inp) inp.focus();
|
||||
}
|
||||
|
||||
function promptAddArrivalBatchRows(btn) {
|
||||
showCenteredPrompt('添加多行', '请输入需要添加的到货批次行数(1–100行):', '3', {
|
||||
type: 'number', min: 1, max: 100, step: 1, inputMode: 'numeric'
|
||||
}).then(function(value) {
|
||||
if (value === null) return;
|
||||
var count = Number(value);
|
||||
if (!Number.isInteger(count) || count < 1 || count > 100) {
|
||||
showCenteredAlert('输入有误', '请输入1到100之间的整数');
|
||||
return;
|
||||
}
|
||||
var firstRow = null;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var row = appendArrivalBatchEditingRow(btn);
|
||||
if (!row) break;
|
||||
if (!firstRow) firstRow = row;
|
||||
}
|
||||
var firstInput = firstRow && firstRow.querySelector('input[type="date"]');
|
||||
if (firstInput) firstInput.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消新增行(删除未保存的行)
|
||||
*/
|
||||
@ -27330,15 +27355,22 @@ window.showCenteredConfirm = function(title, message) {
|
||||
};
|
||||
|
||||
// 通用居中输入弹窗(返回Promise,resolve(输入值)=确认, resolve(null)=取消)
|
||||
window.showCenteredPrompt = function(title, message, defaultValue) {
|
||||
window.showCenteredPrompt = function(title, message, defaultValue, options) {
|
||||
return new Promise(function(resolve) {
|
||||
options = options || {};
|
||||
var inputType = options.type === 'number' ? 'number' : 'text';
|
||||
var inputAttrs = '';
|
||||
if (options.min !== undefined) inputAttrs += ' min="' + escHtml(String(options.min)) + '"';
|
||||
if (options.max !== undefined) inputAttrs += ' max="' + escHtml(String(options.max)) + '"';
|
||||
if (options.step !== undefined) inputAttrs += ' step="' + escHtml(String(options.step)) + '"';
|
||||
if (options.inputMode) inputAttrs += ' inputmode="' + escHtml(String(options.inputMode)) + '"';
|
||||
var modal = document.createElement('div');
|
||||
modal.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:100000;display:flex;align-items:center;justify-content:center;overflow-y:auto';
|
||||
modal.innerHTML = '<div style="background:#fff;border-radius:12px;width:440px;max-width:90vw;box-shadow:0 8px 24px rgba(0,0,0,0.15);margin:20px;overflow:hidden">' +
|
||||
'<div style="padding:24px 24px 12px">' +
|
||||
'<h3 style="margin:0 0 12px;font-size:17px">' + escHtml(title) + '</h3>' +
|
||||
(message ? '<p style="margin:0 0 12px;font-size:14px;color:#555;line-height:1.6">' + message + '</p>' : '') +
|
||||
'<input type="text" id="promptInput" value="' + escHtml(defaultValue || '') + '" style="width:100%;box-sizing:border-box;padding:8px 12px;font-size:14px;border:1px solid #d9d9d9;border-radius:6px;outline:none" autocomplete="off">' +
|
||||
'<input type="' + inputType + '" id="promptInput" value="' + escHtml(defaultValue || '') + '"' + inputAttrs + ' style="width:100%;box-sizing:border-box;padding:8px 12px;font-size:14px;border:1px solid #d9d9d9;border-radius:6px;outline:none" autocomplete="off">' +
|
||||
'</div>' +
|
||||
'<div style="padding:12px 24px 20px;display:flex;justify-content:flex-end;gap:10px">' +
|
||||
'<button class="btn" id="promptCancelBtn">取消</button>' +
|
||||
|
||||
34
tests/test_order_arrival_multi_rows.py
Normal file
34
tests/test_order_arrival_multi_rows.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""订单详情到货批次批量加行回归测试。"""
|
||||
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
APP_JS = (Path(__file__).resolve().parents[1] / 'static/js/app.js').read_text(encoding='utf-8')
|
||||
|
||||
|
||||
class OrderArrivalMultiRowsTest(unittest.TestCase):
|
||||
def test_detail_toolbar_places_multi_row_button_before_single_row_button(self):
|
||||
multi_pos = APP_JS.index('id="addMultiBatchBtn"')
|
||||
single_pos = APP_JS.index('id="addBatchBtn"', multi_pos)
|
||||
self.assertLess(multi_pos, single_pos)
|
||||
self.assertIn('onclick="promptAddArrivalBatchRows(this)"', APP_JS[multi_pos:single_pos])
|
||||
|
||||
def test_multi_row_prompt_requires_bounded_integer(self):
|
||||
self.assertIn("showCenteredPrompt('添加多行'", APP_JS)
|
||||
self.assertIn("type: 'number', min: 1, max: 100, step: 1", APP_JS)
|
||||
self.assertIn('!Number.isInteger(count) || count < 1 || count > 100', APP_JS)
|
||||
|
||||
def test_shared_row_builder_allows_repeated_appends(self):
|
||||
self.assertIn('function appendArrivalBatchEditingRow(btn)', APP_JS)
|
||||
self.assertIn('for (var i = 0; i < count; i++)', APP_JS)
|
||||
self.assertIn('var row = appendArrivalBatchEditingRow(btn)', APP_JS)
|
||||
self.assertNotIn("tbody.querySelector('.batch-editing')", APP_JS)
|
||||
|
||||
def test_centered_prompt_supports_numeric_inputs_without_breaking_text_default(self):
|
||||
self.assertIn('window.showCenteredPrompt = function(title, message, defaultValue, options)', APP_JS)
|
||||
self.assertIn("var inputType = options.type === 'number' ? 'number' : 'text'", APP_JS)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Loading…
x
Reference in New Issue
Block a user