File created successfully at: c:\tmp\insert_assets.sql (file state is current in your context — no need to Read it back)

-- Reference variables
SET @admin = '019e3035-d8be-72ea-9599-7c8d9a68c4ca';
SET @testuser = '019e3057-9143-70e0-83b5-a4722c344ad5';
SET @wangwei = 'd215a440-51ac-11f1-bf48-7eb6b3ae683b';
SET @lina = 'd215af13-51ac-11f1-bf48-7eb6b3ae683b';
SET @zhangsan = 'd215b1ec-51ac-11f1-bf48-7eb6b3ae683b';
SET @liuyang = 'd215b3e5-51ac-11f1-bf48-7eb6b3ae683b';
SET @chenxu = 'd215b5b1-51ac-11f1-bf48-7eb6b3ae683b';

SET @loc_hq_a = 'd218e7fb-51ac-11f1-bf48-7eb6b3ae683b';
SET @loc_hq_b = 'd218f2a6-51ac-11f1-bf48-7eb6b3ae683b';
SET @loc_rd = 'd218f6cb-51ac-11f1-bf48-7eb6b3ae683b';
SET @loc_bj = 'd218f9bc-51ac-11f1-bf48-7eb6b3ae683b';
SET @loc_sh = 'd218fc69-51ac-11f1-bf48-7eb6b3ae683b';
SET @loc_wh_off = 'd218ff03-51ac-11f1-bf48-7eb6b3ae683b';
SET @loc_wh_spare = 'd219019b-51ac-11f1-bf48-7eb6b3ae683b';

SET @sup_dell = 'd21b16fb-51ac-11f1-bf48-7eb6b3ae683b';
SET @sup_lenovo = 'd21b1fbe-51ac-11f1-bf48-7eb6b3ae683b';
SET @sup_huawei = 'd21b2320-51ac-11f1-bf48-7eb6b3ae683b';
SET @sup_ms = 'd21b2523-51ac-11f1-bf48-7eb6b3ae683b';
SET @sup_oracle = 'd21b272b-51ac-11f1-bf48-7eb6b3ae683b';
SET @sup_kejie = 'd21b2902-51ac-11f1-bf48-7eb6b3ae683b';

SET @mfr_dell = '019e3058-1931-7c78-9290-d2a5bcae2323';
SET @mfr_lenovo = 'd21d470f-51ac-11f1-bf48-7eb6b3ae683b';
SET @mfr_huawei = 'd21d4f9f-51ac-11f1-bf48-7eb6b3ae683b';
SET @mfr_hp = 'd21d51cd-51ac-11f1-bf48-7eb6b3ae683b';
SET @mfr_cisco = 'd21d5387-51ac-11f1-bf48-7eb6b3ae683b';
SET @mfr_ms = 'd21d5518-51ac-11f1-bf48-7eb6b3ae683b';
SET @mfr_oracle = 'd21d56a9-51ac-11f1-bf48-7eb6b3ae683b';

SET @cat_server = '019e3035-d8c0-7e72-bd29-ad5352d98cff';
SET @cat_pc = '019e3035-d8c0-7e72-bd2a-9e07f1f23da5';
SET @cat_sw_license = '019e3035-d8c1-76cf-9c77-8a12cb4ec0b9';
SET @cat_saas = '019e3035-d8c1-76cf-9c78-77d0601448b5';
SET @cat_power = '019e3035-d8ce-74ee-9817-64b60562c76c';
SET @cat_net_acc = '019e3035-d8cf-759c-9fa9-a68c1ec47f34';
SET @cat_office_con = '019e3035-d8cf-759c-9faa-723872d1e191';
SET @cat_print_con = '019e3036-e597-7938-be1f-067966358dec';

SET @model_opti = '019e3058-1be7-7177-a8ff-b7bd730e312a';

-- DEVICES (10 records)
INSERT INTO itam_device (id, model_id, category_id, assets_status, serial, device_no, name, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, description, create_time) VALUES
(UUID(), @model_opti, @cat_pc, '1', 'SN-DELL-20240001', 'DEV-2024-001', 'Dell OptiPlex 7090 - Dev Workstation 01', '2024-01-15', 8999.00, '2027-01-15', @wangwei, @loc_rd, @sup_dell, 'R&D Dev Workstation', NOW()),
(UUID(), @model_opti, @cat_pc, '1', 'SN-DELL-20240002', 'DEV-2024-002', 'Dell OptiPlex 7090 - Dev Workstation 02', '2024-01-15', 8999.00, '2027-01-15', @zhangsan, @loc_rd, @sup_dell, 'R&D Dev Workstation', NOW()),
(UUID(), @model_opti, @cat_pc, '1', 'SN-DELL-20240003', 'DEV-2024-003', 'Dell OptiPlex 7090 - Designer PC', '2024-02-20', 10999.00, '2027-02-20', @lina, @loc_rd, @sup_dell, 'UI Designer High-spec PC', NOW()),
(UUID(), @model_opti, @cat_pc, '2', 'SN-DELL-20240004', 'DEV-2024-004', 'Dell OptiPlex 7090 - Ops Workstation', '2024-03-10', 8999.00, '2027-03-10', @liuyang, @loc_hq_a, @sup_dell, 'Operations Monitor Workstation', NOW()),
(UUID(), @model_opti, @cat_pc, '1', 'SN-DELL-20240005', 'DEV-2024-005', 'Dell OptiPlex 7090 - Finance PC', '2024-03-15', 7999.00, '2027-03-15', @chenxu, @loc_hq_a, @sup_dell, 'Finance Dept Office PC', NOW()),
(UUID(), @model_opti, @cat_server, '1', 'SN-DELL-20240006', 'SRV-2024-001', 'Dell PowerEdge R750 - App Server 01', '2024-04-01', 45000.00, '2028-04-01', @admin, @loc_hq_a, @sup_dell, 'Core Application Server', NOW()),
(UUID(), @model_opti, @cat_server, '1', 'SN-DELL-20240007', 'SRV-2024-002', 'Dell PowerEdge R750 - DB Server 01', '2024-04-01', 68000.00, '2028-04-01', @admin, @loc_hq_b, @sup_dell, 'MySQL DB Primary Server', NOW()),
(UUID(), @model_opti, @cat_pc, '1', 'SN-DELL-20240008', 'DEV-2024-006', 'Dell OptiPlex 7090 - QA Test PC', '2024-05-01', 6999.00, '2027-05-01', @testuser, @loc_rd, @sup_dell, 'QA Testing Machine', NOW()),
(UUID(), @model_opti, @cat_server, '1', 'SN-DELL-20240009', 'SRV-2024-003', 'Dell PowerEdge R750 - Backup Server', '2024-06-01', 35000.00, '2028-06-01', @liuyang, @loc_bj, @sup_dell, 'Beijing Branch Backup Server', NOW()),
(UUID(), @model_opti, @cat_pc, '2', 'SN-DELL-20240010', 'DEV-2024-007', 'Dell OptiPlex 7090 - SH Office PC', '2024-06-15', 7999.00, '2027-06-15', @lina, @loc_sh, @sup_dell, 'Shanghai Branch Office PC', NOW());

-- LICENSES (8 records)
INSERT INTO itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, assigned_to, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, notes, create_time) VALUES
(UUID(), 'Microsoft Windows 11 Pro', 'W11P-XXXXX-XXXXX-XXXXX-XXXXX', 50, @mfr_ms, @cat_sw_license, @admin, 5, 'Our ITAM Co. Ltd.', 'it@ouritam.com', @sup_ms, 'PO-2024-MS001', 75000.00, '2024-01-01', '2027-01-01', 'Company-wide Windows 11 Pro license', NOW()),
(UUID(), 'Microsoft Office 365 E3', 'O365E3-XXXXX-XXXXX-XXXXX-XXXXX', 100, @mfr_ms, @cat_saas, @admin, 10, 'Our ITAM Co. Ltd.', 'it@ouritam.com', @sup_ms, 'PO-2024-MS002', 120000.00, '2024-01-01', '2025-01-01', 'Office 365 E3 subscription (annual)', NOW()),
(UUID(), 'Oracle Database 19c EE', 'ODB19-XXXXX-XXXXX-XXXXX-XXXXX', 4, @mfr_oracle, @cat_sw_license, @admin, 1, 'Our ITAM Co. Ltd.', 'it@ouritam.com', @sup_oracle, 'PO-2024-ORA001', 220000.00, '2024-02-01', '2027-02-01', 'Oracle DB Enterprise Edition (4 cores)', NOW()),
(UUID(), 'JetBrains All Products Pack', 'JB-ALL-XXXXX-XXXXX-XXXXX-XXXXX', 25, NULL, @cat_sw_license, @wangwei, 1, 'R&D Team', 'dev@ouritam.com', NULL, 'PO-2024-JB001', 48000.00, '2024-02-15', '2025-02-15', 'R&D IDE All Products Pack (annual)', NOW()),
(UUID(), 'Adobe Creative Cloud', 'ADCC-XXXXX-XXXXX-XXXXX-XXXXX', 10, NULL, @cat_saas, @lina, 1, 'Design Team', 'design@ouritam.com', NULL, 'PO-2024-AD001', 36000.00, '2024-03-01', '2025-03-01', 'Design Team Adobe Suite (annual)', NOW()),
(UUID(), 'VMware vSphere 8 Enterprise', 'VMW8-XXXXX-XXXXX-XXXXX-XXXXX', 6, NULL, @cat_sw_license, @liuyang, 1, 'Ops Team', 'ops@ouritam.com', @sup_dell, 'PO-2024-VMW001', 85000.00, '2024-03-15', '2027-03-15', 'Virtualization platform (6 CPUs)', NOW()),
(UUID(), 'Cisco IOS-XE License', 'CIOS-XXXXX-XXXXX-XXXXX-XXXXX', 4, @mfr_cisco, @cat_sw_license, @liuyang, 1, 'Network Team', 'net@ouritam.com', @sup_huawei, 'PO-2024-CIS001', 32000.00, '2024-04-01', '2026-04-01', 'Cisco Switch IOS License', NOW()),
(UUID(), 'Slack Enterprise Grid', 'SLK-ENT-XXXXX-XXXXX-XXXXX-XXXXX', 200, NULL, @cat_saas, @admin, 10, 'All Employees', 'all@ouritam.com', NULL, 'PO-2024-SLK001', 58000.00, '2024-04-01', '2025-04-01', 'Company-wide instant messaging (annual)', NOW());

-- ACCESSORIES (8 records)
INSERT INTO itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, assigned_to, specifications, location_id, quantity, min_quantity, purchase_date, purchase_cost, order_number, serial_number, description, create_time) VALUES
(UUID(), 'Dell 27-inch 4K Monitor', 'ACC-2024-001', @cat_power, @sup_dell, @mfr_dell, @wangwei, 'U2723QE, 27inch 4K IPS', @loc_rd, 20, 5, '2024-01-15', 3200.00, 'PO-2024-ACC001', 'SN-ACC-2401001', 'Dev Team 4K Monitors', NOW()),
(UUID(), 'Dell Wireless KB/Mouse Set', 'ACC-2024-002', @cat_power, @sup_dell, @mfr_dell, @admin, 'KM7321W, Wireless', @loc_wh_off, 50, 10, '2024-01-15', 450.00, 'PO-2024-ACC002', 'SN-ACC-2401002', 'Office Wireless Keyboard Mouse', NOW()),
(UUID(), 'ThinkPad USB-C Dock', 'ACC-2024-003', @cat_net_acc, @sup_lenovo, @mfr_lenovo, @zhangsan, '40AY0090, USB-C Dock Gen2', @loc_rd, 25, 5, '2024-02-01', 1200.00, 'PO-2024-ACC003', 'SN-ACC-2402001', 'Laptop Docking Station', NOW()),
(UUID(), 'APC UPS 1500VA', 'ACC-2024-004', @cat_power, @sup_kejie, NULL, @liuyang, 'BR1500G-CN, 1500VA/865W', @loc_hq_a, 8, 2, '2024-02-15', 1800.00, 'PO-2024-ACC004', 'SN-ACC-2402002', 'Server Room UPS', NOW()),
(UUID(), 'Cisco SFP-10G-SR Optical Module', 'ACC-2024-005', @cat_net_acc, @sup_huawei, @mfr_cisco, @liuyang, 'SFP-10G-SR, 10GBASE-SR', @loc_hq_a, 30, 10, '2024-03-01', 800.00, 'PO-2024-ACC005', 'SN-ACC-2403001', 'Switch 10G Optical Module', NOW()),
(UUID(), 'Dell Server RAM 32GB', 'ACC-2024-006', @cat_net_acc, @sup_dell, @mfr_dell, @admin, 'DDR4-3200 ECC 32GB RDIMM', @loc_hq_b, 16, 4, '2024-03-15', 2400.00, 'PO-2024-ACC006', 'SN-ACC-2403002', 'Server Memory Upgrade', NOW()),
(UUID(), 'Intel Xeon Gold Processor', 'ACC-2024-007', @cat_net_acc, @sup_dell, NULL, @admin, 'Xeon Gold 6338N, 32C/64T', @loc_hq_b, 4, 1, '2024-04-01', 18000.00, 'PO-2024-ACC007', 'SN-ACC-2404001', 'Server CPU Spare Part', NOW()),
(UUID(), 'Logitech C920 Webcam', 'ACC-2024-008', @cat_power, @sup_kejie, NULL, @lina, 'C920 Pro HD, 1080p', @loc_wh_off, 30, 5, '2024-04-15', 350.00, 'PO-2024-ACC008', 'SN-ACC-2404002', 'Video Conference Webcam', NOW());

-- CONSUMABLES (8 records)
INSERT INTO itam_consumables (id, name, category_id, manufacturer_id, assigned_to, item_no, order_number, purchase_date, purchase_cost, quantity, min_quantity, location_id, create_time) VALUES
(UUID(), 'HP LaserJet Toner Black', @cat_print_con, @mfr_hp, @admin, 'CON-PRINT-001', 'PO-2024-CON001', '2024-01-10', 450.00, 25, 5, @loc_wh_off, NOW()),
(UUID(), 'HP LaserJet Toner Color', @cat_print_con, @mfr_hp, @admin, 'CON-PRINT-002', 'PO-2024-CON002', '2024-01-10', 550.00, 15, 3, @loc_wh_off, NOW()),
(UUID(), 'A4 Paper 70g (5 reams/box)', @cat_office_con, NULL, @admin, 'CON-OFF-001', 'PO-2024-CON003', '2024-02-01', 120.00, 100, 20, @loc_wh_off, NOW()),
(UUID(), 'Brother Label Tape TZe-231', @cat_office_con, NULL, @lina, 'CON-OFF-002', 'PO-2024-CON004', '2024-02-15', 85.00, 40, 10, @loc_wh_off, NOW()),
(UUID(), 'CAT6 Network Cable 3m', @cat_net_acc, NULL, @liuyang, 'CON-NET-001', 'PO-2024-CON005', '2024-03-01', 18.00, 200, 50, @loc_wh_spare, NOW()),
(UUID(), 'LC-LC SM Fiber Patch 3m', @cat_net_acc, NULL, @liuyang, 'CON-NET-002', 'PO-2024-CON006', '2024-03-01', 45.00, 80, 20, @loc_hq_a, NOW()),
(UUID(), 'SSD 1TB NVMe', @cat_net_acc, NULL, @wangwei, 'CON-STO-001', 'PO-2024-CON007', '2024-04-01', 680.00, 12, 3, @loc_wh_spare, NOW()),
(UUID(), 'USB-C to HDMI Adapter', @cat_power, NULL, @zhangsan, 'CON-ADP-001', 'PO-2024-CON008', '2024-04-15', 65.00, 35, 10, @loc_wh_off, NOW());

-- DEPRECIATIONS (5 records)
INSERT INTO itam_depreciations (id, name, status, months, floor_type, floor_val, stages, remark, create_time) VALUES
(UUID(), 'IT Equipment - 3yr Straight Line', 1, 36, 'amount', 100.00, NULL, 'General IT equipment 3yr depreciation, salvage 100', NOW()),
(UUID(), 'Servers - 5yr Straight Line', 1, 60, 'amount', 500.00, NULL, 'Server equipment 5yr depreciation, salvage 500', NOW()),
(UUID(), 'Office Equipment - 3yr Percent', 1, 36, 'percent', 5.00, NULL, 'Office equipment 3yr depreciation, salvage 5%', NOW()),
(UUID(), 'Software License - 2yr Full Amortization', 1, 24, 'amount', 0.00, NULL, 'Software license 2yr full amortization, no salvage', NOW()),
(UUID(), 'Network Equipment - 5yr Percent', 1, 60, 'percent', 10.00, NULL, 'Network equipment 5yr depreciation, salvage 10%', NOW());

-- OFFERINGS (6 records)
INSERT INTO itam_offering (id, name, supplier_id, assigned_to, service_number, start_date, end_date, cost, notes, offering_status, create_time) VALUES
(UUID(), 'Data Center Colocation Service', @sup_dell, @admin, 'SRV-IDC-2024-001', '2024-01-01', '2027-01-01', 180000.00, 'Shenzhen DC colocation with power, cooling, security', 'active', NOW()),
(UUID(), '100M Enterprise Dedicated Line', @sup_huawei, @liuyang, 'SRV-BW-2024-001', '2024-01-01', '2025-01-01', 48000.00, '100M enterprise dedicated internet access', 'active', NOW()),
(UUID(), 'Server Warranty Gold Service', @sup_dell, @admin, 'SRV-WAR-2024-001', '2024-02-01', '2027-02-01', 65000.00, '7x24x4 hour onsite gold service', 'active', NOW()),
(UUID(), 'IT Equipment Recycling & Destruction', @sup_kejie, @chenxu, 'SRV-DIS-2024-001', '2024-03-01', '2025-03-01', 12000.00, 'Annual IT equipment secure destruction service', 'active', NOW()),
(UUID(), 'Cloud Backup Service', @sup_ms, @liuyang, 'SRV-BKP-2024-001', '2024-04-01', '2025-04-01', 36000.00, 'Azure Backup offsite disaster recovery, 500TB', 'active', NOW()),
(UUID(), 'Security Penetration Testing', NULL, @admin, 'SRV-SEC-2024-001', '2024-05-01', '2024-11-01', 85000.00, 'Annual security penetration test and hardening', 'active', NOW());

SELECT 'ALL DATA INSERTED' AS result;


Good, the file is written. Now let me execute it.


Bash

mysql -h 192.168.2.1 -P 3307 -uroot -p'Koteladt@123' our_itam --default-character-set=utf8mb4 < /tmp/insert_assets.sql

Execute asset data insertion SQL


Error: Exit code 1
/usr/bin/bash: line 1: /tmp/insert_assets.sql: No such file or directory


On Windows with bash, I need to use the Windows path. The file is at `c:\tmp\insert_assets.sql`, which in bash would be `/c/tmp/insert_assets.sql`.


mysql -h 192.168.2.1 -P 3307 -uroot -p'Koteladt@123' our_itam --default-character-set=utf8mb4 < /c/tmp/insert_assets.sql

Execute asset data insertion SQL from Windows path


mysql: [Warning] Using a password on the command line interface can be insecure.
result
ALL DATA INSERTED


Asset data inserted successfully. Let me verify the counts and then move on to updating the magic-api endpoints.


数据插入成功。验证一下各表的数据量，然后更新 magic-api 接口。


mysql -h 192.168.2.1 -P 3307 -uroot -p'Koteladt@123' our_itam -e "SELECT 'device' t, COUNT(*) c FROM itam_device WHERE deleted=0 UNION ALL SELECT 'license', COUNT(*) FROM itam_licenses WHERE deleted=0 UNION ALL SELECT 'accessory', COUNT(*) FROM itam_accessories WHERE deleted=0 UNION ALL SELECT 'consumable', COUNT(*) FROM itam_consumables WHERE deleted=0 UNION ALL SELECT 'depreciation', COUNT(*) FROM itam_depreciations WHERE deleted=0 UNION ALL SELECT 'offering', COUNT(*) FROM itam_offering WHERE deleted=0;"

Verify asset table row counts


mysql: [Warning] Using a password on the command line interface can be insecure.
t	c
device	15
license	9
accessory	8
consumable	12
depreciation	5
offering	6


Good data counts:
- device: 15 (10 new + 4 existing + 1 extra)
- license: 9 (8 new + 1 existing)
- accessory: 8 (all new)
- consumable: 12 (8 new + 4 existing)
- depreciation: 5 (all new)
- offering: 6 (all new)

Now let me update the todo list and proceed to update the magic-api save.ms endpoints to record changes in the change_record table.

I need to read each save.ms file and modify it to:
1. Record old values before update
2. Compare old vs new
3. Write change records to itam_change_record

Let me also read the existing save.ms files for each asset type to understand the current logic.


TodoWrite

为所有资产表添加 assigned_to 责任人字段

创建资产变更记录表 itam_change_record

获取系统用户列表用于责任人分配

为所有资产表填充示例数据

更新 save 接口记录变更

更新各资产 save.ms 写入变更记录

创建变更记录查询接口

更新前端资产页面：展示责任人、变更记录


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

为所有资产表添加 assigned_to 责任人字段

创建资产变更记录表 itam_change_record

获取系统用户列表用于责任人分配

为所有资产表填充示例数据

更新各资产 save.ms 写入变更记录

更新 save 接口记录变更

创建变更记录查询接口

更新前端资产页面：展示责任人、变更记录

为所有资产表添加 assigned_to 责任人字段

创建资产变更记录表 itam_change_record

获取系统用户列表用于责任人分配

为所有资产表填充示例数据

更新各资产 save.ms 写入变更记录

更新 save 接口记录变更

创建变更记录查询接口

更新前端资产页面：展示责任人、变更记录


Now I need to update each asset's save.ms file to record changes. Let me first read the current save.ms files for each asset type.


先读取所有 save.ms 的当前内容，然后逐个更新加入变更记录逻辑。


1	{
2	  "properties": {},
3	  "id": "9911d2ac-f63e-5cec-88d7-f7d89d3e2aca",
4	  "script": null,
5	  "groupId": "9d06cc71-d6e8-502c-a704-d7a088878bb8",
6	  "name": "保存",
7	  "createTime": 1778891835481,
8	  "updateTime": null,
9	  "lock": null,
10	  "createBy": null,
11	  "updateBy": null,
12	  "path": "/save",
13	  "method": "POST",
14	  "parameters": [],
15	  "options": [],
16	  "requestBody": null,
17	  "headers": [],
18	  "paths": [],
19	  "responseBody": null,
20	  "description": null,
21	  "requestBodyDefinition": null,
22	  "responseBodyDefinition": null
23	}
24	================================
25	import 'com.itam.util.UuidUtil';
26
27	var assets_status = body.assets_status;
28	var assigned_to = body.assigned_to;
29	var category_id = body.category_id;
30	var depreciation_id = body.depreciation_id;
31	var description = body.description;
32	var device_no = body.device_no;
33	var id = body.id;
34	var image_url = body.image_url;
35	var location_id = body.location_id;
36	var model_id = body.model_id;
37	var name = body.name;
38	var purchase_cost = body.purchase_cost;
39	var purchase_date = body.purchase_date;
40	var serial = body.serial;
41	var supplier_id = body.supplier_id;
42	var warranty_date = body.warranty_date;
43	assert body.name != null && body.name != '' : 400, '设备名称不能为空';
44	assert body.model_id != null : 400, '型号不能为空';
45
46	if (body.id != null) {
47	    db.update("""
48	    update itam_device
49	    <set>
50	        <if test="name != null">name = #{name},</if>
51	        model_id = #{model_id},
52	        category_id = #{category_id},
53	        assets_status = #{assets_status},
54	        serial = #{serial},
55	        device_no = #{device_no},
56	        image_url = #{image_url},
57	        purchase_date = #{purchase_date},
58	        purchase_cost = #{purchase_cost},
59	        warranty_date = #{warranty_date},
60	        assigned_to = #{assigned_to},
61	        location_id = #{location_id},
62	        supplier_id = #{supplier_id},
63	        depreciation_id = #{depreciation_id},
64	        description = #{description},
65	        update_time = now()
66	    </set>
67	    where id = #{id} and deleted = 0
68	    """);
69
70	    // 更新 allocated 记录（如果分配有变化）
71	    var oldAssigned = db.selectValue("""
72	        select assigned_to from itam_device where id = #{id}
73	    """);
74	    if (oldAssigned != body.assigned_to) {
75	        if (oldAssigned != null) {
76	            // 归还旧的分配
77	            db.update("""
78	            update itam_allocations set status = 'returned', return_date = now(), update_time = now()
79	            where item_type = 'device' and item_id = #{id} and status = 'active'
80	            """);
81	        }
82	        if (body.assigned_to != null && body.assets_status == '2') {
83	            var allocId = UuidUtil.v7();
84	            db.insert("""
85	            insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
86	            values (#{allocId}, 'device', #{id}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
87	            """);
88	        }
89	    }
90
91	    return { id: body.id };
92	} else {
93	    var newId = UuidUtil.v7();
94	    db.insert("""
95	    insert into itam_device (id, model_id, category_id, assets_status, serial, device_no, name, image_url, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, depreciation_id, description, create_time, update_time)
96	    values (#{newId}, #{model_id}, #{category_id}, #{assets_status}, #{serial}, #{device_no}, #{name}, #{image_url}, #{purchase_date}, #{purchase_cost}, #{warranty_date}, #{assigned_to}, #{location_id}, #{supplier_id}, #{depreciation_id}, #{description}, now(), now())
97	    """);
98
99	    // 如果新建时就分配了，创建分配记录
100	    if (body.assigned_to != null && body.assets_status == '2') {
101	        var allocId = UuidUtil.v7();
102	        db.insert("""
103	        insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
104	        values (#{allocId}, 'device', #{newId}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
105	        """);
106	    }
107
108	    return { id: newId };
109	}
110

{
  "properties": {},
  "id": "9911d2ac-f63e-5cec-88d7-f7d89d3e2aca",
  "script": null,
  "groupId": "9d06cc71-d6e8-502c-a704-d7a088878bb8",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var assets_status = body.assets_status;
var assigned_to = body.assigned_to;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var device_no = body.device_no;
var id = body.id;
var image_url = body.image_url;
var location_id = body.location_id;
var model_id = body.model_id;
var name = body.name;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var serial = body.serial;
var supplier_id = body.supplier_id;
var warranty_date = body.warranty_date;
assert body.name != null && body.name != '' : 400, '设备名称不能为空';
assert body.model_id != null : 400, '型号不能为空';

if (body.id != null) {
    db.update("""
    update itam_device
    <set>
        <if test="name != null">name = #{name},</if>
        model_id = #{model_id},
        category_id = #{category_id},
        assets_status = #{assets_status},
        serial = #{serial},
        device_no = #{device_no},
        image_url = #{image_url},
        purchase_date = #{purchase_date},
        purchase_cost = #{purchase_cost},
        warranty_date = #{warranty_date},
        assigned_to = #{assigned_to},
        location_id = #{location_id},
        supplier_id = #{supplier_id},
        depreciation_id = #{depreciation_id},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    // 更新 allocated 记录（如果分配有变化）
    var oldAssigned = db.selectValue("""
        select assigned_to from itam_device where id = #{id}
    """);
    if (oldAssigned != body.assigned_to) {
        if (oldAssigned != null) {
            // 归还旧的分配
            db.update("""
            update itam_allocations set status = 'returned', return_date = now(), update_time = now()
            where item_type = 'device' and item_id = #{id} and status = 'active'
            """);
        }
        if (body.assigned_to != null && body.assets_status == '2') {
            var allocId = UuidUtil.v7();
            db.insert("""
            insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
            values (#{allocId}, 'device', #{id}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
            """);
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_device (id, model_id, category_id, assets_status, serial, device_no, name, image_url, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, depreciation_id, description, create_time, update_time)
    values (#{newId}, #{model_id}, #{category_id}, #{assets_status}, #{serial}, #{device_no}, #{name}, #{image_url}, #{purchase_date}, #{purchase_cost}, #{warranty_date}, #{assigned_to}, #{location_id}, #{supplier_id}, #{depreciation_id}, #{description}, now(), now())
    """);

    // 如果新建时就分配了，创建分配记录
    if (body.assigned_to != null && body.assets_status == '2') {
        var allocId = UuidUtil.v7();
        db.insert("""
        insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
        values (#{allocId}, 'device', #{newId}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
        """);
    }

    return { id: newId };
}


1	{
2	  "properties": {},
3	  "id": "3d31f810-7182-56a7-8d95-b8377b0e82db",
4	  "script": null,
5	  "groupId": "2b123de0-230e-5a36-9258-449f513ae52e",
6	  "name": "保存",
7	  "createTime": 1778891835481,
8	  "updateTime": null,
9	  "lock": null,
10	  "createBy": null,
11	  "updateBy": null,
12	  "path": "/save",
13	  "method": "POST",
14	  "parameters": [],
15	  "options": [],
16	  "requestBody": null,
17	  "headers": [],
18	  "paths": [],
19	  "responseBody": null,
20	  "description": null,
21	  "requestBodyDefinition": null,
22	  "responseBodyDefinition": null
23	}
24	================================
25	import 'com.itam.util.UuidUtil';
26
27	var asset_number = body.asset_number;
28	var category_id = body.category_id;
29	var depreciation_id = body.depreciation_id;
30	var description = body.description;
31	var id = body.id;
32	var location_id = body.location_id;
33	var manufacturer_id = body.manufacturer_id;
34	var min_quantity = body.min_quantity;
35	var name = body.name;
36	var order_number = body.order_number;
37	var purchase_cost = body.purchase_cost;
38	var purchase_date = body.purchase_date;
39	var quantity = body.quantity;
40	var serial_number = body.serial_number;
41	var specifications = body.specifications;
42	var supplier_id = body.supplier_id;
43	var warranty_expiration_date = body.warranty_expiration_date;
44	assert body.name != null && body.name != '' : 400, '配件名称不能为空';
45	assert body.category_id != null : 400, '分类不能为空';
46
47	if (body.id != null) {
48	    db.update("""
49	    update itam_accessories
50	    <set>
51	        <if test="name != null">name = #{name},</if>
52	        asset_number = #{asset_number},
53	        category_id = #{category_id},
54	        supplier_id = #{supplier_id},
55	        manufacturer_id = #{manufacturer_id},
56	        specifications = #{specifications},
57	        location_id = #{location_id},
58	        depreciation_id = #{depreciation_id},
59	        quantity = #{quantity},
60	        min_quantity = #{min_quantity},
61	        purchase_date = #{purchase_date},
62	        warranty_expiration_date = #{warranty_expiration_date},
63	        purchase_cost = #{purchase_cost},
64	        order_number = #{order_number},
65	        serial_number = #{serial_number},
66	        description = #{description},
67	        update_time = now()
68	    </set>
69	    where id = #{id} and deleted = 0
70	    """);
71	    return { id: body.id };
72	} else {
73	    var newId = UuidUtil.v7();
74	    db.insert("""
75	    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)
76	    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())
77	    """);
78	    return { id: newId };
79	}
80

{
  "properties": {},
  "id": "3d31f810-7182-56a7-8d95-b8377b0e82db",
  "script": null,
  "groupId": "2b123de0-230e-5a36-9258-449f513ae52e",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var asset_number = body.asset_number;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var id = body.id;
var location_id = body.location_id;
var manufacturer_id = body.manufacturer_id;
var min_quantity = body.min_quantity;
var name = body.name;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var quantity = body.quantity;
var serial_number = body.serial_number;
var specifications = body.specifications;
var supplier_id = body.supplier_id;
var warranty_expiration_date = body.warranty_expiration_date;
assert body.name != null && body.name != '' : 400, '配件名称不能为空';
assert body.category_id != null : 400, '分类不能为空';

if (body.id != null) {
    db.update("""
    update itam_accessories
    <set>
        <if test="name != null">name = #{name},</if>
        asset_number = #{asset_number},
        category_id = #{category_id},
        supplier_id = #{supplier_id},
        manufacturer_id = #{manufacturer_id},
        specifications = #{specifications},
        location_id = #{location_id},
        depreciation_id = #{depreciation_id},
        quantity = #{quantity},
        min_quantity = #{min_quantity},
        purchase_date = #{purchase_date},
        warranty_expiration_date = #{warranty_expiration_date},
        purchase_cost = #{purchase_cost},
        order_number = #{order_number},
        serial_number = #{serial_number},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)
    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())
    """);
    return { id: newId };
}


1	{
2	  "properties": {},
3	  "id": "6551709f-46cd-5438-8d52-cff974a494a1",
4	  "script": null,
5	  "groupId": "25a971ba-6a80-5bb8-88f2-a0d53c183824",
6	  "name": "保存",
7	  "createTime": 1778891835481,
8	  "updateTime": null,
9	  "lock": null,
10	  "createBy": null,
11	  "updateBy": null,
12	  "path": "/save",
13	  "method": "POST",
14	  "parameters": [],
15	  "options": [],
16	  "requestBody": null,
17	  "headers": [],
18	  "paths": [],
19	  "responseBody": null,
20	  "description": null,
21	  "requestBodyDefinition": null,
22	  "responseBodyDefinition": null
23	}
24	================================
25	import 'com.itam.util.UuidUtil';
26
27	var category_id = body.category_id;
28	var expiration_date = body.expiration_date;
29	var id = body.id;
30	var license_key = body.license_key;
31	var licensed_to_email = body.licensed_to_email;
32	var licensed_to_name = body.licensed_to_name;
33	var manufacturer_id = body.manufacturer_id;
34	var min_qty = body.min_qty;
35	var name = body.name;
36	var notes = body.notes;
37	var order_number = body.order_number;
38	var purchase_cost = body.purchase_cost;
39	var purchase_date = body.purchase_date;
40	var supplier_id = body.supplier_id;
41	var termination_date = body.termination_date;
42	var total_seats = body.total_seats;
43	assert body.name != null && body.name != '' : 400, '软件名称不能为空';
44	assert body.license_key != null && body.license_key != '' : 400, '序列号/密钥不能为空';
45
46	if (body.id != null) {
47	    db.update("""
48	    update itam_licenses
49	    <set>
50	        <if test="name != null">name = #{name},</if>
51	        license_key = #{license_key},
52	        total_seats = #{total_seats},
53	        manufacturer_id = #{manufacturer_id},
54	        category_id = #{category_id},
55	        min_qty = #{min_qty},
56	        licensed_to_name = #{licensed_to_name},
57	        licensed_to_email = #{licensed_to_email},
58	        supplier_id = #{supplier_id},
59	        order_number = #{order_number},
60	        purchase_cost = #{purchase_cost},
61	        purchase_date = #{purchase_date},
62	        expiration_date = #{expiration_date},
63	        termination_date = #{termination_date},
64	        notes = #{notes},
65	        update_time = now()
66	    </set>
67	    where id = #{id} and deleted = 0
68	    """);
69	    return { id: body.id };
70	} else {
71	    var newId = UuidUtil.v7();
72	    db.insert("""
73	    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)
74	    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())
75	    """);
76	    return { id: newId };
77	}
78

{
  "properties": {},
  "id": "6551709f-46cd-5438-8d52-cff974a494a1",
  "script": null,
  "groupId": "25a971ba-6a80-5bb8-88f2-a0d53c183824",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var category_id = body.category_id;
var expiration_date = body.expiration_date;
var id = body.id;
var license_key = body.license_key;
var licensed_to_email = body.licensed_to_email;
var licensed_to_name = body.licensed_to_name;
var manufacturer_id = body.manufacturer_id;
var min_qty = body.min_qty;
var name = body.name;
var notes = body.notes;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var supplier_id = body.supplier_id;
var termination_date = body.termination_date;
var total_seats = body.total_seats;
assert body.name != null && body.name != '' : 400, '软件名称不能为空';
assert body.license_key != null && body.license_key != '' : 400, '序列号/密钥不能为空';

if (body.id != null) {
    db.update("""
    update itam_licenses
    <set>
        <if test="name != null">name = #{name},</if>
        license_key = #{license_key},
        total_seats = #{total_seats},
        manufacturer_id = #{manufacturer_id},
        category_id = #{category_id},
        min_qty = #{min_qty},
        licensed_to_name = #{licensed_to_name},
        licensed_to_email = #{licensed_to_email},
        supplier_id = #{supplier_id},
        order_number = #{order_number},
        purchase_cost = #{purchase_cost},
        purchase_date = #{purchase_date},
        expiration_date = #{expiration_date},
        termination_date = #{termination_date},
        notes = #{notes},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)
    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())
    """);
    return { id: newId };
}


1	{
2	  "properties": {},
3	  "id": "1e5743e4-076c-56db-b06d-b94858f1b3b0",
4	  "script": null,
5	  "groupId": "e6b93db2-0e31-546d-ad30-5c6cbbc55413",
6	  "name": "保存",
7	  "createTime": 1778891835481,
8	  "updateTime": null,
9	  "lock": null,
10	  "createBy": null,
11	  "updateBy": null,
12	  "path": "/save",
13	  "method": "POST",
14	  "parameters": [],
15	  "options": [],
16	  "requestBody": null,
17	  "headers": [],
18	  "paths": [],
19	  "responseBody": null,
20	  "description": null,
21	  "requestBodyDefinition": null,
22	  "responseBodyDefinition": null
23	}
24	================================
25	import 'com.itam.util.UuidUtil';
26
27	var category_id = body.category_id;
28	var id = body.id;
29	var item_no = body.item_no;
30	var location_id = body.location_id;
31	var manufacturer_id = body.manufacturer_id;
32	var min_quantity = body.min_quantity;
33	var name = body.name;
34	var order_number = body.order_number;
35	var purchase_cost = body.purchase_cost;
36	var purchase_date = body.purchase_date;
37	var quantity = body.quantity;
38	assert body.name != null && body.name != '' : 400, '耗材名称不能为空';
39	assert body.category_id != null : 400, '分类不能为空';
40
41	if (body.id != null) {
42	    db.update("""
43	    update itam_consumables
44	    <set>
45	        <if test="name != null">name = #{name},</if>
46	        category_id = #{category_id},
47	        manufacturer_id = #{manufacturer_id},
48	        item_no = #{item_no},
49	        order_number = #{order_number},
50	        purchase_date = #{purchase_date},
51	        purchase_cost = #{purchase_cost},
52	        quantity = #{quantity},
53	        min_quantity = #{min_quantity},
54	        location_id = #{location_id},
55	        update_time = now()
56	    </set>
57	    where id = #{id} and deleted = 0
58	    """);
59	    return { id: body.id };
60	} else {
61	    var newId = UuidUtil.v7();
62	    db.insert("""
63	    insert into itam_consumables (id, name, category_id, manufacturer_id, item_no, order_number, purchase_date, purchase_cost, quantity, min_quantity, location_id, create_time, update_time)
64	    values (#{newId}, #{name}, #{category_id}, #{manufacturer_id}, #{item_no}, #{order_number}, #{purchase_date}, #{purchase_cost}, #{quantity}, #{min_quantity}, #{location_id}, now(), now())
65	    """);
66	    return { id: newId };
67	}
68

{
  "properties": {},
  "id": "1e5743e4-076c-56db-b06d-b94858f1b3b0",
  "script": null,
  "groupId": "e6b93db2-0e31-546d-ad30-5c6cbbc55413",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var category_id = body.category_id;
var id = body.id;
var item_no = body.item_no;
var location_id = body.location_id;
var manufacturer_id = body.manufacturer_id;
var min_quantity = body.min_quantity;
var name = body.name;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var quantity = body.quantity;
assert body.name != null && body.name != '' : 400, '耗材名称不能为空';
assert body.category_id != null : 400, '分类不能为空';

if (body.id != null) {
    db.update("""
    update itam_consumables
    <set>
        <if test="name != null">name = #{name},</if>
        category_id = #{category_id},
        manufacturer_id = #{manufacturer_id},
        item_no = #{item_no},
        order_number = #{order_number},
        purchase_date = #{purchase_date},
        purchase_cost = #{purchase_cost},
        quantity = #{quantity},
        min_quantity = #{min_quantity},
        location_id = #{location_id},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_consumables (id, name, category_id, manufacturer_id, item_no, order_number, purchase_date, purchase_cost, quantity, min_quantity, location_id, create_time, update_time)
    values (#{newId}, #{name}, #{category_id}, #{manufacturer_id}, #{item_no}, #{order_number}, #{purchase_date}, #{purchase_cost}, #{quantity}, #{min_quantity}, #{location_id}, now(), now())
    """);
    return { id: newId };
}


1	{
2	  "properties": {},
3	  "id": "35e99df2-b220-5dd3-92b6-4b9bc9f26149",
4	  "script": null,
5	  "groupId": "318d56b1-02b0-5ea3-a55b-281d8f9cf546",
6	  "name": "保存",
7	  "createTime": 1778891835481,
8	  "updateTime": null,
9	  "lock": null,
10	  "createBy": null,
11	  "updateBy": null,
12	  "path": "/save",
13	  "method": "POST",
14	  "parameters": [],
15	  "options": [],
16	  "requestBody": null,
17	  "headers": [],
18	  "paths": [],
19	  "responseBody": null,
20	  "description": null,
21	  "requestBodyDefinition": null,
22	  "responseBodyDefinition": null
23	}
24	================================
25	import 'com.itam.util.UuidUtil';
26
27	var cost = body.cost;
28	var end_date = body.end_date;
29	var id = body.id;
30	var name = body.name;
31	var notes = body.notes;
32	var offering_status = body.offering_status;
33	var service_number = body.service_number;
34	var start_date = body.start_date;
35	var supplier_id = body.supplier_id;
36	assert body.name != null && body.name != '' : 400, '服务名称不能为空';
37
38	if (body.id != null) {
39	    db.update("""
40	    update itam_offering
41	    <set>
42	        <if test="name != null">name = #{name},</if>
43	        supplier_id = #{supplier_id},
44	        service_number = #{service_number},
45	        start_date = #{start_date},
46	        end_date = #{end_date},
47	        cost = #{cost},
48	        notes = #{notes},
49	        offering_status = #{offering_status},
50	        update_time = now()
51	    </set>
52	    where id = #{id} and deleted = 0
53	    """);
54	    return { id: body.id };
55	} else {
56	    var newId = UuidUtil.v7();
57	    db.insert("""
58	    insert into itam_offering (id, name, supplier_id, service_number, start_date, end_date, cost, notes, offering_status, create_time, update_time)
59	    values (#{newId}, #{name}, #{supplier_id}, #{service_number}, #{start_date}, #{end_date}, #{cost}, #{notes}, #{offering_status}, now(), now())
60	    """);
61	    return { id: newId };
62	}
63

{
  "properties": {},
  "id": "35e99df2-b220-5dd3-92b6-4b9bc9f26149",
  "script": null,
  "groupId": "318d56b1-02b0-5ea3-a55b-281d8f9cf546",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var cost = body.cost;
var end_date = body.end_date;
var id = body.id;
var name = body.name;
var notes = body.notes;
var offering_status = body.offering_status;
var service_number = body.service_number;
var start_date = body.start_date;
var supplier_id = body.supplier_id;
assert body.name != null && body.name != '' : 400, '服务名称不能为空';

if (body.id != null) {
    db.update("""
    update itam_offering
    <set>
        <if test="name != null">name = #{name},</if>
        supplier_id = #{supplier_id},
        service_number = #{service_number},
        start_date = #{start_date},
        end_date = #{end_date},
        cost = #{cost},
        notes = #{notes},
        offering_status = #{offering_status},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_offering (id, name, supplier_id, service_number, start_date, end_date, cost, notes, offering_status, create_time, update_time)
    values (#{newId}, #{name}, #{supplier_id}, #{service_number}, #{start_date}, #{end_date}, #{cost}, #{notes}, #{offering_status}, now(), now())
    """);
    return { id: newId };
}


1	{
2	  "properties": {},
3	  "id": "88b0124c-a77d-5323-849a-b93ef4d5ba97",
4	  "script": null,
5	  "groupId": "cd7e5106-ce44-533e-9425-83d1841090b1",
6	  "name": "保存",
7	  "createTime": 1778891835481,
8	  "updateTime": null,
9	  "lock": null,
10	  "createBy": null,
11	  "updateBy": null,
12	  "path": "/save",
13	  "method": "POST",
14	  "parameters": [],
15	  "options": [],
16	  "requestBody": null,
17	  "headers": [],
18	  "paths": [],
19	  "responseBody": null,
20	  "description": null,
21	  "requestBodyDefinition": null,
22	  "responseBodyDefinition": null
23	}
24	================================
25	import 'com.itam.util.UuidUtil';
26
27	var floor_type = body.floor_type;
28	var floor_val = body.floor_val;
29	var id = body.id;
30	var months = body.months;
31	var name = body.name;
32	var remark = body.remark;
33	var stages = body.stages;
34	var status = body.status;
35	assert body.name != null && body.name != '' : 400, '折旧规则名称不能为空';
36	assert body.months != null && body.months > 0 : 400, '折旧月数必须大于0';
37
38	if (body.id != null) {
39	    db.update("""
40	    update itam_depreciations
41	    <set>
42	        <if test="name != null">name = #{name},</if>
43	        status = #{status},
44	        months = #{months},
45	        floor_type = #{floor_type},
46	        floor_val = #{floor_val},
47	        stages = #{stages},
48	        remark = #{remark},
49	        update_time = now()
50	    </set>
51	    where id = #{id} and deleted = 0
52	    """);
53	    return { id: body.id };
54	} else {
55	    var newId = UuidUtil.v7();
56	    db.insert("""
57	    insert into itam_depreciations (id, name, status, months, floor_type, floor_val, stages, remark, create_time, update_time)
58	    values (#{newId}, #{name}, #{status}, #{months}, #{floor_type}, #{floor_val}, #{stages}, #{remark}, now(), now())
59	    """);
60	    return { id: newId };
61	}
62

{
  "properties": {},
  "id": "88b0124c-a77d-5323-849a-b93ef4d5ba97",
  "script": null,
  "groupId": "cd7e5106-ce44-533e-9425-83d1841090b1",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var floor_type = body.floor_type;
var floor_val = body.floor_val;
var id = body.id;
var months = body.months;
var name = body.name;
var remark = body.remark;
var stages = body.stages;
var status = body.status;
assert body.name != null && body.name != '' : 400, '折旧规则名称不能为空';
assert body.months != null && body.months > 0 : 400, '折旧月数必须大于0';

if (body.id != null) {
    db.update("""
    update itam_depreciations
    <set>
        <if test="name != null">name = #{name},</if>
        status = #{status},
        months = #{months},
        floor_type = #{floor_type},
        floor_val = #{floor_val},
        stages = #{stages},
        remark = #{remark},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_depreciations (id, name, status, months, floor_type, floor_val, stages, remark, create_time, update_time)
    values (#{newId}, #{name}, #{status}, #{months}, #{floor_type}, #{floor_val}, #{stages}, #{remark}, now(), now())
    """);
    return { id: newId };
}


给所有的菜单都加数据，另外，所有资产都要归属责任人，并且 资产变更需要能查看记录


Now I need to update each save.ms to:
1. Add `assigned_to` field handling (for tables that now have it)
2. Record change history in `itam_change_record`
3. For the create case, record a creation change record
4. For the update case, compare old values and record differences

Let me also read the page.ms and detail.ms for each asset to know which ones need assigned_to added.

Let me plan the changes for each save.ms file:

### Device (save.ms)
Already has `assigned_to` handling. Need to add:
- Change record logging for create (record all fields as "create")
- Change record logging for update (compare old vs new, log each changed field)

### License (save.ms)
Need to add:
- `assigned_to` field handling
- Change record logging

### Accessory (save.ms)
Need to add:
- `assigned_to` field handling
- Change record logging

### Consumable (save.ms)
Need to add:
- `assigned_to` field handling
- Change record logging

### Depreciation (save.ms)
No `assigned_to` needed (it's a financial rule, not assigned to a person). But change record logging still needed.

### Offering (save.ms)
Need to add:
- `assigned_to` field handling
- Change record logging

For the change record approach, I'll use a helper function pattern. In magic-script, I can create a function that:
1. On create: logs one record with change_type='create', old_value=null, new_value=JSON snapshot
2. On update: queries the old record, compares fields, and logs each changed field

Let me write the save.ms files now. The change record table has:
- id (UUID)
- asset_type (device/license/accessory/consumable/depreciation/offering)
- asset_id
- asset_name
- change_type (create/update/delete)
- field_name
- old_value
- new_value
- operator_id
- operator_name
- remark
- create_time

For magic-script, the code needs to be practical. Let me make a reasonable implementation.

For the update case, a simple approach: query the old record, then compare key fields one by one, and log the ones that changed.

Actually, let me think about this differently. The magic-script language is limited. I should create a helper function that takes the old and new values and logs changes. But creating functions in magic-script might not work well.

A simpler approach: For each save.ms, on update:
1. Fetch the old record from DB
2. Call a helper API endpoint to log changes (or directly insert into itam_change_record)

Actually, the cleanest approach for magic-script:
- Create a separate magic-api endpoint `/asset/change-record/save` that accepts change data and inserts it
- Or just directly insert into `itam_change_record` in each save.ms

Let me use direct insertion since it's simpler.

For each save.ms I'll add a generic change-logging block. Let me think about the best approach...

In magic-script, I can do:
```
if (id != null) {
    // Get old record
    var old = db.selectOne("select * from table where id = #{id}");

    // Update...

    // Log changes
    var fields = ['name', 'status', ...];
    for (field in fields) {
        var oldVal = old[field];
        var newVal = body[field];
        if (oldVal != newVal) {
            db.insert("insert into itam_change_record...");
        }
    }
}
```

This should work. Let me write the updated save.ms for each asset type. I'll include the assigned_to field where it was missing.

Let me write the device save.ms first as it's the most complex (already has allocation logic):

For the device, I'll add change logging after the update/insert. The key fields to track are: name, model_id, category_id, assets_status, serial, device_no, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, depreciation_id, description.

For simplicity, I'll track the most important fields.

Let me create a unified approach. I'll add a helper section at the end of each save.ms that records changes. For create, just record one change with type 'create'. For update, compare fields and record differences.

Actually, since the magic-script is limited and I don't want to make the files too complex, let me take a practical approach:

For CREATE: Record a single change record with change_type='create' and a JSON-like summary
For UPDATE: Compare old vs new for key fields and record each change

Let me now write all 6 save.ms files. I'll use Edit to modify the existing files.


现在开始更新每个 save.ms。先从 device 开始，加入变更记录逻辑。


Write

{
  "properties": {},
  "id": "9911d2ac-f63e-5cec-88d7-f7d89d3e2aca",
  "script": null,
  "groupId": "9d06cc71-d6e8-502c-a704-d7a088878bb8",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var assets_status = body.assets_status;
var assigned_to = body.assigned_to;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var device_no = body.device_no;
var id = body.id;
var image_url = body.image_url;
var location_id = body.location_id;
var model_id = body.model_id;
var name = body.name;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var serial = body.serial;
var supplier_id = body.supplier_id;
var warranty_date = body.warranty_date;
var operatorName = body.operator_name != null ? body.operator_name : 'system';
var operatorId = body.operator_id;
assert body.name != null && body.name != '' : 400, '设备名称不能为空';
assert body.model_id != null : 400, '型号不能为空';

if (body.id != null) {
    // 查询旧记录用于变更对比
    var old = db.selectOne("""
        select * from itam_device where id = #{id} and deleted = 0
    """);

    db.update("""
    update itam_device
    <set>
        <if test="name != null">name = #{name},</if>
        model_id = #{model_id},
        category_id = #{category_id},
        assets_status = #{assets_status},
        serial = #{serial},
        device_no = #{device_no},
        image_url = #{image_url},
        purchase_date = #{purchase_date},
        purchase_cost = #{purchase_cost},
        warranty_date = #{warranty_date},
        assigned_to = #{assigned_to},
        location_id = #{location_id},
        supplier_id = #{supplier_id},
        depreciation_id = #{depreciation_id},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    // 记录变更
    if (old != null) {
        var trackFields = ['name', 'model_id', 'category_id', 'assets_status', 'serial', 'device_no', 'purchase_date', 'purchase_cost', 'warranty_date', 'assigned_to', 'location_id', 'supplier_id', 'depreciation_id', 'description'];
        for (field in trackFields) {
            var oldVal = old[field] != null ? '' + old[field] : null;
            var newVal = body[field] != null ? '' + body[field] : null;
            if (oldVal != newVal) {
                var changeId = UuidUtil.v7();
                db.insert("""
                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
                values (#{changeId}, 'device', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())
                """);
            }
        }
    }

    // 更新 allocated 记录（如果分配有变化）
    var oldAssigned = db.selectValue("""
        select assigned_to from itam_device where id = #{id}
    """);
    if (oldAssigned != body.assigned_to) {
        if (oldAssigned != null) {
            db.update("""
            update itam_allocations set status = 'returned', return_date = now(), update_time = now()
            where item_type = 'device' and item_id = #{id} and status = 'active'
            """);
        }
        if (body.assigned_to != null && body.assets_status == '2') {
            var allocId = UuidUtil.v7();
            db.insert("""
            insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
            values (#{allocId}, 'device', #{id}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
            """);
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_device (id, model_id, category_id, assets_status, serial, device_no, name, image_url, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, depreciation_id, description, create_time, update_time)
    values (#{newId}, #{model_id}, #{category_id}, #{assets_status}, #{serial}, #{device_no}, #{name}, #{image_url}, #{purchase_date}, #{purchase_cost}, #{warranty_date}, #{assigned_to}, #{location_id}, #{supplier_id}, #{depreciation_id}, #{description}, now(), now())
    """);

    // 记录创建变更
    var changeId = UuidUtil.v7();
    db.insert("""
    insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
    values (#{changeId}, 'device', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())
    """);

    // 如果新建时就分配了，创建分配记录
    if (body.assigned_to != null && body.assets_status == '2') {
        var allocId = UuidUtil.v7();
        db.insert("""
        insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
        values (#{allocId}, 'device', #{newId}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
        """);
    }

    return { id: newId };
}


The file c:\Workspace\Project\tansci\our-itam\data\magic-api\api\asset\device\save.ms has been updated successfully. (file state is current in your context — no need to Read it back)

{
  "properties": {},
  "id": "9911d2ac-f63e-5cec-88d7-f7d89d3e2aca",
  "script": null,
  "groupId": "9d06cc71-d6e8-502c-a704-d7a088878bb8",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var assets_status = body.assets_status;
var assigned_to = body.assigned_to;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var device_no = body.device_no;
var id = body.id;
var image_url = body.image_url;
var location_id = body.location_id;
var model_id = body.model_id;
var name = body.name;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var serial = body.serial;
var supplier_id = body.supplier_id;
var warranty_date = body.warranty_date;
var operatorName = body.operator_name != null ? body.operator_name : 'system';
var operatorId = body.operator_id;
assert body.name != null && body.name != '' : 400, '设备名称不能为空';
assert body.model_id != null : 400, '型号不能为空';

if (body.id != null) {
    // 查询旧记录用于变更对比
    var old = db.selectOne("""
        select * from itam_device where id = #{id} and deleted = 0
    """);

    db.update("""
    update itam_device
    <set>
        <if test="name != null">name = #{name},</if>
        model_id = #{model_id},
        category_id = #{category_id},
        assets_status = #{assets_status},
        serial = #{serial},
        device_no = #{device_no},
        image_url = #{image_url},
        purchase_date = #{purchase_date},
        purchase_cost = #{purchase_cost},
        warranty_date = #{warranty_date},
        assigned_to = #{assigned_to},
        location_id = #{location_id},
        supplier_id = #{supplier_id},
        depreciation_id = #{depreciation_id},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    // 记录变更
    if (old != null) {
        var trackFields = ['name', 'model_id', 'category_id', 'assets_status', 'serial', 'device_no', 'purchase_date', 'purchase_cost', 'warranty_date', 'assigned_to', 'location_id', 'supplier_id', 'depreciation_id', 'description'];
        for (field in trackFields) {
            var oldVal = old[field] != null ? '' + old[field] : null;
            var newVal = body[field] != null ? '' + body[field] : null;
            if (oldVal != newVal) {
                var changeId = UuidUtil.v7();
                db.insert("""
                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
                values (#{changeId}, 'device', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())
                """);
            }
        }
    }

    // 更新 allocated 记录（如果分配有变化）
    var oldAssigned = db.selectValue("""
        select assigned_to from itam_device where id = #{id}
    """);
    if (oldAssigned != body.assigned_to) {
        if (oldAssigned != null) {
            db.update("""
            update itam_allocations set status = 'returned', return_date = now(), update_time = now()
            where item_type = 'device' and item_id = #{id} and status = 'active'
            """);
        }
        if (body.assigned_to != null && body.assets_status == '2') {
            var allocId = UuidUtil.v7();
            db.insert("""
            insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
            values (#{allocId}, 'device', #{id}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
            """);
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_device (id, model_id, category_id, assets_status, serial, device_no, name, image_url, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, depreciation_id, description, create_time, update_time)
    values (#{newId}, #{model_id}, #{category_id}, #{assets_status}, #{serial}, #{device_no}, #{name}, #{image_url}, #{purchase_date}, #{purchase_cost}, #{warranty_date}, #{assigned_to}, #{location_id}, #{supplier_id}, #{depreciation_id}, #{description}, now(), now())
    """);

    // 记录创建变更
    var changeId = UuidUtil.v7();
    db.insert("""
    insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
    values (#{changeId}, 'device', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())
    """);

    // 如果新建时就分配了，创建分配记录
    if (body.assigned_to != null && body.assets_status == '2') {
        var allocId = UuidUtil.v7();
        db.insert("""
        insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
        values (#{allocId}, 'device', #{newId}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
        """);
    }

    return { id: newId };
}

+var operatorName = body.operator_name != null ? body.operator_name : 'system';

+    // 查询旧记录用于变更对比

+        select * from itam_device where id = #{id} and deleted = 0

+    // 记录变更

+        var trackFields = ['name', 'model_id', 'category_id', 'assets_status', 'serial', 'device_no', 'purchase_date', 'purchase_cost', 'warranty_date', 'assigned_to', 'location_id', 'supplier_id', 'depreciation_id', 'description'];

+            var oldVal = old[field] != null ? '' + old[field] : null;

+            var newVal = body[field] != null ? '' + body[field] : null;

+                var changeId = UuidUtil.v7();

+                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)

+                values (#{changeId}, 'device', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())

// 更新 allocated 记录（如果分配有变化）

-            // 归还旧的分配

+    // 记录创建变更

+    values (#{changeId}, 'device', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())

// 如果新建时就分配了，创建分配记录

{
  "properties": {},
  "id": "9911d2ac-f63e-5cec-88d7-f7d89d3e2aca",
  "script": null,
  "groupId": "9d06cc71-d6e8-502c-a704-d7a088878bb8",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var assets_status = body.assets_status;
var assigned_to = body.assigned_to;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var device_no = body.device_no;
var id = body.id;
var image_url = body.image_url;
var location_id = body.location_id;
var model_id = body.model_id;
var name = body.name;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var serial = body.serial;
var supplier_id = body.supplier_id;
var warranty_date = body.warranty_date;
assert body.name != null && body.name != '' : 400, '设备名称不能为空';
assert body.model_id != null : 400, '型号不能为空';

if (body.id != null) {
    db.update("""
    update itam_device
    <set>
        <if test="name != null">name = #{name},</if>
        model_id = #{model_id},
        category_id = #{category_id},
        assets_status = #{assets_status},
        serial = #{serial},
        device_no = #{device_no},
        image_url = #{image_url},
        purchase_date = #{purchase_date},
        purchase_cost = #{purchase_cost},
        warranty_date = #{warranty_date},
        assigned_to = #{assigned_to},
        location_id = #{location_id},
        supplier_id = #{supplier_id},
        depreciation_id = #{depreciation_id},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    // 更新 allocated 记录（如果分配有变化）
    var oldAssigned = db.selectValue("""
        select assigned_to from itam_device where id = #{id}
    """);
    if (oldAssigned != body.assigned_to) {
        if (oldAssigned != null) {
            // 归还旧的分配
            db.update("""
            update itam_allocations set status = 'returned', return_date = now(), update_time = now()
            where item_type = 'device' and item_id = #{id} and status = 'active'
            """);
        }
        if (body.assigned_to != null && body.assets_status == '2') {
            var allocId = UuidUtil.v7();
            db.insert("""
            insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
            values (#{allocId}, 'device', #{id}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
            """);
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_device (id, model_id, category_id, assets_status, serial, device_no, name, image_url, purchase_date, purchase_cost, warranty_date, assigned_to, location_id, supplier_id, depreciation_id, description, create_time, update_time)
    values (#{newId}, #{model_id}, #{category_id}, #{assets_status}, #{serial}, #{device_no}, #{name}, #{image_url}, #{purchase_date}, #{purchase_cost}, #{warranty_date}, #{assigned_to}, #{location_id}, #{supplier_id}, #{depreciation_id}, #{description}, now(), now())
    """);

    // 如果新建时就分配了，创建分配记录
    if (body.assigned_to != null && body.assets_status == '2') {
        var allocId = UuidUtil.v7();
        db.insert("""
        insert into itam_allocations (id, item_type, item_id, owner_type, owner_id, quantity, status, assign_date, create_time, update_time)
        values (#{allocId}, 'device', #{newId}, 'user', #{assigned_to}, 1, 'active', now(), now(), now())
        """);
    }

    return { id: newId };
}


Good. Now let me update the license save.ms to add assigned_to and change record logging.


{
  "properties": {},
  "id": "6551709f-46cd-5438-8d52-cff974a494a1",
  "script": null,
  "groupId": "25a971ba-6a80-5bb8-88f2-a0d53c183824",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var assigned_to = body.assigned_to;
var category_id = body.category_id;
var expiration_date = body.expiration_date;
var id = body.id;
var license_key = body.license_key;
var licensed_to_email = body.licensed_to_email;
var licensed_to_name = body.licensed_to_name;
var manufacturer_id = body.manufacturer_id;
var min_qty = body.min_qty;
var name = body.name;
var notes = body.notes;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var supplier_id = body.supplier_id;
var termination_date = body.termination_date;
var total_seats = body.total_seats;
var operatorName = body.operator_name != null ? body.operator_name : 'system';
var operatorId = body.operator_id;
assert body.name != null && body.name != '' : 400, '软件名称不能为空';
assert body.license_key != null && body.license_key != '' : 400, '序列号/密钥不能为空';

if (body.id != null) {
    var old = db.selectOne("""
        select * from itam_licenses where id = #{id} and deleted = 0
    """);

    db.update("""
    update itam_licenses
    <set>
        <if test="name != null">name = #{name},</if>
        license_key = #{license_key},
        total_seats = #{total_seats},
        manufacturer_id = #{manufacturer_id},
        category_id = #{category_id},
        assigned_to = #{assigned_to},
        min_qty = #{min_qty},
        licensed_to_name = #{licensed_to_name},
        licensed_to_email = #{licensed_to_email},
        supplier_id = #{supplier_id},
        order_number = #{order_number},
        purchase_cost = #{purchase_cost},
        purchase_date = #{purchase_date},
        expiration_date = #{expiration_date},
        termination_date = #{termination_date},
        notes = #{notes},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    // 记录变更
    if (old != null) {
        var trackFields = ['name', 'license_key', 'total_seats', 'manufacturer_id', 'category_id', 'assigned_to', 'min_qty', 'licensed_to_name', 'licensed_to_email', 'supplier_id', 'order_number', 'purchase_cost', 'purchase_date', 'expiration_date', 'termination_date', 'notes'];
        for (field in trackFields) {
            var oldVal = old[field] != null ? '' + old[field] : null;
            var newVal = body[field] != null ? '' + body[field] : null;
            if (oldVal != newVal) {
                var changeId = UuidUtil.v7();
                db.insert("""
                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
                values (#{changeId}, 'license', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())
                """);
            }
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, assigned_to, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)
    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{assigned_to}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())
    """);

    var changeId = UuidUtil.v7();
    db.insert("""
    insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
    values (#{changeId}, 'license', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())
    """);

    return { id: newId };
}


The file c:\Workspace\Project\tansci\our-itam\data\magic-api\api\asset\license\save.ms has been updated successfully. (file state is current in your context — no need to Read it back)

{
  "properties": {},
  "id": "6551709f-46cd-5438-8d52-cff974a494a1",
  "script": null,
  "groupId": "25a971ba-6a80-5bb8-88f2-a0d53c183824",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var assigned_to = body.assigned_to;
var category_id = body.category_id;
var expiration_date = body.expiration_date;
var id = body.id;
var license_key = body.license_key;
var licensed_to_email = body.licensed_to_email;
var licensed_to_name = body.licensed_to_name;
var manufacturer_id = body.manufacturer_id;
var min_qty = body.min_qty;
var name = body.name;
var notes = body.notes;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var supplier_id = body.supplier_id;
var termination_date = body.termination_date;
var total_seats = body.total_seats;
var operatorName = body.operator_name != null ? body.operator_name : 'system';
var operatorId = body.operator_id;
assert body.name != null && body.name != '' : 400, '软件名称不能为空';
assert body.license_key != null && body.license_key != '' : 400, '序列号/密钥不能为空';

if (body.id != null) {
    var old = db.selectOne("""
        select * from itam_licenses where id = #{id} and deleted = 0
    """);

    db.update("""
    update itam_licenses
    <set>
        <if test="name != null">name = #{name},</if>
        license_key = #{license_key},
        total_seats = #{total_seats},
        manufacturer_id = #{manufacturer_id},
        category_id = #{category_id},
        assigned_to = #{assigned_to},
        min_qty = #{min_qty},
        licensed_to_name = #{licensed_to_name},
        licensed_to_email = #{licensed_to_email},
        supplier_id = #{supplier_id},
        order_number = #{order_number},
        purchase_cost = #{purchase_cost},
        purchase_date = #{purchase_date},
        expiration_date = #{expiration_date},
        termination_date = #{termination_date},
        notes = #{notes},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    // 记录变更
    if (old != null) {
        var trackFields = ['name', 'license_key', 'total_seats', 'manufacturer_id', 'category_id', 'assigned_to', 'min_qty', 'licensed_to_name', 'licensed_to_email', 'supplier_id', 'order_number', 'purchase_cost', 'purchase_date', 'expiration_date', 'termination_date', 'notes'];
        for (field in trackFields) {
            var oldVal = old[field] != null ? '' + old[field] : null;
            var newVal = body[field] != null ? '' + body[field] : null;
            if (oldVal != newVal) {
                var changeId = UuidUtil.v7();
                db.insert("""
                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
                values (#{changeId}, 'license', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())
                """);
            }
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, assigned_to, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)
    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{assigned_to}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())
    """);

    var changeId = UuidUtil.v7();
    db.insert("""
    insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
    values (#{changeId}, 'license', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())
    """);

    return { id: newId };
}

+var operatorName = body.operator_name != null ? body.operator_name : 'system';

+        select * from itam_licenses where id = #{id} and deleted = 0

+    // 记录变更

+        var trackFields = ['name', 'license_key', 'total_seats', 'manufacturer_id', 'category_id', 'assigned_to', 'min_qty', 'licensed_to_name', 'licensed_to_email', 'supplier_id', 'order_number', 'purchase_cost', 'purchase_date', 'expiration_date', 'termination_date', 'notes'];

+            var oldVal = old[field] != null ? '' + old[field] : null;

+            var newVal = body[field] != null ? '' + body[field] : null;

+                var changeId = UuidUtil.v7();

+                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)

+                values (#{changeId}, 'license', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())

-    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)

-    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())

+    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, assigned_to, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)

+    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{assigned_to}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())

+    values (#{changeId}, 'license', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())

{
  "properties": {},
  "id": "6551709f-46cd-5438-8d52-cff974a494a1",
  "script": null,
  "groupId": "25a971ba-6a80-5bb8-88f2-a0d53c183824",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var category_id = body.category_id;
var expiration_date = body.expiration_date;
var id = body.id;
var license_key = body.license_key;
var licensed_to_email = body.licensed_to_email;
var licensed_to_name = body.licensed_to_name;
var manufacturer_id = body.manufacturer_id;
var min_qty = body.min_qty;
var name = body.name;
var notes = body.notes;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var supplier_id = body.supplier_id;
var termination_date = body.termination_date;
var total_seats = body.total_seats;
assert body.name != null && body.name != '' : 400, '软件名称不能为空';
assert body.license_key != null && body.license_key != '' : 400, '序列号/密钥不能为空';

if (body.id != null) {
    db.update("""
    update itam_licenses
    <set>
        <if test="name != null">name = #{name},</if>
        license_key = #{license_key},
        total_seats = #{total_seats},
        manufacturer_id = #{manufacturer_id},
        category_id = #{category_id},
        min_qty = #{min_qty},
        licensed_to_name = #{licensed_to_name},
        licensed_to_email = #{licensed_to_email},
        supplier_id = #{supplier_id},
        order_number = #{order_number},
        purchase_cost = #{purchase_cost},
        purchase_date = #{purchase_date},
        expiration_date = #{expiration_date},
        termination_date = #{termination_date},
        notes = #{notes},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_licenses (id, name, license_key, total_seats, manufacturer_id, category_id, min_qty, licensed_to_name, licensed_to_email, supplier_id, order_number, purchase_cost, purchase_date, expiration_date, termination_date, notes, create_time, update_time)
    values (#{newId}, #{name}, #{license_key}, #{total_seats}, #{manufacturer_id}, #{category_id}, #{min_qty}, #{licensed_to_name}, #{licensed_to_email}, #{supplier_id}, #{order_number}, #{purchase_cost}, #{purchase_date}, #{expiration_date}, #{termination_date}, #{notes}, now(), now())
    """);
    return { id: newId };
}


为所有资产表添加 assigned_to 责任人字段

创建资产变更记录表 itam_change_record

获取系统用户列表用于责任人分配

为所有资产表填充示例数据

更新各资产 save.ms 写入变更记录

更新 save 接口记录变更

创建变更记录查询接口

更新前端资产页面：展示责任人、变更记录


Good. Now let me update the remaining 4 save.ms files: accessory, consumable, depreciation, offering.


{
  "properties": {},
  "id": "3d31f810-7182-56a7-8d95-b8377b0e82db",
  "script": null,
  "groupId": "2b123de0-230e-5a36-9258-449f513ae52e",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var asset_number = body.asset_number;
var assigned_to = body.assigned_to;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var id = body.id;
var location_id = body.location_id;
var manufacturer_id = body.manufacturer_id;
var min_quantity = body.min_quantity;
var name = body.name;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var quantity = body.quantity;
var serial_number = body.serial_number;
var specifications = body.specifications;
var supplier_id = body.supplier_id;
var warranty_expiration_date = body.warranty_expiration_date;
var operatorName = body.operator_name != null ? body.operator_name : 'system';
var operatorId = body.operator_id;
assert body.name != null && body.name != '' : 400, '配件名称不能为空';
assert body.category_id != null : 400, '分类不能为空';

if (body.id != null) {
    var old = db.selectOne("""
        select * from itam_accessories where id = #{id} and deleted = 0
    """);

    db.update("""
    update itam_accessories
    <set>
        <if test="name != null">name = #{name},</if>
        asset_number = #{asset_number},
        category_id = #{category_id},
        supplier_id = #{supplier_id},
        manufacturer_id = #{manufacturer_id},
        assigned_to = #{assigned_to},
        specifications = #{specifications},
        location_id = #{location_id},
        depreciation_id = #{depreciation_id},
        quantity = #{quantity},
        min_quantity = #{min_quantity},
        purchase_date = #{purchase_date},
        warranty_expiration_date = #{warranty_expiration_date},
        purchase_cost = #{purchase_cost},
        order_number = #{order_number},
        serial_number = #{serial_number},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    if (old != null) {
        var trackFields = ['name', 'asset_number', 'category_id', 'supplier_id', 'manufacturer_id', 'assigned_to', 'specifications', 'location_id', 'depreciation_id', 'quantity', 'min_quantity', 'purchase_date', 'warranty_expiration_date', 'purchase_cost', 'order_number', 'serial_number', 'description'];
        for (field in trackFields) {
            var oldVal = old[field] != null ? '' + old[field] : null;
            var newVal = body[field] != null ? '' + body[field] : null;
            if (oldVal != newVal) {
                var changeId = UuidUtil.v7();
                db.insert("""
                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
                values (#{changeId}, 'accessory', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())
                """);
            }
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, assigned_to, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)
    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{assigned_to}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())
    """);

    var changeId = UuidUtil.v7();
    db.insert("""
    insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
    values (#{changeId}, 'accessory', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())
    """);

    return { id: newId };
}


The file c:\Workspace\Project\tansci\our-itam\data\magic-api\api\asset\accessory\save.ms has been updated successfully. (file state is current in your context — no need to Read it back)

{
  "properties": {},
  "id": "3d31f810-7182-56a7-8d95-b8377b0e82db",
  "script": null,
  "groupId": "2b123de0-230e-5a36-9258-449f513ae52e",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var asset_number = body.asset_number;
var assigned_to = body.assigned_to;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var id = body.id;
var location_id = body.location_id;
var manufacturer_id = body.manufacturer_id;
var min_quantity = body.min_quantity;
var name = body.name;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var quantity = body.quantity;
var serial_number = body.serial_number;
var specifications = body.specifications;
var supplier_id = body.supplier_id;
var warranty_expiration_date = body.warranty_expiration_date;
var operatorName = body.operator_name != null ? body.operator_name : 'system';
var operatorId = body.operator_id;
assert body.name != null && body.name != '' : 400, '配件名称不能为空';
assert body.category_id != null : 400, '分类不能为空';

if (body.id != null) {
    var old = db.selectOne("""
        select * from itam_accessories where id = #{id} and deleted = 0
    """);

    db.update("""
    update itam_accessories
    <set>
        <if test="name != null">name = #{name},</if>
        asset_number = #{asset_number},
        category_id = #{category_id},
        supplier_id = #{supplier_id},
        manufacturer_id = #{manufacturer_id},
        assigned_to = #{assigned_to},
        specifications = #{specifications},
        location_id = #{location_id},
        depreciation_id = #{depreciation_id},
        quantity = #{quantity},
        min_quantity = #{min_quantity},
        purchase_date = #{purchase_date},
        warranty_expiration_date = #{warranty_expiration_date},
        purchase_cost = #{purchase_cost},
        order_number = #{order_number},
        serial_number = #{serial_number},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);

    if (old != null) {
        var trackFields = ['name', 'asset_number', 'category_id', 'supplier_id', 'manufacturer_id', 'assigned_to', 'specifications', 'location_id', 'depreciation_id', 'quantity', 'min_quantity', 'purchase_date', 'warranty_expiration_date', 'purchase_cost', 'order_number', 'serial_number', 'description'];
        for (field in trackFields) {
            var oldVal = old[field] != null ? '' + old[field] : null;
            var newVal = body[field] != null ? '' + body[field] : null;
            if (oldVal != newVal) {
                var changeId = UuidUtil.v7();
                db.insert("""
                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
                values (#{changeId}, 'accessory', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())
                """);
            }
        }
    }

    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, assigned_to, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)
    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{assigned_to}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())
    """);

    var changeId = UuidUtil.v7();
    db.insert("""
    insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)
    values (#{changeId}, 'accessory', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())
    """);

    return { id: newId };
}

+var operatorName = body.operator_name != null ? body.operator_name : 'system';

+        select * from itam_accessories where id = #{id} and deleted = 0

+        var trackFields = ['name', 'asset_number', 'category_id', 'supplier_id', 'manufacturer_id', 'assigned_to', 'specifications', 'location_id', 'depreciation_id', 'quantity', 'min_quantity', 'purchase_date', 'warranty_expiration_date', 'purchase_cost', 'order_number', 'serial_number', 'description'];

+            var oldVal = old[field] != null ? '' + old[field] : null;

+            var newVal = body[field] != null ? '' + body[field] : null;

+                var changeId = UuidUtil.v7();

+                insert into itam_change_record (id, asset_type, asset_id, asset_name, change_type, field_name, old_value, new_value, operator_id, operator_name, create_time)

+                values (#{changeId}, 'accessory', #{id}, #{old.name}, 'update', #{field}, #{oldVal}, #{newVal}, #{operatorId}, #{operatorName}, now())

-    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)

-    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())

+    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, assigned_to, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)

+    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{assigned_to}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())

+    values (#{changeId}, 'accessory', #{newId}, #{name}, 'create', null, null, null, #{operatorId}, #{operatorName}, now())

{
  "properties": {},
  "id": "3d31f810-7182-56a7-8d95-b8377b0e82db",
  "script": null,
  "groupId": "2b123de0-230e-5a36-9258-449f513ae52e",
  "name": "保存",
  "createTime": 1778891835481,
  "updateTime": null,
  "lock": null,
  "createBy": null,
  "updateBy": null,
  "path": "/save",
  "method": "POST",
  "parameters": [],
  "options": [],
  "requestBody": null,
  "headers": [],
  "paths": [],
  "responseBody": null,
  "description": null,
  "requestBodyDefinition": null,
  "responseBodyDefinition": null
}
================================
import 'com.itam.util.UuidUtil';

var asset_number = body.asset_number;
var category_id = body.category_id;
var depreciation_id = body.depreciation_id;
var description = body.description;
var id = body.id;
var location_id = body.location_id;
var manufacturer_id = body.manufacturer_id;
var min_quantity = body.min_quantity;
var name = body.name;
var order_number = body.order_number;
var purchase_cost = body.purchase_cost;
var purchase_date = body.purchase_date;
var quantity = body.quantity;
var serial_number = body.serial_number;
var specifications = body.specifications;
var supplier_id = body.supplier_id;
var warranty_expiration_date = body.warranty_expiration_date;
assert body.name != null && body.name != '' : 400, '配件名称不能为空';
assert body.category_id != null : 400, '分类不能为空';

if (body.id != null) {
    db.update("""
    update itam_accessories
    <set>
        <if test="name != null">name = #{name},</if>
        asset_number = #{asset_number},
        category_id = #{category_id},
        supplier_id = #{supplier_id},
        manufacturer_id = #{manufacturer_id},
        specifications = #{specifications},
        location_id = #{location_id},
        depreciation_id = #{depreciation_id},
        quantity = #{quantity},
        min_quantity = #{min_quantity},
        purchase_date = #{purchase_date},
        warranty_expiration_date = #{warranty_expiration_date},
        purchase_cost = #{purchase_cost},
        order_number = #{order_number},
        serial_number = #{serial_number},
        description = #{description},
        update_time = now()
    </set>
    where id = #{id} and deleted = 0
    """);
    return { id: body.id };
} else {
    var newId = UuidUtil.v7();
    db.insert("""
    insert into itam_accessories (id, name, asset_number, category_id, supplier_id, manufacturer_id, specifications, location_id, depreciation_id, quantity, min_quantity, purchase_date, warranty_expiration_date, purchase_cost, order_number, serial_number, description, create_time, update_time)
    values (#{newId}, #{name}, #{asset_number}, #{category_id}, #{supplier_id}, #{manufacturer_id}, #{specifications}, #{location_id}, #{depreciation_id}, #{quantity}, #{min_quantity}, #{purchase_date}, #{warranty_expiration_date}, #{purchase_cost}, #{order_number}, #{serial_number}, #{description}, now(), now())
    """);
    return { id: newId };
}