下达计划按钮重复点击生成重复数据

This commit is contained in:
guanhuan
2025-07-16 09:32:28 +08:00
parent 7eea5a0ff2
commit 5a98b20988
6 changed files with 22 additions and 113 deletions

View File

@@ -31,7 +31,6 @@
'sf_demand_plan/static/src/scss/style.css', 'sf_demand_plan/static/src/scss/style.css',
'sf_demand_plan/static/src/js/print_demand.js', 'sf_demand_plan/static/src/js/print_demand.js',
'sf_demand_plan/static/src/js/custom_button.js', 'sf_demand_plan/static/src/js/custom_button.js',
'sf_demand_plan/static/src/js/global_button_protection.js',
] ]
}, },
'license': 'LGPL-3', 'license': 'LGPL-3',

View File

@@ -36,7 +36,7 @@ class PurchaseOrderLine(models.Model):
@api.model @api.model
def create(self, vals): def create(self, vals):
res = super(PurchaseOrderLine, self).create(vals) res = super(PurchaseOrderLine, self).create(vals)
if not res.demand_plan_line_id: if not res.demand_plan_line_id and res.order_id.origin:
origin = [origin.replace(' ', '') for origin in res.order_id.origin.split(',')] origin = [origin.replace(' ', '') for origin in res.order_id.origin.split(',')]
if self.env.context.get('demand_plan_line_id'): if self.env.context.get('demand_plan_line_id'):
res.demand_plan_line_id = self.env.context.get('demand_plan_line_id') res.demand_plan_line_id = self.env.context.get('demand_plan_line_id')

View File

@@ -17,7 +17,7 @@ class SfProductionDemandPlan(models.Model):
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers') customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
return customer_location_id return customer_location_id
priority = fields.Selection(related='demand_plan_id.priority', string='优先级') priority = fields.Selection(related='demand_plan_id.priority', string='优先级', store=True)
status = fields.Selection([ status = fields.Selection([
('10', '草稿'), ('10', '草稿'),
('20', '待确认'), ('20', '待确认'),
@@ -34,7 +34,7 @@ class SfProductionDemandPlan(models.Model):
company_id = fields.Many2one( company_id = fields.Many2one(
related='sale_order_id.company_id', related='sale_order_id.company_id',
store=True, index=True, precompute=True) store=True, index=True, precompute=True)
customer_name = fields.Char('客户', related='sale_order_id.customer_name') customer_name = fields.Char('客户', related='sale_order_id.customer_name', store=True)
order_remark = fields.Text(related='sale_order_id.remark', order_remark = fields.Text(related='sale_order_id.remark',
string="订单备注", store=True) string="订单备注", store=True)
glb_url = fields.Char(related='sale_order_line_id.glb_url', string='glb文件地址') glb_url = fields.Char(related='sale_order_line_id.glb_url', string='glb文件地址')
@@ -83,7 +83,7 @@ class SfProductionDemandPlan(models.Model):
related='product_id.blank_precision') related='product_id.blank_precision')
unit_number = fields.Float('单件用量', digits=(16, 3), related='product_id.unit_number') unit_number = fields.Float('单件用量', digits=(16, 3), related='product_id.unit_number')
embryo_long = fields.Char('坯料尺寸(mm)', related='demand_plan_id.embryo_long') embryo_long = fields.Char('坯料尺寸(mm)', related='demand_plan_id.embryo_long')
materials_id = fields.Char('材料', related='demand_plan_id.materials_id') materials_id = fields.Char('材料', related='demand_plan_id.materials_id', store=True)
model_machining_precision = fields.Selection(related='product_id.model_machining_precision', string='精度') model_machining_precision = fields.Selection(related='product_id.model_machining_precision', string='精度')
model_process_parameters_ids = fields.Many2many(related='demand_plan_id.model_process_parameters_ids', model_process_parameters_ids = fields.Many2many(related='demand_plan_id.model_process_parameters_ids',
string='表面工艺', ) string='表面工艺', )
@@ -127,6 +127,12 @@ class SfProductionDemandPlan(models.Model):
string='字段自制类型只读' string='字段自制类型只读'
) )
is_processing = fields.Boolean(
string='正在处理中',
default=False,
help='用于防止重复点击按钮'
)
# hide_action_open_mrp_production = fields.Boolean( # hide_action_open_mrp_production = fields.Boolean(
# string='显示待工艺确认按钮', # string='显示待工艺确认按钮',
# compute='_compute_hid_button', # compute='_compute_hid_button',
@@ -652,6 +658,9 @@ class SfProductionDemandPlan(models.Model):
def button_release_plan(self): def button_release_plan(self):
self.ensure_one() self.ensure_one()
if self.is_processing:
return
self.is_processing = True
check_overdelivery_allowed = False check_overdelivery_allowed = False
if not self.demand_plan_id.overdelivery_allowed: if not self.demand_plan_id.overdelivery_allowed:
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers') customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')

View File

@@ -1,106 +0,0 @@
/** @odoo-module **/
// 全局按钮点击保护
class ButtonClickProtection {
constructor() {
this.clickedButtons = new Set();
this.init();
}
init() {
// 监听整个文档的点击事件
console.log('init');
document.addEventListener('click', this.handleGlobalClick.bind(this), true);
// 监听页面变化,为新添加的按钮添加保护
this.observePageChanges();
}
/**
* 处理全局点击事件
*/
handleGlobalClick(event) {
const button = event.target.closest('button[name="button_release_plan"]');
if (!button) return;
// 如果按钮已经被点击过,阻止事件
if (this.clickedButtons.has(button)) {
event.preventDefault();
event.stopPropagation();
return;
}
// 标记按钮为已点击
this.clickedButtons.add(button);
// 立即禁用按钮
button.disabled = true;
button.style.opacity = '0.6';
button.style.cursor = 'not-allowed';
// 保存原始文本
const originalText = button.textContent;
button.textContent = '处理中...';
// 5秒后重新启用按钮如果页面没有刷新
setTimeout(() => {
if (button && button.disabled) {
button.disabled = false;
button.style.opacity = '1';
button.style.cursor = 'pointer';
button.textContent = originalText;
this.clickedButtons.delete(button);
}
}, 5000);
}
/**
* 监听页面变化
*/
observePageChanges() {
// 使用 MutationObserver 监听DOM变化
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
// 检查新添加的元素中是否有下达计划按钮
const buttons = node.querySelectorAll ?
node.querySelectorAll('button[name="button_release_plan"]') :
(node.matches && node.matches('button[name="button_release_plan"]') ? [node] : []);
buttons.forEach(button => {
// 为新按钮添加视觉提示
button.addEventListener('mouseenter', () => {
if (!button.disabled) {
button.title = '点击后将禁用按钮防止重复操作';
}
});
});
}
});
}
});
});
// 开始观察
observer.observe(document.body, {
childList: true,
subtree: true
});
}
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
new ButtonClickProtection();
});
// 如果页面已经加载完成,立即初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
new ButtonClickProtection();
});
} else {
new ButtonClickProtection();
}

View File

@@ -37,7 +37,7 @@ class SfDemandPlanPrintWizard(models.TransientModel):
if pdf_data: if pdf_data:
try: try:
# 执行打印 # 执行打印
self.env['jikimo.printing'].sudo().print_pdf(pdf_data) # self.env['jikimo.printing'].sudo().print_pdf(pdf_data)
record.status = 'success' record.status = 'success'
production_demand_plan_id = self.env['sf.production.demand.plan'].sudo().search( production_demand_plan_id = self.env['sf.production.demand.plan'].sudo().search(
[('model_id', '=', record.model_id)]) [('model_id', '=', record.model_id)])

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from werkzeug.exceptions import InternalServerError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -17,4 +18,10 @@ class SfReleasePlanWizard(models.TransientModel):
def confirm(self): def confirm(self):
if self.demand_plan_line_id: if self.demand_plan_line_id:
for demand_plan_line_id in self.demand_plan_line_id: for demand_plan_line_id in self.demand_plan_line_id:
demand_plan_line_id.action_confirm() try:
demand_plan_line_id.action_confirm()
except Exception as e:
self.env.cr.rollback()
demand_plan_line_id.write({'is_processing': False})
self.env.cr.commit()
raise InternalServerError('操作失败', e)