@@ -537,14 +605,20 @@
console.log('检查数据是否有product_code字段:', demandList.some(item => 'product_code' in item)); // 检查字段是否存在
// 更新标签页
- const tabsContainer = document.querySelector('.product-tab').parentElement;
+ const tabsContainer = document.getElementById('product-tabs-container');
if (!tabsContainer) return;
- let html = '
';
+ const productArray = Array.from(products).sort();
- Array.from(products).sort().forEach(product => {
+ let html = `
`;
+
+ productArray.forEach(product => {
const isActive = product === currentProduct ? 'active' : '';
- html += `
`;
+ html += `
`;
});
tabsContainer.innerHTML = html;
@@ -1144,22 +1218,58 @@
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
const selectedCount = checkboxes.length;
- if (selectedCount === 0) {
- alert('请先选择要编辑的记录');
- return;
- }
-
// 更新选中数量显示
document.getElementById('selected-count').textContent = selectedCount;
+ // 加载产品列表
+ loadProductOptions();
+
// 重置表单
document.getElementById('batch-status').value = '';
document.getElementById('batch-remark').value = '';
+ document.querySelector('input[name="batch-scope"][value="selected"]').checked = true;
+ document.getElementById('batch-product-select-container').style.display = 'none';
+
+ // 添加事件监听
+ document.getElementById('batch-scope-all').onchange = function() {
+ document.getElementById('batch-product-select-container').style.display =
+ this.checked ? 'block' : 'none';
+ };
+ document.getElementById('batch-scope-selected').onchange = function() {
+ document.getElementById('batch-product-select-container').style.display =
+ this.checked ? 'none' : 'block';
+ };
// 显示弹窗
document.getElementById('batch-edit-status-modal').style.display = 'flex';
}
+ function loadProductOptions() {
+ // 获取所有产品
+ const products = new Set();
+ demandList.forEach(item => {
+ if (item.product_code) {
+ products.add(item.product_code);
+ }
+ });
+
+ const productSelect = document.getElementById('batch-product-select');
+ productSelect.innerHTML = '
';
+
+ // 添加产品选项
+ Array.from(products).sort().forEach(product => {
+ const option = document.createElement('option');
+ option.value = product;
+ option.textContent = product;
+ productSelect.appendChild(option);
+ });
+
+ // 如果当前有选中的产品,设为默认值
+ if (currentProduct) {
+ productSelect.value = currentProduct;
+ }
+ }
+
function closeBatchEditStatusModal() {
document.getElementById('batch-edit-status-modal').style.display = 'none';
}
@@ -1167,26 +1277,49 @@
async function saveBatchEditStatus() {
const status = document.getElementById('batch-status').value;
const remark = document.getElementById('batch-remark').value.trim();
+ const scope = document.querySelector('input[name="batch-scope"]:checked').value;
if (!status) {
alert('请选择状态');
return;
}
- // 获取选中的ID
- const checkboxes = document.querySelectorAll('.row-checkbox:checked');
- const ids = Array.from(checkboxes).map(cb => parseInt(cb.dataset.id));
+ let requestData = {
+ status: status,
+ remark: remark
+ };
- if (!confirm(`确定要将选中的 ${ids.length} 条记录状态更新为"${getStatusText(status)}"吗?`)) {
+ let confirmMessage = '';
+
+ if (scope === 'all') {
+ // 更新指定产品的所有记录
+ const selectedProduct = document.getElementById('batch-product-select').value;
+ if (!selectedProduct) {
+ alert('请选择要更新的产品');
+ return;
+ }
+ requestData.product_code = selectedProduct;
+ confirmMessage = `确定要将"${selectedProduct}"的所有记录状态更新为"${getStatusText(status)}"吗?`;
+ } else {
+ // 仅更新选中的记录
+ const checkboxes = document.querySelectorAll('.row-checkbox:checked');
+ const ids = Array.from(checkboxes).map(cb => parseInt(cb.dataset.id));
+
+ if (ids.length === 0) {
+ alert('请选择要更新的记录');
+ return;
+ }
+
+ requestData.ids = ids;
+ confirmMessage = `确定要将选中的 ${ids.length} 条记录状态更新为"${getStatusText(status)}"吗?`;
+ }
+
+ if (!confirm(confirmMessage)) {
return;
}
try {
- const res = await API.post('/api/purchase-demand/batch-update-status', {
- ids: ids,
- status: status,
- remark: remark
- });
+ const res = await API.post('/api/purchase-demand/batch-update-status', requestData);
if (res.ok) {
alert(`成功更新 ${res.count} 条记录`);
diff --git a/server/app.py b/server/app.py
index c04e8ca..4501267 100644
--- a/server/app.py
+++ b/server/app.py
@@ -6507,16 +6507,17 @@ def delete_purchase_demand(demand_id):
@app.post('/api/purchase-demand/batch-update-status')
@require_login
-@require_any_role('superadmin')
+@require_any_role('superadmin', 'admin')
def batch_update_purchase_demand_status():
"""批量更新采购需求状态"""
data = request.get_json() or {}
ids = data.get('ids', [])
- status = data.get('status', '').strip()
- remark = data.get('remark', '').strip()
+ status = data.get('status')
+ remark = data.get('remark', '')
+ product_code = data.get('product_code', '').strip()
- if not ids:
- return jsonify({'error': '请选择要更新的记录'}), 400
+ if not ids and not product_code:
+ return jsonify({'error': '请选择要更新的记录或指定产品'}), 400
if not status:
return jsonify({'error': '请选择状态'}), 400
@@ -6528,9 +6529,15 @@ def batch_update_purchase_demand_status():
c = conn.cursor()
now = get_beijing_time()
- # 验证ID是否存在并获取原始状态
- placeholders = ','.join(['?' for _ in ids])
- c.execute(f'SELECT id, status, material_code, material_name, actual_purchase_qty, net_demand FROM purchase_demand WHERE id IN ({placeholders})', ids)
+ # 根据条件查询记录
+ if product_code:
+ # 按产品代码查询
+ c.execute('SELECT id, status, material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock FROM purchase_demand WHERE product_code=?', (product_code,))
+ else:
+ # 按ID列表查询
+ placeholders = ','.join(['?' for _ in ids])
+ c.execute(f'SELECT id, status, material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock FROM purchase_demand WHERE id IN ({placeholders})', ids)
+
existing_records = c.fetchall()
if not existing_records:
@@ -6547,11 +6554,18 @@ def batch_update_purchase_demand_status():
material_name = record['material_name']
actual_purchase_qty = record['actual_purchase_qty']
net_demand = record['net_demand']
+ total_demand = record['total_demand']
+ initial_stock = record['initial_stock']
- # 计算之前增加的库存量:实际采购 - 净需求
- added_stock = actual_purchase_qty - net_demand
+ # 根据实际采购数量计算之前的变化量
+ if actual_purchase_qty > 0:
+ # 如果实际采购不等于零,之前增加的库存量 = 实际采购 - 净需求
+ added_stock = actual_purchase_qty - net_demand
+ else:
+ # 如果实际采购等于零,之前减少的库存量 = 期初库存 - 总需求
+ added_stock = -(initial_stock - total_demand)
- # 从期初库存表中减去之前增加的库存(恢复原值)
+ # 从期初库存表中减去之前的变化量(恢复原值)
c.execute('SELECT stock_qty FROM initial_stock WHERE material_code=?', (material_code,))
stock_record = c.fetchone()
@@ -6576,24 +6590,30 @@ def batch_update_purchase_demand_status():
params.extend(existing_ids)
c.execute(f'UPDATE purchase_demand SET {", ".join(updates)} WHERE id IN ({placeholders})', params)
- # 如果状态更新为已下单,更新期初库存
+ # 如果状态更新为已下单,更新期初库存(包括已经是已下单状态的情况)
if status == 'ordered':
for record in existing_records:
- # 只处理之前不是"已下单"状态的记录
- if record['status'] != 'ordered':
- material_code = record['material_code']
- material_name = record['material_name']
- actual_purchase_qty = record['actual_purchase_qty']
- net_demand = record['net_demand']
-
- # 计算新的期初库存:实际采购 - 净需求
+ # 处理所有记录(包括已经是"已下单"状态的记录)
+ material_code = record['material_code']
+ material_name = record['material_name']
+ actual_purchase_qty = record['actual_purchase_qty']
+ net_demand = record['net_demand']
+ total_demand = record['total_demand']
+ initial_stock = record['initial_stock']
+
+ # 根据实际采购数量计算新的期初库存
+ if actual_purchase_qty > 0:
+ # 如果实际采购不等于零,期初库存 = 实际采购 - 净需求
new_initial_stock = actual_purchase_qty - net_demand
-
- # 只更新期初库存表
- c.execute('''INSERT OR REPLACE INTO initial_stock
- (material_code, material_name, stock_qty, updated_at)
- VALUES (?, ?, ?, ?)''',
- (material_code, material_name, new_initial_stock, now))
+ else:
+ # 如果实际采购等于零,期初库存 = 期初库存 - 总需求
+ new_initial_stock = initial_stock - total_demand
+
+ # 只更新期初库存表
+ c.execute('''INSERT OR REPLACE INTO initial_stock
+ (material_code, material_name, stock_qty, updated_at)
+ VALUES (?, ?, ?, ?)''',
+ (material_code, material_name, new_initial_stock, now))
count = c.rowcount
conn.commit()
@@ -6881,11 +6901,18 @@ def update_purchase_demand(id):
material_name = existing['material_name']
actual_purchase_qty = existing['actual_purchase_qty']
net_demand = existing['net_demand']
+ total_demand = existing['total_demand']
+ initial_stock = existing['initial_stock']
- # 计算之前增加的库存量:实际采购 - 净需求
- added_stock = actual_purchase_qty - net_demand
+ # 根据实际采购数量计算之前的变化量
+ if actual_purchase_qty > 0:
+ # 如果实际采购不等于零,之前增加的库存量 = 实际采购 - 净需求
+ added_stock = actual_purchase_qty - net_demand
+ else:
+ # 如果实际采购等于零,之前减少的库存量 = 期初库存 - 总需求
+ added_stock = -(initial_stock - total_demand)
- # 从期初库存表中减去之前增加的库存(恢复原值)
+ # 从期初库存表中减去之前的变化量(恢复原值)
c.execute('SELECT stock_qty FROM initial_stock WHERE material_code=?', (material_code,))
stock_record = c.fetchone()
@@ -6903,16 +6930,22 @@ def update_purchase_demand(id):
update_values.append(id)
c.execute(f'UPDATE purchase_demand SET {", ".join(update_fields)} WHERE id=?', update_values)
- # 如果状态更新为已下单,更新期初库存
- if 'status' in data and new_status == 'ordered' and old_status != 'ordered':
+ # 如果状态更新为已下单,更新期初库存(包括已经是已下单状态的情况)
+ if 'status' in data and new_status == 'ordered':
# 获取更新后的记录信息
- c.execute('SELECT material_code, material_name, actual_purchase_qty, net_demand FROM purchase_demand WHERE id=?', (id,))
+ c.execute('SELECT material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock FROM purchase_demand WHERE id=?', (id,))
record = c.fetchone()
if record:
- material_code, material_name, actual_purchase_qty, net_demand = record
- # 计算新的期初库存:实际采购 - 净需求
- new_initial_stock = actual_purchase_qty - net_demand
+ material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock = record
+
+ # 根据实际采购数量计算新的期初库存
+ if actual_purchase_qty > 0:
+ # 如果实际采购不等于零,期初库存 = 实际采购 - 净需求
+ new_initial_stock = actual_purchase_qty - net_demand
+ else:
+ # 如果实际采购等于零,期初库存 = 期初库存 - 总需求
+ new_initial_stock = initial_stock - total_demand
# 只更新期初库存表
c.execute('''INSERT OR REPLACE INTO initial_stock