fix: 对齐field_to_perm与sys_element权限码 + 税率6% + 含税总价反算
- buy/semi/product: 数量字段映射对齐sys_element实际注册码(qty_inbound/qty_stock/qty_available) - 数据库: 补全buy(9)+semi(10)+product(13)缺失权限码 - deploy_production.sql: 同步更新 - buy.vue: 税率新增6%选项, 价格联动以含税为主输入, 税率变化保持最后编辑价格不变 - buy.vue: 新增含税总价可输入反算功能
This commit is contained in:
206
db_migrations/deploy_production.sql
Normal file
206
db_migrations/deploy_production.sql
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- 生产环境部署 SQL(可直接在 DataGrip 中执行)
|
||||||
|
-- 涵盖: 表结构变更 + 权限码补全 + 默认分配
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 一、表结构变更
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- 1. 采购申请表新增 base_id(关联物料基础信息)
|
||||||
|
ALTER TABLE purchase_request ADD COLUMN IF NOT EXISTS base_id INTEGER;
|
||||||
|
|
||||||
|
-- 2. 采购入库表新增 request_id(关联采购申请单)
|
||||||
|
ALTER TABLE stock_buy ADD COLUMN IF NOT EXISTS request_id INTEGER;
|
||||||
|
|
||||||
|
-- 3. 角色权限表新增 company_name(支持公司级别权限隔离)
|
||||||
|
ALTER TABLE sys_role_permission ADD COLUMN IF NOT EXISTS company_name VARCHAR(255);
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 二、补全 sys_element 权限码(确保权限分配页面可见)
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- 2.1 采购入库字段权限(14个缺失码)
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '基础物料ID', 'inbound_buy:base_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:base_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '全局打印ID', 'inbound_buy:global_print_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:global_print_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '强制质检标记', 'inbound_buy:isInspectionRequired', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:isInspectionRequired');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '入库数量', 'inbound_buy:in_quantity', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:in_quantity');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '当前库存', 'inbound_buy:stock_quantity', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:stock_quantity');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '当前可用', 'inbound_buy:available_quantity', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:available_quantity');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '含税单价', 'inbound_buy:post_tax_unit_price', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:post_tax_unit_price');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '采购邮箱', 'inbound_buy:purchaser_email', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:purchaser_email');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '原始链接', 'inbound_buy:source_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:source_link');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '详情链接', 'inbound_buy:detail_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:detail_link');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '到货图片', 'inbound_buy:arrival_photo', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:arrival_photo');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '检测报告', 'inbound_buy:inspection_report', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:inspection_report');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '关联采购单ID', 'inbound_buy:request_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:request_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_buy', '关联采购单号', 'inbound_buy:request_no', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_buy:request_no');
|
||||||
|
|
||||||
|
-- 2.1b 入库半成品字段权限(对齐 field_to_perm)
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '基础物料ID', 'inbound_semi:base_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:base_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '批号', 'inbound_semi:batch_number', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:batch_number');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '序列号', 'inbound_semi:serial_number', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:serial_number');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', 'BOM版本', 'inbound_semi:bom_version', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:bom_version');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '人工成本', 'inbound_semi:manual_cost', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:manual_cost');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '生产开始时间', 'inbound_semi:production_start_time', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:production_start_time');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '生产结束时间', 'inbound_semi:production_end_time', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:production_end_time');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '到货图片', 'inbound_semi:arrival_photo', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:arrival_photo');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '质检报告链接', 'inbound_semi:quality_report_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:quality_report_link');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_semi', '详情链接', 'inbound_semi:detail_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_semi:detail_link');
|
||||||
|
|
||||||
|
-- 2.1c 入库成品字段权限(对齐 field_to_perm)
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '基础物料ID', 'inbound_product:base_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:base_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '批号', 'inbound_product:batch_number', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:batch_number');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '条形码', 'inbound_product:barcode', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:barcode');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '序列号', 'inbound_product:serial_number', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:serial_number');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', 'BOM版本', 'inbound_product:bom_version', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:bom_version');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '人工成本', 'inbound_product:manual_cost', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:manual_cost');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '生产开始时间', 'inbound_product:production_start_time', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:production_start_time');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '生产结束时间', 'inbound_product:production_end_time', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:production_end_time');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '产品图片', 'inbound_product:product_photo', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:product_photo');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '质检报告链接', 'inbound_product:quality_report_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:quality_report_link');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '质检报告链接(入库)', 'inbound_product:inspection_report_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:inspection_report_link');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '详情链接', 'inbound_product:detail_link', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:detail_link');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'inbound_product', '入库数量', 'inbound_product:qty_inbound', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'inbound_product:qty_inbound');
|
||||||
|
|
||||||
|
-- 2.2 BOM 管理字段权限(5个缺失码)
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'bom_manage', '父件ID', 'bom_manage:parent_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'bom_manage:parent_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'bom_manage', '父件规格', 'bom_manage:parent_spec', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'bom_manage:parent_spec');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'bom_manage', '子件ID', 'bom_manage:child_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'bom_manage:child_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'bom_manage', '用量', 'bom_manage:dosage', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'bom_manage:dosage');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'bom_manage', '备注', 'bom_manage:remark', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'bom_manage:remark');
|
||||||
|
|
||||||
|
-- 2.3 员工管理字段权限(8个缺失码)
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '用户ID', 'system_user:id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '用户名', 'system_user:username', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:username');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '账号ID', 'system_user:account_id', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:account_id');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '邮箱', 'system_user:email', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:email');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '部门', 'system_user:department', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:department');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '角色', 'system_user:role', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:role');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '状态', 'system_user:status', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:status');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_user', '创建时间', 'system_user:created_at', 'column' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_user:created_at');
|
||||||
|
|
||||||
|
-- 2.4 系统管理操作权限(2个)
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_mgmt', '全局跨域访问', 'crossDomain', 'element' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'crossDomain');
|
||||||
|
INSERT INTO sys_element (menu_code, name, code, element_type)
|
||||||
|
SELECT 'system_mgmt', '权限分配操作', 'system_permission:operation', 'element' WHERE NOT EXISTS (SELECT 1 FROM sys_element WHERE code = 'system_permission:operation');
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 三、补全 sys_role_permission(给各角色分配新权限码)
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- 3.1 BOM 权限 → 分配给已有 BOM 权限的角色
|
||||||
|
INSERT INTO sys_role_permission (role_code, target_code, type, company_name)
|
||||||
|
SELECT rp.role_code, elem.code, 'element', rp.company_name
|
||||||
|
FROM (SELECT DISTINCT role_code, company_name FROM sys_role_permission WHERE target_code LIKE 'bom_manage:%') rp
|
||||||
|
CROSS JOIN (SELECT unnest(ARRAY['bom_manage:parent_id','bom_manage:parent_spec','bom_manage:child_id','bom_manage:dosage','bom_manage:remark','bom_manage:operation']) AS code) elem
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_role_permission rp2
|
||||||
|
WHERE rp2.role_code = rp.role_code AND rp2.target_code = elem.code
|
||||||
|
AND COALESCE(rp2.company_name, '') = COALESCE(rp.company_name, '')
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3.2 员工管理字段权限 → 分配给 SUPER_ADMIN 和 SUPERVISOR
|
||||||
|
INSERT INTO sys_role_permission (role_code, target_code, type)
|
||||||
|
SELECT r.role, elem.code, 'element'
|
||||||
|
FROM (SELECT unnest(ARRAY['SUPER_ADMIN','SUPERVISOR']) AS role) r
|
||||||
|
CROSS JOIN (
|
||||||
|
SELECT unnest(ARRAY['system_user:id','system_user:username','system_user:account_id','system_user:email','system_user:department','system_user:role','system_user:status','system_user:created_at','system_user:operation']) AS code
|
||||||
|
) elem
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_role_permission rp
|
||||||
|
WHERE rp.role_code = r.role AND rp.target_code = elem.code AND rp.type = 'element'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3.3 crossDomain → 仅 SUPER_ADMIN 默认拥有(其他角色通过权限页手动勾选)
|
||||||
|
INSERT INTO sys_role_permission (role_code, target_code, type)
|
||||||
|
SELECT 'SUPER_ADMIN', 'crossDomain', 'element'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_code = 'SUPER_ADMIN' AND target_code = 'crossDomain');
|
||||||
|
|
||||||
|
-- 3.4 system_permission:operation → 分配给 SUPER_ADMIN 和 SUPERVISOR
|
||||||
|
INSERT INTO sys_role_permission (role_code, target_code, type)
|
||||||
|
SELECT 'SUPER_ADMIN', 'system_permission:operation', 'element'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_code = 'SUPER_ADMIN' AND target_code = 'system_permission:operation');
|
||||||
|
|
||||||
|
INSERT INTO sys_role_permission (role_code, target_code, type)
|
||||||
|
SELECT 'SUPERVISOR', 'system_permission:operation', 'element'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_code = 'SUPERVISOR' AND target_code = 'system_permission:operation');
|
||||||
|
|
||||||
|
-- 3.5 system_mgmt / system_permission / system_audit → SUPERVISOR
|
||||||
|
INSERT INTO sys_role_permission (role_code, target_code, type)
|
||||||
|
SELECT 'SUPERVISOR', code, 'menu'
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE code IN ('system_mgmt', 'system_permission', 'system_audit')
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM sys_role_permission rp WHERE rp.role_code = 'SUPERVISOR' AND rp.target_code = sys_menu.code AND rp.type = 'menu');
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 四、验证
|
||||||
|
-- ============================================================
|
||||||
|
SELECT '=== 验证 ===' AS info;
|
||||||
|
|
||||||
|
SELECT '表结构' AS item, column_name, data_type
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name IN ('purchase_request', 'stock_buy', 'sys_role_permission')
|
||||||
|
AND column_name IN ('base_id', 'request_id', 'company_name')
|
||||||
|
ORDER BY table_name, column_name;
|
||||||
|
|
||||||
|
SELECT '权限码总数' AS item, count(*) FROM sys_element;
|
||||||
|
|
||||||
|
SELECT '角色权限总数' AS item, count(*) FROM sys_role_permission;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@ -62,16 +62,16 @@ def filter_item_by_permissions(item_dict, user_permissions):
|
|||||||
# 状态
|
# 状态
|
||||||
'status': 'inbound_buy:status',
|
'status': 'inbound_buy:status',
|
||||||
'inspection_status': 'inbound_buy:inspection_status',
|
'inspection_status': 'inbound_buy:inspection_status',
|
||||||
# 数量(三组命名,覆盖 model to_dict 中所有 key)
|
# 数量(对齐 sys_element 中实际存在的权限码)
|
||||||
'in_quantity': 'inbound_buy:in_quantity',
|
'in_quantity': 'inbound_buy:qty_inbound',
|
||||||
'qty_inbound': 'inbound_buy:in_quantity',
|
'qty_inbound': 'inbound_buy:qty_inbound',
|
||||||
'stock_quantity': 'inbound_buy:stock_quantity',
|
'stock_quantity': 'inbound_buy:qty_stock',
|
||||||
'qty_stock': 'inbound_buy:stock_quantity',
|
'qty_stock': 'inbound_buy:qty_stock',
|
||||||
'available_quantity': 'inbound_buy:available_quantity',
|
'available_quantity': 'inbound_buy:qty_available',
|
||||||
'qty_available': 'inbound_buy:available_quantity',
|
'qty_available': 'inbound_buy:qty_available',
|
||||||
# 价格
|
# 价格
|
||||||
'unit_price': 'inbound_buy:unit_price',
|
'unit_price': 'inbound_buy:unit_price',
|
||||||
'post_tax_unit_price': 'inbound_buy:post_tax_unit_price',
|
'post_tax_unit_price': 'inbound_buy:unit_price',
|
||||||
'total_price': 'inbound_buy:total_price',
|
'total_price': 'inbound_buy:total_price',
|
||||||
'tax_rate': 'inbound_buy:tax_rate',
|
'tax_rate': 'inbound_buy:tax_rate',
|
||||||
'currency': 'inbound_buy:currency',
|
'currency': 'inbound_buy:currency',
|
||||||
|
|||||||
@ -27,8 +27,8 @@ def filter_item_by_permissions(item_dict, user_permissions):
|
|||||||
'unit': 'inbound_product:unit', 'sku': 'inbound_product:sku', 'inbound_date': 'inbound_product:inbound_date',
|
'unit': 'inbound_product:unit', 'sku': 'inbound_product:sku', 'inbound_date': 'inbound_product:inbound_date',
|
||||||
'barcode': 'inbound_product:barcode', 'serial_number': 'inbound_product:serial_number',
|
'barcode': 'inbound_product:barcode', 'serial_number': 'inbound_product:serial_number',
|
||||||
'status': 'inbound_product:status', 'quality_status': 'inbound_product:quality_status',
|
'status': 'inbound_product:status', 'quality_status': 'inbound_product:quality_status',
|
||||||
'in_quantity': 'inbound_product:in_quantity', 'stock_quantity': 'inbound_product:stock_quantity',
|
'in_quantity': 'inbound_product:qty_inbound', 'stock_quantity': 'inbound_product:qty_stock',
|
||||||
'available_quantity': 'inbound_product:available_quantity', 'warehouse_location': 'inbound_product:warehouse_location',
|
'available_quantity': 'inbound_product:qty_available', 'warehouse_location': 'inbound_product:warehouse_loc',
|
||||||
'bom_code': 'inbound_product:bom_code', 'bom_version': 'inbound_product:bom_version',
|
'bom_code': 'inbound_product:bom_code', 'bom_version': 'inbound_product:bom_version',
|
||||||
'work_order_code': 'inbound_product:work_order_code', 'order_id': 'inbound_product:order_id',
|
'work_order_code': 'inbound_product:work_order_code', 'order_id': 'inbound_product:order_id',
|
||||||
'production_manager': 'inbound_product:production_manager', 'production_start_time': 'inbound_product:production_start_time',
|
'production_manager': 'inbound_product:production_manager', 'production_start_time': 'inbound_product:production_start_time',
|
||||||
|
|||||||
@ -27,9 +27,9 @@ def filter_item_by_permissions(item_dict, user_permissions):
|
|||||||
'unit': 'inbound_semi:unit', 'sku': 'inbound_semi:sku', 'inbound_date': 'inbound_semi:inbound_date',
|
'unit': 'inbound_semi:unit', 'sku': 'inbound_semi:sku', 'inbound_date': 'inbound_semi:inbound_date',
|
||||||
'barcode': 'inbound_semi:barcode', 'serial_number': 'inbound_semi:serial_number',
|
'barcode': 'inbound_semi:barcode', 'serial_number': 'inbound_semi:serial_number',
|
||||||
'batch_number': 'inbound_semi:batch_number', 'status': 'inbound_semi:status',
|
'batch_number': 'inbound_semi:batch_number', 'status': 'inbound_semi:status',
|
||||||
'quality_status': 'inbound_semi:quality_status', 'in_quantity': 'inbound_semi:in_quantity',
|
'quality_status': 'inbound_semi:quality_status', 'in_quantity': 'inbound_semi:qty_inbound',
|
||||||
'stock_quantity': 'inbound_semi:stock_quantity', 'available_quantity': 'inbound_semi:available_quantity',
|
'stock_quantity': 'inbound_semi:qty_stock', 'available_quantity': 'inbound_semi:qty_available',
|
||||||
'warehouse_location': 'inbound_semi:warehouse_location', 'bom_code': 'inbound_semi:bom_code',
|
'warehouse_location': 'inbound_semi:warehouse_loc', 'bom_code': 'inbound_semi:bom_code',
|
||||||
'bom_version': 'inbound_semi:bom_version', 'work_order_code': 'inbound_semi:work_order_code',
|
'bom_version': 'inbound_semi:bom_version', 'work_order_code': 'inbound_semi:work_order_code',
|
||||||
'raw_material_cost': 'inbound_semi:raw_material_cost', 'manual_cost': 'inbound_semi:manual_cost',
|
'raw_material_cost': 'inbound_semi:raw_material_cost', 'manual_cost': 'inbound_semi:manual_cost',
|
||||||
'unit_total_cost': 'inbound_semi:unit_total_cost', 'production_manager': 'inbound_semi:production_manager',
|
'unit_total_cost': 'inbound_semi:unit_total_cost', 'production_manager': 'inbound_semi:production_manager',
|
||||||
|
|||||||
@ -529,6 +529,7 @@
|
|||||||
<el-select v-model="form.tax_rate" style="width:100%" @change="updatePrices('tax')">
|
<el-select v-model="form.tax_rate" style="width:100%" @change="updatePrices('tax')">
|
||||||
<el-option label="0%" :value="0" />
|
<el-option label="0%" :value="0" />
|
||||||
<el-option label="1%" :value="1" />
|
<el-option label="1%" :value="1" />
|
||||||
|
<el-option label="6%" :value="6" />
|
||||||
<el-option label="13%" :value="13" />
|
<el-option label="13%" :value="13" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -575,6 +576,22 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20" v-if="hasFormFieldPermission('total_price') && form.tax_rate > 0">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="含税总价">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form._post_tax_total_price"
|
||||||
|
:precision="2"
|
||||||
|
:controls="false"
|
||||||
|
style="width:100%"
|
||||||
|
class="total-price-input"
|
||||||
|
placeholder="输入含税总价反算"
|
||||||
|
@change="updatePrices('post_total')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-row :gutter="20" style="margin-top: 15px;">
|
<el-row :gutter="20" style="margin-top: 15px;">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="供应商">
|
<el-form-item label="供应商">
|
||||||
@ -1161,7 +1178,8 @@ const form = reactive({
|
|||||||
supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '',
|
supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '',
|
||||||
arrival_photo: [] as string[], inspection_report: [] as string[],
|
arrival_photo: [] as string[], inspection_report: [] as string[],
|
||||||
print_copies: 1,
|
print_copies: 1,
|
||||||
request_id: undefined as number | undefined // [新增] 关联采购申请单
|
request_id: undefined as number | undefined, // [新增] 关联采购申请单
|
||||||
|
_post_tax_total_price: undefined as number | undefined // 含税总价(仅前端输入用,不提交后端)
|
||||||
})
|
})
|
||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
@ -1364,38 +1382,61 @@ const handleEntryModeChange = (val: string) => {
|
|||||||
if(formRef.value) formRef.value.clearValidate('batch_number')
|
if(formRef.value) formRef.value.clearValidate('batch_number')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 价格联动计算 (精确到小数点后2位,并支持空值)
|
// 价格联动:含税单价为主输入,不含税价格自动反算
|
||||||
|
// 追踪用户最后编辑的是含税还是不含税('pre' | 'post')
|
||||||
|
const lastPriceEdit = ref<'pre' | 'post'>('post') // 默认以含税为主
|
||||||
|
|
||||||
const updatePrices = (source: string) => {
|
const updatePrices = (source: string) => {
|
||||||
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
|
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
|
||||||
|
|
||||||
if (source === 'pre') {
|
if (source === 'pre') {
|
||||||
if (form.unit_price !== undefined && form.unit_price !== null) {
|
// 用户编辑了不含税单价 → 反推含税
|
||||||
|
lastPriceEdit.value = 'pre'
|
||||||
|
if (form.unit_price != null) {
|
||||||
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
|
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
|
||||||
} else {
|
} else {
|
||||||
form.post_tax_unit_price = undefined;
|
form.post_tax_unit_price = undefined;
|
||||||
}
|
}
|
||||||
} else if (source === 'post') {
|
} else if (source === 'post') {
|
||||||
if (form.post_tax_unit_price !== undefined && form.post_tax_unit_price !== null) {
|
// 用户编辑了含税单价 → 反推不含税
|
||||||
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(2));
|
lastPriceEdit.value = 'post'
|
||||||
|
if (form.post_tax_unit_price != null) {
|
||||||
|
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(4));
|
||||||
} else {
|
} else {
|
||||||
form.unit_price = undefined;
|
form.unit_price = undefined;
|
||||||
}
|
}
|
||||||
} else if (source === 'tax') {
|
} else if (source === 'tax') {
|
||||||
if (form.unit_price !== undefined && form.unit_price !== null) {
|
// 税率变化:保持用户最后编辑的那个价格不变,重算另一个
|
||||||
|
if (lastPriceEdit.value === 'post' && form.post_tax_unit_price != null) {
|
||||||
|
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(4));
|
||||||
|
} else if (form.unit_price != null) {
|
||||||
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
|
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
|
||||||
}
|
}
|
||||||
|
} else if (source === 'post_total') {
|
||||||
|
// 用户输入了含税总价 → 反推不含税总价和单价
|
||||||
|
lastPriceEdit.value = 'post'
|
||||||
|
const postTaxTotal = form._post_tax_total_price
|
||||||
|
if (postTaxTotal != null && form.in_quantity > 0) {
|
||||||
|
const preTaxTotal = postTaxTotal / taxMultiplier
|
||||||
|
form.total_price = Number(preTaxTotal.toFixed(2))
|
||||||
|
form.unit_price = Number((preTaxTotal / form.in_quantity).toFixed(4))
|
||||||
|
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2))
|
||||||
|
}
|
||||||
|
return // 已完整计算,跳过下面的总价逻辑
|
||||||
}
|
}
|
||||||
|
|
||||||
if (form.in_quantity !== undefined && form.unit_price !== undefined && form.unit_price !== null) {
|
// 计算不含税总价
|
||||||
|
if (form.in_quantity > 0 && form.unit_price != null) {
|
||||||
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(2));
|
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(2));
|
||||||
} else {
|
} else {
|
||||||
form.total_price = undefined;
|
form.total_price = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 数量或不含税单价变化 → 自动推总价和含税单价
|
||||||
watch(() => [form.in_quantity, form.unit_price], () => {
|
watch(() => [form.in_quantity, form.unit_price], () => {
|
||||||
if (form.unit_price !== undefined && form.unit_price !== null) {
|
if (form.unit_price != null && form.in_quantity > 0) {
|
||||||
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(2));
|
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(2));
|
||||||
// 同时更新含税单价
|
|
||||||
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
|
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
|
||||||
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
|
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
|
||||||
} else {
|
} else {
|
||||||
@ -2005,7 +2046,8 @@ const resetForm = () => {
|
|||||||
tax_rate: 0,
|
tax_rate: 0,
|
||||||
currency: 'CNY', exchange_rate: 1.00, supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '', arrival_photo: [], inspection_report: [],
|
currency: 'CNY', exchange_rate: 1.00, supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '', arrival_photo: [], inspection_report: [],
|
||||||
print_copies: 1,
|
print_copies: 1,
|
||||||
request_id: undefined
|
request_id: undefined,
|
||||||
|
_post_tax_total_price: undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const getStatusType = (status: string) => { const map: any = {'在库': 'success', '出库': 'info', '损耗': 'danger'}; return map[status] || 'warning' }
|
const getStatusType = (status: string) => { const map: any = {'在库': 'success', '出库': 'info', '损耗': 'danger'}; return map[status] || 'warning' }
|
||||||
|
|||||||
Reference in New Issue
Block a user