diff --git a/wm-revenue/pom.xml b/wm-revenue/pom.xml index 64f4d965..59429eed 100644 --- a/wm-revenue/pom.xml +++ b/wm-revenue/pom.xml @@ -6,8 +6,9 @@ com.water - water-management-system - 1.0.0 + wm-parent + 1.0.0-SNAPSHOT + ../pom.xml wm-revenue diff --git a/wm-revenue/src/main/java/com/water/revenue/controller/MeterLifecycleController.java b/wm-revenue/src/main/java/com/water/revenue/controller/MeterLifecycleController.java new file mode 100644 index 00000000..80fbea3c --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/controller/MeterLifecycleController.java @@ -0,0 +1,153 @@ +package com.water.revenue.controller; + +import com.water.revenue.service.MeterService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/meter/lifecycle") +public class MeterLifecycleController { + + private final MeterService meterService; + + /** + * 水表入库 + */ + @PostMapping("/stock-in") + public ResponseEntity stockIn( + @RequestParam String meterNo, + @RequestParam String caliber, + @RequestParam String meterType, + @RequestParam String manufacturer, + @RequestParam int quantity, + @RequestParam String operatorId, + @RequestParam String operatorName) { + + try { + meterService.stockIn(meterNo, caliber, meterType, manufacturer, quantity, operatorId, operatorName); + return ResponseEntity.ok().body(Map.of("success", true, "message", "水表入库成功")); + } catch (Exception e) { + log.error("水表入库失败", e); + return ResponseEntity.badRequest().body(Map.of("success", false, "message", "水表入库失败: " + e.getMessage())); + } + } + + /** + * 水表安装 + */ + @PostMapping("/install") + public ResponseEntity install( + @RequestParam Long meterId, + @RequestParam Long customerId, + @RequestParam String address, + @RequestParam BigDecimal initialReading, + @RequestParam String operatorId, + @RequestParam String operatorName) { + + try { + meterService.install(meterId, customerId, address, initialReading, operatorId, operatorName); + return ResponseEntity.ok().body(Map.of("success", true, "message", "水表安装成功")); + } catch (Exception e) { + log.error("水表安装失败", e); + return ResponseEntity.badRequest().body(Map.of("success", false, "message", "水表安装失败: " + e.getMessage())); + } + } + + /** + * 故障换表 + */ + @PostMapping("/replace") + public ResponseEntity replace( + @RequestParam Long oldMeterId, + @RequestParam Long newMeterId, + @RequestParam BigDecimal oldReading, + @RequestParam String remark, + @RequestParam String operatorId, + @RequestParam String operatorName) { + + try { + meterService.replace(oldMeterId, newMeterId, oldReading, remark, operatorId, operatorName); + return ResponseEntity.ok().body(Map.of("success", true, "message", "换表成功")); + } catch (Exception e) { + log.error("换表失败", e); + return ResponseEntity.badRequest().body(Map.of("success", false, "message", "换表失败: " + e.getMessage())); + } + } + + /** + * 水表报废 + */ + @PostMapping("/scrap") + public ResponseEntity scrap( + @RequestParam Long meterId, + @RequestParam String reason, + @RequestParam String operatorId, + @RequestParam String operatorName) { + + try { + meterService.scrap(meterId, reason, operatorId, operatorName); + return ResponseEntity.ok().body(Map.of("success", true, "message", "水表报废成功")); + } catch (Exception e) { + log.error("水表报废失败", e); + return ResponseEntity.badRequest().body(Map.of("success", false, "message", "水表报废失败: " + e.getMessage())); + } + } + + /** + * 查询水表生命周期记录 + */ + @GetMapping("/lifecycle/{meterId}") + public ResponseEntity>> getLifecycle(@PathVariable Long meterId) { + List> lifecycle = meterService.getLifecycle(meterId); + return ResponseEntity.ok(lifecycle); + } + + /** + * 获取库存统计 + */ + @GetMapping("/inventory/stats") + public ResponseEntity> getInventoryStats() { + Map stats = meterService.getInventoryStats(); + return ResponseEntity.ok(stats); + } + + /** + * 查询库存水表 + */ + @GetMapping("/inventory") + public ResponseEntity>> getWarehouseMeters( + @RequestParam(required = false) String caliber, + @RequestParam(required = false) String meterType, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + + List> meters = meterService.getWarehouseMeters(caliber, meterType, page, size); + return ResponseEntity.ok(meters); + } + + /** + * 获取最近操作记录 + */ + @GetMapping("/recent-operations") + public ResponseEntity>> getRecentOperations(@RequestParam(defaultValue = "10") int limit) { + List> operations = meterService.getRecentOperations(limit); + return ResponseEntity.ok(operations); + } + + /** + * 获取水表详情 + */ + @GetMapping("/{meterId}") + public ResponseEntity> getMeterDetails(@PathVariable Long meterId) { + Map details = meterService.getMeterDetails(meterId); + return ResponseEntity.ok(details); + } +} \ No newline at end of file diff --git a/wm-revenue/src/main/java/com/water/revenue/dto/MeterInventoryStatsDTO.java b/wm-revenue/src/main/java/com/water/revenue/dto/MeterInventoryStatsDTO.java new file mode 100644 index 00000000..49287aa7 --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/dto/MeterInventoryStatsDTO.java @@ -0,0 +1,39 @@ +package com.water.revenue.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MeterInventoryStatsDTO { + + // 总体统计 + private Long totalWarehouse; + private Long totalActive; + private Long totalDismantled; + private Long totalScrapped; + + // 按状态统计 + private Map statusStats; + + // 按口径统计 + private Map caliberStats; + + // 按类型统计 + private Map typeStats; + + // 按制造商统计 + private Map manufacturerStats; + + // 最近操作 + private List recentOperations; +} \ No newline at end of file diff --git a/wm-revenue/src/main/java/com/water/revenue/dto/MeterOperationLogDTO.java b/wm-revenue/src/main/java/com/water/revenue/dto/MeterOperationLogDTO.java new file mode 100644 index 00000000..6ae31668 --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/dto/MeterOperationLogDTO.java @@ -0,0 +1,47 @@ +package com.water.revenue.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MeterOperationLogDTO { + + private Long id; + private Long meterId; + private String meterNo; + private String operationType; + private String operationName; + private BigDecimal oldReading; + private BigDecimal newReading; + private String equipmentNo; + private Long operatorId; + private String operatorName; + private List photos; + private String remark; + private LocalDateTime createdAt; + + // 操作类型中文名称映射 + public String getOperationName() { + switch (operationType) { + case "install": return "安装"; + case "dismantle": return "拆除"; + case "replace": return "更换"; + case "scrap": return "报废"; + case "stock_in": return "入库"; + case "repair": return "维修"; + case "calibrate": return "校准"; + case "refurbish": return "翻新"; + default: return operationType; + } + } +} \ No newline at end of file diff --git a/wm-revenue/src/main/java/com/water/revenue/service/MeterService.java b/wm-revenue/src/main/java/com/water/revenue/service/MeterService.java index 53f6ebf4..427e7be0 100644 --- a/wm-revenue/src/main/java/com/water/revenue/service/MeterService.java +++ b/wm-revenue/src/main/java/com/water/revenue/service/MeterService.java @@ -17,35 +17,42 @@ public class MeterService { private final JdbcTemplate jdbcTemplate; /** 水表入库 */ - public void stockIn(String meterNo, String caliber, String meterType, String manufacturer, int quantity) { + @Transactional + public void stockIn(String meterNo, String caliber, String meterType, String manufacturer, int quantity, String operatorId, String operatorName) { for (int i = 0; i < quantity; i++) { String no = meterNo + "-" + (i + 1); jdbcTemplate.update( "INSERT INTO rev_meter (meter_no, caliber, meter_type, manufacturer, status) VALUES (?,?,?,?,?)", no, caliber, meterType, manufacturer, "warehouse"); + + // 记录入库日志 + jdbcTemplate.update( + "INSERT INTO rev_meter_log (meter_id, operation_type, operator_id, operator_name, remark) VALUES (?,?,?,?,?)", + jdbcTemplate.queryForObject("SELECT id FROM rev_meter WHERE meter_no = ?", Long.class, no), + "stock_in", operatorId, operatorName, "水表入库:" + meterNo + "-" + (i + 1)); } log.info("Meter stock in: {} x{}", meterNo, quantity); } /** 水表出库安装 */ @Transactional - public void install(Long meterId, Long customerId, String address, BigDecimal initialReading) { + public void install(Long meterId, Long customerId, String address, BigDecimal initialReading, String operatorId, String operatorName) { jdbcTemplate.update( "UPDATE rev_meter SET customer_id = ?, install_address = ?, initial_reading = ?, current_reading = ?, status = 'active', install_date = CURRENT_DATE WHERE id = ?", customerId, address, initialReading, initialReading, meterId); jdbcTemplate.update( - "INSERT INTO rev_meter_log (meter_id, operation_type, old_reading, new_reading, remark) VALUES (?,?,?,?,?)", - meterId, "install", BigDecimal.ZERO, initialReading, "新表安装"); + "INSERT INTO rev_meter_log (meter_id, operation_type, operator_id, operator_name, old_reading, new_reading, remark) VALUES (?,?,?,?,?,?,?)", + meterId, "install", operatorId, operatorName, BigDecimal.ZERO, initialReading, "新表安装"); } /** 故障换表 */ @Transactional - public void replace(Long oldMeterId, Long newMeterId, BigDecimal oldReading, String remark) { + public void replace(Long oldMeterId, Long newMeterId, BigDecimal oldReading, String remark, String operatorId, String operatorName) { // 旧表拆除 - jdbcTemplate.update("UPDATE rev_meter SET status = 'dismantled', current_reading = ? WHERE id = ?", oldReading, oldMeterId); + jdbcTemplate.update("UPDATE rev_meter SET status = 'dismantled', current_reading = ?, dismantle_date = CURRENT_DATE WHERE id = ?", oldReading, oldMeterId); jdbcTemplate.update( - "INSERT INTO rev_meter_log (meter_id, operation_type, old_reading, remark) VALUES (?,?,?,?)", - oldMeterId, "dismantle", oldReading, remark); + "INSERT INTO rev_meter_log (meter_id, operation_type, operator_id, operator_name, old_reading, remark) VALUES (?,?,?,?,?,?)", + oldMeterId, "dismantle", operatorId, operatorName, oldReading, remark); // 新表安装(继承客户信息) Map oldMeter = jdbcTemplate.queryForMap("SELECT customer_id, install_address FROM rev_meter WHERE id = ?", oldMeterId); @@ -53,16 +60,20 @@ public class MeterService { "UPDATE rev_meter SET customer_id = ?, install_address = ?, status = 'active', install_date = CURRENT_DATE WHERE id = ?", oldMeter.get("customer_id"), oldMeter.get("install_address"), newMeterId); jdbcTemplate.update( - "INSERT INTO rev_meter_log (meter_id, operation_type, new_meter_no, remark) VALUES (?,?,?,?)", - newMeterId, "change", String.valueOf(newMeterId), "替换旧表 #" + oldMeterId); + "INSERT INTO rev_meter_log (meter_id, operation_type, operator_id, operator_name, new_meter_no, remark) VALUES (?,?,?,?,?,?)", + newMeterId, "change", operatorId, operatorName, String.valueOf(newMeterId), "替换旧表 #" + oldMeterId); + + log.info("Meter replaced: old={}, new={}, operator={}", oldMeterId, newMeterId, operatorId); } /** 水表报废 */ - public void scrap(Long meterId, String reason) { - jdbcTemplate.update("UPDATE rev_meter SET status = 'scrapped' WHERE id = ?", meterId); + @Transactional + public void scrap(Long meterId, String reason, String operatorId, String operatorName) { + jdbcTemplate.update("UPDATE rev_meter SET status = 'scrapped', scrapped_date = CURRENT_DATE WHERE id = ?", meterId); jdbcTemplate.update( - "INSERT INTO rev_meter_log (meter_id, operation_type, remark) VALUES (?,?,?)", - meterId, "scrap", reason); + "INSERT INTO rev_meter_log (meter_id, operation_type, operator_id, operator_name, remark) VALUES (?,?,?,?,?)", + meterId, "scrap", operatorId, operatorName, reason); + log.info("Meter scrapped: id={}, reason={}", meterId, reason); } /** 查询水表生命周期记录 */ @@ -71,4 +82,92 @@ public class MeterService { "SELECT * FROM rev_meter_log WHERE meter_id = ? ORDER BY created_at", meterId); } + + /** 库存统计 */ + public Map getInventoryStats() { + Map stats = new HashMap<>(); + + // 按状态统计 + List> statusStats = jdbcTemplate.queryForList( + "SELECT status, COUNT(*) as count FROM rev_meter GROUP BY status"); + stats.put("statusStats", statusStats); + + // 按口径统计 + List> caliberStats = jdbcTemplate.queryForList( + "SELECT caliber, COUNT(*) as count FROM rev_meter WHERE status = 'warehouse' GROUP BY caliber"); + stats.put("caliberStats", caliberStats); + + // 按类型统计 + List> typeStats = jdbcTemplate.queryForList( + "SELECT meter_type, COUNT(*) as count FROM rev_meter WHERE status = 'warehouse' GROUP BY meter_type"); + stats.put("typeStats", typeStats); + + // 按制造商统计 + List> manufacturerStats = jdbcTemplate.queryForList( + "SELECT manufacturer, COUNT(*) as count FROM rev_meter WHERE status = 'warehouse' GROUP BY manufacturer"); + stats.put("manufacturerStats", manufacturerStats); + + // 总库存 + Long totalWarehouse = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM rev_meter WHERE status = 'warehouse'", Long.class); + stats.put("totalWarehouse", totalWarehouse); + + // 活跃水表数 + Long totalActive = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM rev_meter WHERE status = 'active'", Long.class); + stats.put("totalActive", totalActive); + + // 其他状态计数 + Long totalDismantled = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM rev_meter WHERE status = 'dismantled'", Long.class); + stats.put("totalDismantled", totalDismantled); + + Long totalScrapped = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM rev_meter WHERE status = 'scrapped'", Long.class); + stats.put("totalScrapped", totalScrapped); + + return stats; + } + + /** 库存查询 */ + public List> getWarehouseMeters(String caliber, String meterType, int page, int size) { + String sql = "SELECT * FROM rev_meter WHERE status = 'warehouse'"; + List params = new ArrayList<>(); + + if (caliber != null && !caliber.isEmpty()) { + sql += " AND caliber = ?"; + params.add(caliber); + } + if (meterType != null && !meterType.isEmpty()) { + sql += " AND meter_type = ?"; + params.add(meterType); + } + + sql += " ORDER BY created_at DESC LIMIT ? OFFSET ?"; + params.add(size); + params.add(page * size); + + return jdbcTemplate.queryForList(sql, params.toArray()); + } + + /** 获取最近操作记录 */ + public List> getRecentOperations(int limit) { + return jdbcTemplate.queryForList( + "SELECT rml.*, rm.meter_no " + + "FROM rev_meter_log rml " + + "JOIN rev_meter rm ON rml.meter_id = rm.id " + + "ORDER BY rml.created_at DESC LIMIT ?", limit); + } + + /** 获取水表详情 */ + public Map getMeterDetails(Long meterId) { + Map meter = jdbcTemplate.queryForMap( + "SELECT * FROM rev_meter WHERE id = ?", meterId); + + // 获取生命周期记录 + List> lifecycle = getLifecycle(meterId); + meter.put("lifecycle", lifecycle); + + return meter; + } } diff --git a/wm-revenue/src/main/resources/db/V1__base_tables.sql b/wm-revenue/src/main/resources/db/V1__base_tables.sql index ec80d10a..3458835a 100644 --- a/wm-revenue/src/main/resources/db/V1__base_tables.sql +++ b/wm-revenue/src/main/resources/db/V1__base_tables.sql @@ -54,6 +54,9 @@ CREATE TABLE IF NOT EXISTS rev_meter ( install_date DATE, install_address VARCHAR(300), status VARCHAR(20) DEFAULT 'active', -- active/dismantled/scrapped/repaired/warehouse + install_date DATE, + scrapped_date DATE, + dismantle_date DATE, remark VARCHAR(500), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() @@ -64,12 +67,14 @@ COMMENT ON TABLE rev_meter IS '水表档案表'; CREATE TABLE IF NOT EXISTS rev_meter_log ( id BIGSERIAL PRIMARY KEY, meter_id BIGINT REFERENCES rev_meter(id), - operation_type VARCHAR(30) NOT NULL, -- install/dismantle/repair/change/scrap/calibrate/refurbish + operation_type VARCHAR(30) NOT NULL, -- install/dismantle/repair/change/scrap/calibrate/refurbish/stock_in old_reading DECIMAL(10,2), new_reading DECIMAL(10,2), new_meter_no VARCHAR(50), operator_id BIGINT, operator_name VARCHAR(50), + photos JSONB, -- 现场照片URL数组 + equipment_no VARCHAR(50), -- 设备编号(如新换的表号) photos JSONB, -- 现场照片URL数组 remark VARCHAR(500), created_at TIMESTAMP DEFAULT NOW() diff --git a/wm-revenue/src/main/resources/db/V4__meter_lifecycle.sql b/wm-revenue/src/main/resources/db/V4__meter_lifecycle.sql new file mode 100644 index 00000000..1c70f8f1 --- /dev/null +++ b/wm-revenue/src/main/resources/db/V4__meter_lifecycle.sql @@ -0,0 +1,38 @@ +-- 水表全生命周期管理升级脚本 +-- 添加缺失的日期字段到水表表 + +-- 为水表表添加安装、拆除、报废日期字段 +ALTER TABLE rev_meter ADD COLUMN IF NOT EXISTS install_date DATE; +ALTER TABLE rev_meter ADD COLUMN IF NOT EXISTS scrapped_date DATE; +ALTER TABLE rev_meter ADD COLUMN IF NOT EXISTS dismantle_date DATE; + +-- 添加照片和设备编号字段到日志表 +ALTER TABLE rev_meter_log ADD COLUMN IF NOT EXISTS photos JSONB; +ALTER TABLE rev_meter_log ADD COLUMN IF NOT EXISTS equipment_no VARCHAR(50); + +-- 创建水表统计视图 +CREATE OR REPLACE VIEW v_meter_statistics AS +SELECT + status, + COUNT(*) as count, + COUNT(CASE WHEN install_date IS NOT NULL THEN 1 END) as installed_count, + COUNT(CASE WHEN scrapped_date IS NOT NULL THEN 1 END) as scrapped_count, + COUNT(CASE WHEN dismantle_date IS NOT NULL THEN 1 END) as dismantled_count +FROM rev_meter +GROUP BY status; + +-- 创建库存统计视图 +CREATE OR REPLACE VIEW v_meter_inventory AS +SELECT + status, + caliber, + meter_type, + manufacturer, + COUNT(*) as count +FROM rev_meter +GROUP BY status, caliber, meter_type, manufacturer +ORDER BY status, caliber, meter_type, manufacturer; + +-- 为水表操作类型添加注释 +COMMENT ON COLUMN rev_meter.status IS 'active/dismantled/scrapped/repaired/warehouse'; +COMMENT ON COLUMN rev_meter_log.operation_type IS 'install/dismantle/repair/change/scrap/calibrate/refurbish/stock_in'; \ No newline at end of file diff --git a/wm-revenue/src/main/resources/db/V5__meter_test_data.sql b/wm-revenue/src/main/resources/db/V5__meter_test_data.sql new file mode 100644 index 00000000..3e008d4b --- /dev/null +++ b/wm-revenue/src/main/resources/db/V5__meter_test_data.sql @@ -0,0 +1,40 @@ +-- 水表全生命周期管理测试数据 +-- 插入测试用水表数据 + +-- 插入测试用水表(仓库状态) +INSERT INTO rev_meter (meter_no, caliber, meter_type, manufacturer, status, created_at) VALUES +('WH001', 'DN15', 'mechanical', '威胜', 'warehouse', CURRENT_TIMESTAMP), +('WH002', 'DN20', 'mechanical', '威胜', 'warehouse', CURRENT_TIMESTAMP), +('WH003', 'DN15', 'electromagnetic', '三川', 'warehouse', CURRENT_TIMESTAMP), +('WH004', 'DN25', 'ultrasonic', '宁水', 'warehouse', CURRENT_TIMESTAMP), +('WH005', 'DN40', 'mechanical', '威胜', 'warehouse', CURRENT_TIMESTAMP), +('WH006', 'DN50', 'electromagnetic', '三川', 'warehouse', CURRENT_TIMESTAMP), +('WH007', 'DN80', 'ultrasonic', '宁水', 'warehouse', CURRENT_TIMESTAMP), +('WH008', 'DN100', 'ultrasonic', '宁水', 'warehouse', CURRENT_TIMESTAMP), +('WH009', 'DN15', 'mechanical', '威胜', 'warehouse', CURRENT_TIMESTAMP), +('WH010', 'DN20', 'electromagnetic', '三川', 'warehouse', CURRENT_TIMESTAMP) +ON CONFLICT (meter_no) DO NOTHING; + +-- 插入一些已安装的水表用于测试 +INSERT INTO rev_meter (meter_no, customer_id, caliber, meter_type, manufacturer, status, install_date, initial_reading, current_reading, created_at) VALUES +('M001', 1, 'DN15', 'mechanical', '威胜', 'active', '2025-01-01', 0.00, 1200.50, CURRENT_TIMESTAMP), +('M002', 2, 'DN20', 'electromagnetic', '三川', 'active', '2025-02-01', 0.00, 2100.75, CURRENT_TIMESTAMP), +('M003', 3, 'DN15', 'ultrasonic', '宁水', 'dismantled', '2025-03-01', 0.00, 3200.00, CURRENT_TIMESTAMP), +('M004', 4, 'DN25', 'mechanical', '威胜', 'scrapped', '2025-04-01', 0.00, 1500.25, CURRENT_TIMESTAMP) +ON CONFLICT (meter_no) DO NOTHING; + +-- 插入一些操作记录测试数据 +INSERT INTO rev_meter_log (meter_id, operation_type, operator_id, operator_name, old_reading, new_reading, remark, created_at) VALUES +((SELECT id FROM rev_meter WHERE meter_no = 'M001'), 'install', '1001', '张三', 0.00, 100.00, '新表安装', CURRENT_TIMESTAMP - INTERVAL '1 year'), +((SELECT id FROM rev_meter WHERE meter_no = 'M001'), 'calibrate', '1002', '李四', 1100.00, 1100.50, '年度校准', CURRENT_TIMESTAMP - INTERVAL '6 months'), +((SELECT id FROM rev_meter WHERE meter_no = 'M001'), 'repair', '1001', '张三', 1150.00, 1150.00, '更换电池', CURRENT_TIMESTAMP - INTERVAL '3 months'), + +((SELECT id FROM rev_meter WHERE meter_no = 'M002'), 'install', '1001', '张三', 0.00, 200.00, '新表安装', CURRENT_TIMESTAMP - INTERVAL '1 year'), +((SELECT id FROM rev_meter WHERE meter_no = 'M002'), 'replace', '1003', '王五', 2000.00, 2100.75, '故障换表', CURRENT_TIMESTAMP - INTERVAL '1 month'), + +((SELECT id FROM rev_meter WHERE meter_no = 'M003'), 'install', '1001', '张三', 0.00, 300.00, '新表安装', CURRENT_TIMESTAMP - INTERVAL '2 years'), +((SELECT id FROM rev_meter WHERE meter_no = 'M003'), 'dismantle', '1004', '赵六', 3000.00, 3200.00, '客户要求拆除', CURRENT_TIMESTAMP - INTERVAL '1 month'), + +((SELECT id FROM rev_meter WHERE meter_no = 'M004'), 'install', '1001', '张三', 0.00, 400.00, '新表安装', CURRENT_TIMESTAMP - INTERVAL '2 years'), +((SELECT id FROM rev_meter WHERE meter_no = 'M004'), 'scrap', '1004', '赵六', 1500.25, NULL, '到期报废', CURRENT_TIMESTAMP - INTERVAL '1 month') +ON CONFLICT (id) DO NOTHING; \ No newline at end of file