refactor(energy): 简化事件驱动系统(7个→3个)

- 删除旧事件:BillApprovedEvent, BillCreatedEvent, DeductionCompletedEvent, DetailAuditedEvent, DetailCreatedEvent, RecordMatchedEvent
- 新增事件:BillAuditPassedEvent, DetailAuditPassedEvent
- 保留事件:RecordImportedEvent
- 更新监听器:AccountEventListener, BillEventListener, DetailEventListener
- 清理代码中的旧事件引用和注释

优化原则:前端简单,后端健壮
事件流程:导入→匹配→生成明细→审核→扣款→生成账单→结算
This commit is contained in:
kkfluous
2026-03-16 12:53:14 +08:00
parent f5062cec22
commit 2f38a703f9
167 changed files with 9876 additions and 824 deletions

View File

@@ -0,0 +1,67 @@
-- 合同管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'合同管理', '', 2, 5, 5055,
'contract', 'documentation', 'asset/contract/index', 0, 'Contract'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 合同管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('合同查询', 'asset:contract:query', 3, 1, @menuId, '', '', '', 0),
('合同创建', 'asset:contract:create', 3, 2, @menuId, '', '', '', 0),
('合同更新', 'asset:contract:update', 3, 3, @menuId, '', '', '', 0),
('合同删除', 'asset:contract:delete', 3, 4, @menuId, '', '', '', 0),
('合同导出', 'asset:contract:export', 3, 5, @menuId, '', '', '', 0),
('提交审批', 'asset:contract:submit-approval', 3, 6, @menuId, '', '', '', 0),
('撤回审批', 'asset:contract:withdraw-approval', 3, 7, @menuId, '', '', '', 0),
('终止合同', 'asset:contract:terminate', 3, 8, @menuId, '', '', '', 0),
('续签合同', 'asset:contract:renew', 3, 9, @menuId, '', '', '', 0);
-- 2. 字典类型
INSERT INTO system_dict_type (name, type, status, remark, creator, create_time, updater, update_time, deleted)
VALUES
('合同类型', 'asset_contract_type', 0, '车辆租赁合同类型', 'admin', NOW(), 'admin', NOW(), b'0'),
('合同审批状态', 'asset_contract_approval_status', 0, '合同审批状态', 'admin', NOW(), 'admin', NOW(), b'0'),
('合同状态', 'asset_contract_status', 0, '合同业务状态', 'admin', NOW(), 'admin', NOW(), b'0'),
('车辆订单状态', 'asset_contract_vehicle_status', 0, '合同车辆订单状态', 'admin', NOW(), 'admin', NOW(), b'0');
-- 3. 字典数据 - 合同类型
INSERT INTO system_dict_data (dict_type, label, value, sort, status, remark, creator, create_time, updater, update_time, deleted)
VALUES
('asset_contract_type', '试用合同', '1', 1, 0, '试用期合同', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_type', '正式合同', '2', 2, 0, '正式租赁合同', 'admin', NOW(), 'admin', NOW(), b'0');
-- 4. 字典数据 - 合同审批状态
INSERT INTO system_dict_data (dict_type, label, value, sort, status, color_type, remark, creator, create_time, updater, update_time, deleted)
VALUES
('asset_contract_approval_status', '草稿', '0', 1, 0, 'info', '草稿状态', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_approval_status', '审批中', '1', 2, 0, 'warning', '审批中', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_approval_status', '审批通过', '2', 3, 0, 'success', '审批通过', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_approval_status', '审批拒绝', '3', 4, 0, 'danger', '审批拒绝', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_approval_status', '已撤回', '4', 5, 0, 'info', '已撤回', 'admin', NOW(), 'admin', NOW(), b'0');
-- 5. 字典数据 - 合同状态
INSERT INTO system_dict_data (dict_type, label, value, sort, status, color_type, remark, creator, create_time, updater, update_time, deleted)
VALUES
('asset_contract_status', '草稿', '0', 1, 0, 'info', '草稿状态', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_status', '待生效', '1', 2, 0, 'warning', '待生效', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_status', '进行中', '2', 3, 0, 'success', '进行中', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_status', '已到期', '3', 4, 0, 'info', '已到期', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_status', '已终止', '4', 5, 0, 'danger', '已终止', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_status', '已续签', '5', 6, 0, 'primary', '已续签', 'admin', NOW(), 'admin', NOW(), b'0');
-- 6. 字典数据 - 车辆订单状态
INSERT INTO system_dict_data (dict_type, label, value, sort, status, color_type, remark, creator, create_time, updater, update_time, deleted)
VALUES
('asset_contract_vehicle_status', '待交车', '0', 1, 0, 'warning', '待交车', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_vehicle_status', '已交车', '1', 2, 0, 'success', '已交车', 'admin', NOW(), 'admin', NOW(), b'0'),
('asset_contract_vehicle_status', '已退车', '2', 3, 0, 'info', '已退车', 'admin', NOW(), 'admin', NOW(), b'0');

View File

@@ -0,0 +1,74 @@
-- 合同管理补充表(合同被授权人、变更历史、附件、车辆服务项目)
-- 3. 合同被授权人表
CREATE TABLE IF NOT EXISTS `asset_contract_authorized` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`name` VARCHAR(100) NOT NULL COMMENT '姓名',
`phone` VARCHAR(20) COMMENT '电话',
`id_card` VARCHAR(30) COMMENT '身份证号',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
KEY `idx_contract_id` (`contract_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同被授权人表';
-- 4. 合同变更历史表
CREATE TABLE IF NOT EXISTS `asset_contract_change_history` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`change_type` VARCHAR(50) NOT NULL COMMENT '变更类型',
`change_content` TEXT COMMENT '变更内容',
`operator` VARCHAR(64) COMMENT '操作人',
`operate_time` DATETIME COMMENT '操作时间',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
KEY `idx_contract_id` (`contract_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同变更历史表';
-- 5. 合同附件表
CREATE TABLE IF NOT EXISTS `asset_contract_attachment` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`attachment_type` INT COMMENT '附件类型1=合同原件 2=盖章合同)',
`file_id` BIGINT COMMENT '文件ID',
`file_name` VARCHAR(255) COMMENT '文件名称',
`file_url` VARCHAR(500) COMMENT '文件URL',
`file_size` BIGINT COMMENT '文件大小(字节)',
`upload_time` DATETIME COMMENT '上传时间',
`uploader` VARCHAR(64) COMMENT '上传人',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
KEY `idx_contract_id` (`contract_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同附件表';
-- 6. 合同车辆服务项目表
CREATE TABLE IF NOT EXISTS `asset_contract_vehicle_service` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_vehicle_id` BIGINT NOT NULL COMMENT '合同车辆ID',
`service_name` VARCHAR(200) NOT NULL COMMENT '服务项目名称',
`service_fee` DECIMAL(10,2) COMMENT '服务费用(元)',
`effective_date` DATE COMMENT '生效日期',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
KEY `idx_contract_vehicle_id` (`contract_vehicle_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同车辆服务项目表';

View File

@@ -0,0 +1,73 @@
-- 合同管理表结构
-- 1. 车辆租赁合同表
CREATE TABLE IF NOT EXISTS `asset_contract` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_code` VARCHAR(50) NOT NULL COMMENT '合同编码',
`contract_type` TINYINT NOT NULL COMMENT '合同类型1=试用 2=正式)',
`project_name` VARCHAR(200) NOT NULL COMMENT '项目名称',
`start_date` DATE NOT NULL COMMENT '生效日期',
`end_date` DATE NOT NULL COMMENT '结束日期',
`payment_method` VARCHAR(100) NOT NULL COMMENT '付款方式',
`payment_cycle` VARCHAR(100) NOT NULL COMMENT '付款周期',
`signing_company` VARCHAR(200) NOT NULL COMMENT '签约公司(乙方)',
`delivery_province` VARCHAR(50) NOT NULL COMMENT '交车省份',
`delivery_city` VARCHAR(50) NOT NULL COMMENT '交车城市',
`delivery_location` VARCHAR(255) NOT NULL COMMENT '交车地点',
`remark` VARCHAR(500) COMMENT '备注',
`customer_id` BIGINT NOT NULL COMMENT '客户ID',
`customer_name` VARCHAR(100) COMMENT '客户名称(冗余)',
`third_party_enabled` BIT(1) DEFAULT b'0' COMMENT '是否三方合同',
`third_party_customer_id` BIGINT COMMENT '丙方客户ID',
`third_party_name` VARCHAR(100) COMMENT '丙方名称',
`business_dept_id` BIGINT COMMENT '业务部门ID',
`business_manager_id` BIGINT COMMENT '业务负责人ID',
`approval_status` TINYINT NOT NULL DEFAULT 0 COMMENT '审批状态0=草稿 1=审批中 2=审批通过 3=审批拒绝 4=已撤回)',
`bpm_instance_id` VARCHAR(64) COMMENT 'BPM流程实例ID',
`contract_status` TINYINT NOT NULL DEFAULT 0 COMMENT '合同状态0=草稿 1=待生效 2=进行中 3=已到期 4=已终止 5=已续签)',
`effective_time` DATETIME COMMENT '实际生效时间',
`terminate_time` DATETIME COMMENT '终止时间',
`terminate_reason` VARCHAR(500) COMMENT '终止原因',
`renewed_contract_id` BIGINT COMMENT '续签后的新合同ID',
`original_contract_id` BIGINT COMMENT '原合同ID如果是续签合同',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_contract_code` (`contract_code`, `deleted`),
KEY `idx_customer_id` (`customer_id`),
KEY `idx_approval_status` (`approval_status`),
KEY `idx_contract_status` (`contract_status`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='车辆租赁合同表';
-- 2. 合同车辆租赁订单表
CREATE TABLE IF NOT EXISTS `asset_contract_vehicle` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`vehicle_id` BIGINT COMMENT '车辆ID关联 asset_vehicle_base',
`brand` VARCHAR(50) NOT NULL COMMENT '品牌',
`model` VARCHAR(100) NOT NULL COMMENT '型号',
`plate_no` VARCHAR(20) COMMENT '车牌号',
`vin` VARCHAR(50) COMMENT 'VIN码',
`month_rent` DECIMAL(10,2) NOT NULL COMMENT '月租金(元)',
`deposit` DECIMAL(10,2) NOT NULL COMMENT '保证金(元)',
`vehicle_status` TINYINT NOT NULL DEFAULT 0 COMMENT '车辆状态0=待交车 1=已交车 2=已退车)',
`actual_delivery_time` DATETIME COMMENT '实际交车时间',
`delivery_person` VARCHAR(50) COMMENT '交车人',
`remark` VARCHAR(500) COMMENT '备注',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
KEY `idx_contract_id` (`contract_id`),
KEY `idx_vehicle_id` (`vehicle_id`),
KEY `idx_plate_no` (`plate_no`),
KEY `idx_vin` (`vin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同车辆租赁订单表';

View File

@@ -0,0 +1,27 @@
-- 合同管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'合同管理', '', 2, 6, 5055,
'contract', 'file-text', 'asset/contract/index', 0, 'Contract'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 合同管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('合同查询', 'asset:contract:query', 3, 1, @menuId, '', '', '', 0),
('合同创建', 'asset:contract:create', 3, 2, @menuId, '', '', '', 0),
('合同更新', 'asset:contract:update', 3, 3, @menuId, '', '', '', 0),
('合同删除', 'asset:contract:delete', 3, 4, @menuId, '', '', '', 0),
('合同导出', 'asset:contract:export', 3, 5, @menuId, '', '', '', 0),
('提交审批', 'asset:contract:submit-approval', 3, 6, @menuId, '', '', '', 0),
('撤回审批', 'asset:contract:withdraw-approval', 3, 7, @menuId, '', '', '', 0),
('终止合同', 'asset:contract:terminate', 3, 8, @menuId, '', '', '', 0),
('续签合同', 'asset:contract:renew', 3, 9, @menuId, '', '', '', 0);

View File

@@ -0,0 +1,23 @@
-- 客户管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'客户管理', '', 2, 2, 5055,
'customer', 'user', 'asset/customer/index', 0, 'Customer'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 客户管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('客户查询', 'asset:customer:query', 3, 1, @menuId, '', '', '', 0),
('客户创建', 'asset:customer:create', 3, 2, @menuId, '', '', '', 0),
('客户更新', 'asset:customer:update', 3, 3, @menuId, '', '', '', 0),
('客户删除', 'asset:customer:delete', 3, 4, @menuId, '', '', '', 0),
('客户导出', 'asset:customer:export', 3, 5, @menuId, '', '', '', 0);

View File

@@ -0,0 +1,44 @@
-- ==================== 客户信息表重建脚本 ====================
-- 说明:原表列名与 Java DO 不匹配,重建以对齐
-- 日期2026-03-13
-- 注意:如果 asset_customer 已有数据,请先备份!
-- 1. 备份旧表(如果存在)
-- CREATE TABLE asset_customer_bak AS SELECT * FROM asset_customer;
-- 2. 删除旧表
DROP TABLE IF EXISTS asset_customer;
-- 3. 创建新表(与 CustomerDO 字段完全对齐)
CREATE TABLE `asset_customer` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`customer_code` varchar(50) DEFAULT NULL COMMENT '客户编号',
`coop_status` varchar(20) DEFAULT NULL COMMENT '合作状态',
`customer_name` varchar(100) NOT NULL COMMENT '客户名称',
`province` varchar(50) DEFAULT NULL COMMENT '省份',
`city` varchar(50) DEFAULT NULL COMMENT '城市',
`address` varchar(255) DEFAULT NULL COMMENT '地址',
`region` varchar(20) DEFAULT NULL COMMENT '区域',
`contact` varchar(50) DEFAULT NULL COMMENT '联系人',
`contact_mobile` varchar(20) DEFAULT NULL COMMENT '联系人手机',
`contact_phone` varchar(20) DEFAULT NULL COMMENT '联系人座机',
`email` varchar(100) DEFAULT NULL COMMENT '电子邮箱',
`credit_code_or_id` varchar(50) DEFAULT NULL COMMENT '统一社会信用代码/身份证',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`tax_id` varchar(50) DEFAULT NULL COMMENT '纳税人识别号',
`invoice_address` varchar(255) DEFAULT NULL COMMENT '发票地址',
`invoice_phone` varchar(20) DEFAULT NULL COMMENT '发票电话',
`account` varchar(50) DEFAULT NULL COMMENT '银行账号',
`opening_bank` varchar(100) DEFAULT NULL COMMENT '开户行',
`mailing_address` varchar(255) DEFAULT NULL COMMENT '邮寄地址',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除0=未删除 1=已删除)',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_customer_code` (`customer_code`) USING BTREE COMMENT '客户编号查询',
KEY `idx_customer_name` (`customer_name`) USING BTREE COMMENT '客户名称查询',
KEY `idx_tenant_deleted` (`tenant_id`, `deleted`) USING BTREE COMMENT '租户隔离 + 逻辑删除'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='客户信息表';

View File

@@ -0,0 +1,23 @@
-- 停车场管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'停车场管理', '', 2, 1, 5055,
'parking', 'car', 'asset/parking/index', 0, 'Parking'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 停车场管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('停车场查询', 'asset:parking:query', 3, 1, @menuId, '', '', '', 0),
('停车场创建', 'asset:parking:create', 3, 2, @menuId, '', '', '', 0),
('停车场更新', 'asset:parking:update', 3, 3, @menuId, '', '', '', 0),
('停车场删除', 'asset:parking:delete', 3, 4, @menuId, '', '', '', 0),
('停车场导出', 'asset:parking:export', 3, 5, @menuId, '', '', '', 0);

View File

@@ -0,0 +1,23 @@
-- 供应商管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'供应商管理', '', 2, 3, 5055,
'supplier', 'user', 'asset/supplier/index', 0, 'Supplier'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 供应商管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('供应商查询', 'asset:supplier:query', 3, 1, @menuId, '', '', '', 0),
('供应商创建', 'asset:supplier:create', 3, 2, @menuId, '', '', '', 0),
('供应商更新', 'asset:supplier:update', 3, 3, @menuId, '', '', '', 0),
('供应商删除', 'asset:supplier:delete', 3, 4, @menuId, '', '', '', 0),
('供应商导出', 'asset:supplier:export', 3, 5, @menuId, '', '', '', 0);

View File

@@ -0,0 +1,23 @@
-- 车型参数管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'车型参数', '', 2, 4, 5055,
'vehicle-model', 'car', 'asset/vehicle-model/index', 0, 'VehicleModel'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 车型参数管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('车型参数查询', 'asset:vehicle-model:query', 3, 1, @menuId, '', '', '', 0),
('车型参数创建', 'asset:vehicle-model:create', 3, 2, @menuId, '', '', '', 0),
('车型参数更新', 'asset:vehicle-model:update', 3, 3, @menuId, '', '', '', 0),
('车型参数删除', 'asset:vehicle-model:delete', 3, 4, @menuId, '', '', '', 0),
('车型参数导出', 'asset:vehicle-model:export', 3, 5, @menuId, '', '', '', 0);

View File

@@ -0,0 +1,25 @@
-- 车辆上牌管理菜单和权限初始化脚本
-- 1. 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'车辆上牌', '', 2, 5, 5055,
'vehicle-registration', 'file-text', 'asset/vehicle-registration/index', 0, 'VehicleRegistration'
);
-- 获取刚插入的菜单ID
SET @menuId = LAST_INSERT_ID();
-- 车辆上牌管理按钮权限
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES
('车辆上牌查询', 'asset:vehicle-registration:query', 3, 1, @menuId, '', '', '', 0),
('车辆上牌创建', 'asset:vehicle-registration:create', 3, 2, @menuId, '', '', '', 0),
('车辆上牌更新', 'asset:vehicle-registration:update', 3, 3, @menuId, '', '', '', 0),
('车辆上牌删除', 'asset:vehicle-registration:delete', 3, 4, @menuId, '', '', '', 0),
('车辆上牌导出', 'asset:vehicle-registration:export', 3, 5, @menuId, '', '', '', 0),
('车辆上牌确认', 'asset:vehicle-registration:confirm', 3, 6, @menuId, '', '', '', 0),
('车辆上牌作废', 'asset:vehicle-registration:void', 3, 7, @menuId, '', '', '', 0);

View File

@@ -0,0 +1,35 @@
-- =============================================
-- 车辆租赁业务流程表结构增量变更
-- 对应前端新增字段
-- =============================================
-- 1. 备车记录表 - 新增字段
ALTER TABLE `asset_vehicle_prepare`
ADD COLUMN `vehicle_type` VARCHAR(50) COMMENT '车辆类型' AFTER `model`,
ADD COLUMN `parking_lot` VARCHAR(100) COMMENT '停车场' AFTER `vehicle_type`,
ADD COLUMN `preparation_type` VARCHAR(50) COMMENT '整备类型' AFTER `contract_code`,
ADD COLUMN `mileage` INT COMMENT '里程(km)' AFTER `preparation_type`,
ADD COLUMN `hydrogen_remaining` DECIMAL(10,2) COMMENT '剩余氢量' AFTER `mileage`,
ADD COLUMN `hydrogen_unit` VARCHAR(10) DEFAULT '%' COMMENT '氢量单位(%/MPa/kg)' AFTER `hydrogen_remaining`,
ADD COLUMN `battery_remaining` DECIMAL(10,2) COMMENT '剩余电量(%)' AFTER `hydrogen_unit`,
ADD COLUMN `enlarged_text_photo` VARCHAR(1000) COMMENT '放大字照片JSON数组' AFTER `body_ad_photos`,
ADD COLUMN `spare_tire_depth` DECIMAL(10,2) COMMENT '备胎胎纹深度(mm)' AFTER `has_tail_lift`,
ADD COLUMN `spare_tire_photo` VARCHAR(1000) COMMENT '备胎照片JSON数组' AFTER `spare_tire_depth`,
ADD COLUMN `remark` VARCHAR(500) COMMENT '备注' AFTER `check_list`,
ADD COLUMN `complete_time` DATETIME COMMENT '完成时间' AFTER `status`;
-- 2. 交车单表 - 新增司机信息、交检清单、费用信息
ALTER TABLE `asset_delivery_order`
ADD COLUMN `driver_name` VARCHAR(64) COMMENT '司机姓名' AFTER `delivery_photos`,
ADD COLUMN `driver_id_card` VARCHAR(18) COMMENT '司机身份证' AFTER `driver_name`,
ADD COLUMN `driver_phone` VARCHAR(20) COMMENT '司机手机号' AFTER `driver_id_card`,
ADD COLUMN `inspection_data` TEXT COMMENT '交检清单JSON' AFTER `driver_phone`,
ADD COLUMN `cost_list` TEXT COMMENT '费用信息JSON' AFTER `inspection_data`;
-- 3. 交车单车辆表 - 新增电量
ALTER TABLE `asset_delivery_order_vehicle`
ADD COLUMN `battery_level` DECIMAL(10,2) COMMENT '交车时电量(%)' AFTER `hydrogen_level`;
-- 4. 还车车辆表 - 新增违章费用
ALTER TABLE `asset_return_order_vehicle`
ADD COLUMN `violation_fee` DECIMAL(10,2) DEFAULT 0 COMMENT '违章费用' AFTER `unpaid_repair_fee`;

View File

@@ -0,0 +1,222 @@
-- =============================================
-- 车辆租赁业务流程表结构
-- 包含:备车、交车任务、交车单、还车单
-- =============================================
-- 1. 备车记录表
CREATE TABLE IF NOT EXISTS `asset_vehicle_prepare` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`vehicle_id` BIGINT NOT NULL COMMENT '车辆ID',
`plate_no` VARCHAR(20) COMMENT '车牌号',
`vin` VARCHAR(50) NOT NULL COMMENT '车辆识别代码',
`vehicle_model_id` BIGINT NOT NULL COMMENT '车型ID',
`brand` VARCHAR(100) COMMENT '品牌',
`model` VARCHAR(100) COMMENT '型号',
`contract_id` BIGINT COMMENT '关联合同ID',
`contract_code` VARCHAR(50) COMMENT '合同编码',
`has_body_ad` BIT(1) DEFAULT b'0' COMMENT '是否有车身广告',
`body_ad_photos` VARCHAR(1000) COMMENT '广告照片JSON数组',
`has_tail_lift` BIT(1) DEFAULT b'0' COMMENT '是否有尾板',
`trailer_plate_no` VARCHAR(20) COMMENT '挂车牌号',
`defect_photos` VARCHAR(1000) COMMENT '瑕疵照片JSON数组',
`check_list` TEXT COMMENT '备车检查清单JSON',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态0=待提交 1=已完成)',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_vehicle_id` (`vehicle_id`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_status` (`status`),
INDEX `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='备车记录表';
-- 2. 交车任务表
CREATE TABLE IF NOT EXISTS `asset_delivery_task` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`task_code` VARCHAR(50) NOT NULL COMMENT '交车任务编码',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`contract_code` VARCHAR(50) NOT NULL COMMENT '合同编码',
`project_name` VARCHAR(200) NOT NULL COMMENT '项目名称',
`customer_id` BIGINT NOT NULL COMMENT '客户ID',
`customer_name` VARCHAR(200) NOT NULL COMMENT '客户名称',
`expected_delivery_date_start` DATE COMMENT '预计交车开始日期',
`expected_delivery_date_end` DATE COMMENT '预计交车结束日期',
`billing_start_date` DATE NOT NULL COMMENT '开始计费日期',
`delivery_province` VARCHAR(50) COMMENT '交车省份',
`delivery_city` VARCHAR(50) COMMENT '交车城市',
`delivery_location` VARCHAR(255) COMMENT '交车地点',
`vehicle_count` INT NOT NULL DEFAULT 0 COMMENT '交车数量',
`task_status` TINYINT NOT NULL DEFAULT 0 COMMENT '任务状态0=激活 1=挂起)',
`delivery_status` TINYINT NOT NULL DEFAULT 0 COMMENT '交车状态0=未交车 1=已交车)',
`need_return` BIT(1) NOT NULL DEFAULT b'1' COMMENT '是否需要还车',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_task_code` (`task_code`, `deleted`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_customer_id` (`customer_id`),
INDEX `idx_task_status` (`task_status`),
INDEX `idx_delivery_status` (`delivery_status`),
INDEX `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='交车任务表';
-- 3. 交车任务车辆表
CREATE TABLE IF NOT EXISTS `asset_delivery_task_vehicle` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`task_id` BIGINT NOT NULL COMMENT '交车任务ID',
`contract_vehicle_id` BIGINT NOT NULL COMMENT '合同车辆ID',
`vehicle_id` BIGINT NOT NULL COMMENT '车辆ID',
`plate_no` VARCHAR(20) COMMENT '车牌号',
`vin` VARCHAR(50) NOT NULL COMMENT '车辆识别代码',
`brand` VARCHAR(100) NOT NULL COMMENT '品牌',
`model` VARCHAR(100) NOT NULL COMMENT '型号',
`month_rent` DECIMAL(10,2) NOT NULL COMMENT '月租金',
`deposit` DECIMAL(10,2) NOT NULL COMMENT '保证金',
`actual_delivery_date` DATETIME COMMENT '实际交车日期',
`delivery_person` VARCHAR(64) COMMENT '交车人',
`is_delivered` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否已交车',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_task_id` (`task_id`),
INDEX `idx_vehicle_id` (`vehicle_id`),
INDEX `idx_contract_vehicle_id` (`contract_vehicle_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='交车任务车辆表';
-- 4. 交车单表
CREATE TABLE IF NOT EXISTS `asset_delivery_order` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_code` VARCHAR(50) NOT NULL COMMENT '交车单编码',
`task_id` BIGINT NOT NULL COMMENT '交车任务ID',
`task_code` VARCHAR(50) NOT NULL COMMENT '交车任务编码',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`contract_code` VARCHAR(50) NOT NULL COMMENT '合同编码',
`project_name` VARCHAR(200) NOT NULL COMMENT '项目名称',
`customer_id` BIGINT NOT NULL COMMENT '客户ID',
`customer_name` VARCHAR(200) NOT NULL COMMENT '客户名称',
`delivery_date` DATETIME NOT NULL COMMENT '交车日期',
`delivery_person` VARCHAR(64) NOT NULL COMMENT '交车人',
`delivery_location` VARCHAR(255) COMMENT '交车地点',
`authorized_person_id` BIGINT COMMENT '被授权人ID',
`authorized_person_name` VARCHAR(100) COMMENT '被授权人姓名',
`authorized_person_phone` VARCHAR(20) COMMENT '被授权人电话',
`authorized_person_id_card` VARCHAR(18) COMMENT '被授权人身份证',
`esign_flow_id` VARCHAR(100) COMMENT 'E签宝流程ID',
`esign_status` TINYINT DEFAULT 0 COMMENT 'E签宝状态0=未签 1=已签)',
`delivery_photos` VARCHAR(1000) COMMENT '交车照片JSON数组',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态0=待完成 1=已完成)',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_code` (`order_code`, `deleted`),
INDEX `idx_task_id` (`task_id`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_status` (`status`),
INDEX `idx_delivery_date` (`delivery_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='交车单表';
-- 5. 交车单车辆表
CREATE TABLE IF NOT EXISTS `asset_delivery_order_vehicle` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_id` BIGINT NOT NULL COMMENT '交车单ID',
`task_vehicle_id` BIGINT NOT NULL COMMENT '交车任务车辆ID',
`vehicle_id` BIGINT NOT NULL COMMENT '车辆ID',
`plate_no` VARCHAR(20) COMMENT '车牌号',
`vin` VARCHAR(50) NOT NULL COMMENT '车辆识别代码',
`brand` VARCHAR(100) NOT NULL COMMENT '品牌',
`model` VARCHAR(100) NOT NULL COMMENT '型号',
`mileage` INT COMMENT '交车时里程',
`hydrogen_level` DECIMAL(10,2) COMMENT '交车时氢气量kg',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_order_id` (`order_id`),
INDEX `idx_vehicle_id` (`vehicle_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='交车单车辆表';
-- 6. 还车单表
CREATE TABLE IF NOT EXISTS `asset_return_order` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_code` VARCHAR(50) NOT NULL COMMENT '还车单编码',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`contract_code` VARCHAR(50) NOT NULL COMMENT '合同编码',
`project_name` VARCHAR(200) NOT NULL COMMENT '项目名称',
`customer_id` BIGINT NOT NULL COMMENT '客户ID',
`customer_name` VARCHAR(200) NOT NULL COMMENT '客户名称',
`return_date` DATETIME NOT NULL COMMENT '还车日期',
`return_person` VARCHAR(64) NOT NULL COMMENT '还车验收人',
`return_location` VARCHAR(255) COMMENT '还车地点',
`return_reason` VARCHAR(50) COMMENT '还车原因',
`return_reason_desc` VARCHAR(500) COMMENT '还车原因说明',
`total_refund_amount` DECIMAL(10,2) DEFAULT 0 COMMENT '退还总金额',
`deposit_refund` DECIMAL(10,2) DEFAULT 0 COMMENT '退还保证金',
`hydrogen_refund` DECIMAL(10,2) DEFAULT 0 COMMENT '氢气退款',
`other_charges` DECIMAL(10,2) DEFAULT 0 COMMENT '其他费用',
`return_photos` VARCHAR(1000) COMMENT '还车照片JSON数组',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态0=待验车 1=验车完成 2=已结算)',
`approval_status` TINYINT NOT NULL DEFAULT 0 COMMENT '审批状态0=草稿 1=审批中 2=审批通过 3=审批拒绝)',
`bpm_instance_id` VARCHAR(64) COMMENT 'BPM流程实例ID',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_code` (`order_code`, `deleted`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_status` (`status`),
INDEX `idx_approval_status` (`approval_status`),
INDEX `idx_return_date` (`return_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='还车单表';
-- 7. 还车车辆表
CREATE TABLE IF NOT EXISTS `asset_return_order_vehicle` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`return_order_id` BIGINT NOT NULL COMMENT '还车单ID',
`vehicle_id` BIGINT NOT NULL COMMENT '车辆ID',
`plate_no` VARCHAR(20) COMMENT '车牌号',
`vin` VARCHAR(50) NOT NULL COMMENT '车辆识别代码',
`brand` VARCHAR(100) NOT NULL COMMENT '品牌',
`model` VARCHAR(100) NOT NULL COMMENT '型号',
`return_mileage` INT COMMENT '还车时里程',
`return_hydrogen_level` DECIMAL(10,2) COMMENT '还车时氢气量kg',
`delivery_hydrogen_level` DECIMAL(10,2) COMMENT '交车时氢气量kg',
`hydrogen_diff` DECIMAL(10,2) COMMENT '氢气差值kg',
`hydrogen_unit_price` DECIMAL(10,2) COMMENT '氢气单价(元/kg',
`hydrogen_refund_amount` DECIMAL(10,2) COMMENT '氢气退款金额',
`check_list` TEXT COMMENT '还车检查清单JSON',
`defect_photos` VARCHAR(1000) COMMENT '瑕疵照片JSON数组',
`vehicle_damage_fee` DECIMAL(10,2) DEFAULT 0 COMMENT '车损费',
`tool_damage_fee` DECIMAL(10,2) DEFAULT 0 COMMENT '工具损坏费',
`unpaid_maintenance_fee` DECIMAL(10,2) DEFAULT 0 COMMENT '未结算保养费',
`unpaid_repair_fee` DECIMAL(10,2) DEFAULT 0 COMMENT '未结算维修费',
`other_fee` DECIMAL(10,2) DEFAULT 0 COMMENT '其他费用',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_return_order_id` (`return_order_id`),
INDEX `idx_vehicle_id` (`vehicle_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='还车车辆表';

View File

@@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.asset.enums.contract;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 合同审批状态枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum ContractApprovalStatusEnum {
DRAFT(0, "草稿"),
APPROVING(1, "审批中"),
APPROVED(2, "审批通过"),
REJECTED(3, "审批拒绝"),
WITHDRAWN(4, "已撤回");
/**
* 状态
*/
private final Integer status;
/**
* 名称
*/
private final String name;
public static ContractApprovalStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.asset.enums.contract;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 合同状态枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum ContractStatusEnum {
DRAFT(0, "草稿"),
PENDING(1, "待生效"),
IN_PROGRESS(2, "进行中"),
EXPIRED(3, "已到期"),
TERMINATED(4, "已终止"),
RENEWED(5, "已续签");
/**
* 状态
*/
private final Integer status;
/**
* 名称
*/
private final String name;
public static ContractStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.asset.enums.contract;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 合同类型枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum ContractTypeEnum {
TRIAL(1, "试用合同"),
FORMAL(2, "正式合同");
/**
* 类型
*/
private final Integer type;
/**
* 名称
*/
private final String name;
public static ContractTypeEnum valueOf(Integer type) {
return Arrays.stream(values())
.filter(item -> item.getType().equals(type))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.asset.enums.delivery;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 交车单状态枚举
*/
@Getter
@AllArgsConstructor
public enum DeliveryOrderStatusEnum {
PENDING(0, "待完成"),
COMPLETED(1, "已完成");
private final Integer status;
private final String name;
public static DeliveryOrderStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.asset.enums.delivery;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 交车状态枚举
*/
@Getter
@AllArgsConstructor
public enum DeliveryStatusEnum {
NOT_DELIVERED(0, "未交车"),
DELIVERED(1, "已交车");
private final Integer status;
private final String name;
public static DeliveryStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.asset.enums.delivery;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 交车任务状态枚举
*/
@Getter
@AllArgsConstructor
public enum DeliveryTaskStatusEnum {
ACTIVE(0, "激活"),
SUSPENDED(1, "挂起");
private final Integer status;
private final String name;
public static DeliveryTaskStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.asset.enums.prepare;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 备车状态枚举
*/
@Getter
@AllArgsConstructor
public enum VehiclePrepareStatusEnum {
DRAFT(0, "待提交"),
COMPLETED(1, "已完成");
private final Integer status;
private final String name;
public static VehiclePrepareStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.asset.enums.returnorder;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 还车单状态枚举
*/
@Getter
@AllArgsConstructor
public enum ReturnOrderStatusEnum {
PENDING_INSPECTION(0, "待验车"),
INSPECTION_COMPLETED(1, "验车完成"),
SETTLED(2, "已结算");
private final Integer status;
private final String name;
public static ReturnOrderStatusEnum valueOf(Integer status) {
return Arrays.stream(values())
.filter(item -> item.getStatus().equals(status))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.asset.enums.returnorder;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 还车原因枚举
*/
@Getter
@AllArgsConstructor
public enum ReturnReasonEnum {
CONTRACT_EXPIRED("CONTRACT_EXPIRED", "合同到期"),
CUSTOMER_REQUEST("CUSTOMER_REQUEST", "客户申请"),
CONTRACT_TERMINATED("CONTRACT_TERMINATED", "合同终止");
private final String code;
private final String name;
public static ReturnReasonEnum valueOfCode(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
}

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.asset;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 资产管理模块 Application
@@ -9,6 +10,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* @author 芋道源码
*/
@SpringBootApplication
@EnableFeignClients(basePackages = {
"cn.iocoder.yudao.module.system.api", // System 模块 API
"cn.iocoder.yudao.module.ocr.api", // OCR 模块 API
"cn.iocoder.yudao.module.infra.api", // Infra 模块 API
"cn.iocoder.yudao.module.bpm.api" // BPM 模块 API
})
public class AssetServerApplication {
public static void main(String[] args) {

View File

@@ -0,0 +1,212 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.asset.controller.admin.contract.vo.*;
import cn.iocoder.yudao.module.asset.convert.contract.ContractConvert;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.*;
import cn.iocoder.yudao.module.asset.dal.mysql.contract.*;
import cn.iocoder.yudao.module.asset.service.contract.ContractService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* 车辆租赁合同 Controller
*
* @author 芋道源码
*/
@Tag(name = "管理后台 - 车辆租赁合同管理")
@RestController
@RequestMapping("/asset/contract")
@Validated
public class ContractController {
@Resource
private ContractService contractService;
@Resource
private ContractVehicleMapper contractVehicleMapper;
@Resource
private ContractVehicleServiceMapper contractVehicleServiceMapper;
@Resource
private ContractAuthorizedMapper contractAuthorizedMapper;
@Resource
private ContractChangeHistoryMapper contractChangeHistoryMapper;
@PostMapping("/create")
@Operation(summary = "创建合同")
@PreAuthorize("@ss.hasPermission('asset:contract:create')")
public CommonResult<Long> createContract(@Valid @RequestBody ContractSaveReqVO createReqVO) {
return success(contractService.createContract(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新合同")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Boolean> updateContract(@Valid @RequestBody ContractSaveReqVO updateReqVO) {
contractService.updateContract(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除合同")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:contract:delete')")
public CommonResult<Boolean> deleteContract(@RequestParam("id") Long id) {
contractService.deleteContract(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除合同")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('asset:contract:delete')")
public CommonResult<Boolean> deleteContractList(@RequestParam("ids") List<Long> ids) {
for (Long id : ids) {
contractService.deleteContract(id);
}
return success(true);
}
@GetMapping("/export-excel")
@Operation(summary = "导出合同 Excel")
@PreAuthorize("@ss.hasPermission('asset:contract:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportContractExcel(HttpServletResponse response, @Valid ContractPageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ContractDO> list = contractService.getContractPage(exportReqVO).getList();
// 输出
ExcelUtils.write(response, "车辆租赁合同.xls", "合同数据", ContractExcelVO.class,
BeanUtils.toBean(list, ContractExcelVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得合同详情")
@Parameter(name = "id", description = "编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('asset:contract:query')")
public CommonResult<ContractDetailRespVO> getContract(@RequestParam("id") Long id) {
return success(contractService.getContractDetail(id));
}
@GetMapping("/page")
@Operation(summary = "获得合同分页")
@PreAuthorize("@ss.hasPermission('asset:contract:query')")
public CommonResult<PageResult<ContractRespVO>> getContractPage(@Valid ContractPageReqVO pageReqVO) {
PageResult<ContractDO> pageResult = contractService.getContractPage(pageReqVO);
PageResult<ContractRespVO> voPage = ContractConvert.INSTANCE.convertPage(pageResult);
// 填充车辆数和已交车辆数
for (ContractRespVO vo : voPage.getList()) {
List<ContractVehicleDO> vehicles = contractVehicleMapper.selectListByContractId(vo.getId());
vo.setVehicleCount(vehicles.size());
vo.setDeliveredCount((int) vehicles.stream()
.filter(v -> Integer.valueOf(1).equals(v.getVehicleStatus()))
.count());
}
return success(voPage);
}
@GetMapping("/change-history")
@Operation(summary = "获得合同变更历史")
@Parameter(name = "contractId", description = "合同ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('asset:contract:query')")
public CommonResult<List<ContractChangeHistoryDO>> getChangeHistory(@RequestParam("contractId") Long contractId) {
return success(contractChangeHistoryMapper.selectListByContractId(contractId));
}
@PostMapping("/submit-approval")
@Operation(summary = "提交合同审批")
@Parameter(name = "id", description = "合同ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<String> submitApproval(@RequestParam("id") Long id) {
return success(contractService.submitContractApproval(id));
}
@PostMapping("/withdraw-approval")
@Operation(summary = "撤回合同审批")
@Parameter(name = "id", description = "合同ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Boolean> withdrawApproval(@RequestParam("id") Long id) {
contractService.withdrawContractApproval(id);
return success(true);
}
@PostMapping("/terminate")
@Operation(summary = "终止合同")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Boolean> terminateContract(@RequestParam("id") Long id,
@RequestParam("reason") String reason) {
contractService.terminateContract(id, reason);
return success(true);
}
@GetMapping("/simple-list")
@Operation(summary = "获得合同精简列表", description = "用于下拉选择")
public CommonResult<List<ContractSimpleRespVO>> getContractSimpleList() {
List<ContractDO> list = contractService.getContractSimpleList();
return success(BeanUtils.toBean(list, ContractSimpleRespVO.class));
}
@PostMapping("/renew")
@Operation(summary = "续签合同")
@PreAuthorize("@ss.hasPermission('asset:contract:create')")
public CommonResult<Long> renewContract(@RequestParam("id") Long id,
@Valid @RequestBody ContractSaveReqVO newContractReqVO) {
return success(contractService.renewContract(id, newContractReqVO));
}
@PostMapping("/convert-to-third-party")
@Operation(summary = "变更为三方合同")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Long> convertToThirdParty(@RequestParam("id") Long id,
@Valid @RequestBody ContractSaveReqVO newContractReqVO) {
return success(contractService.convertToThirdParty(id, newContractReqVO));
}
@PostMapping("/convert-to-formal")
@Operation(summary = "试用合同转正式")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Long> convertToFormal(@RequestParam("id") Long id,
@Valid @RequestBody ContractSaveReqVO newContractReqVO) {
return success(contractService.convertToFormal(id, newContractReqVO));
}
@PostMapping("/add-vehicle")
@Operation(summary = "往现有合同追加车辆")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Boolean> addVehicle(@RequestParam("id") Long id,
@Valid @RequestBody List<ContractSaveReqVO.ContractVehicleSaveVO> vehicles) {
contractService.addVehiclesToContract(id, vehicles);
return success(true);
}
@PostMapping("/upload-seal")
@Operation(summary = "上传盖章合同附件")
@PreAuthorize("@ss.hasPermission('asset:contract:update')")
public CommonResult<Boolean> uploadSeal(@RequestParam("id") Long id,
@RequestParam("fileUrl") String fileUrl,
@RequestParam("fileName") String fileName) {
contractService.uploadSealedContract(id, fileUrl, fileName);
return success(true);
}
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 合同附件 VO
*
* @author 芋道源码
*/
@Data
public class ContractAttachmentVO {
@Schema(description = "主键ID", example = "1")
private Long id;
@Schema(description = "附件类型1=合同原件 2=盖章合同)", example = "1")
private Integer attachmentType;
@Schema(description = "文件名称", example = "合同扫描件.pdf")
private String fileName;
@Schema(description = "文件URL", example = "https://xxx.com/contract.pdf")
private String fileUrl;
@Schema(description = "文件大小(字节)", example = "1024000")
private Long fileSize;
@Schema(description = "上传时间", example = "2026-01-01 00:00:00")
private LocalDateTime uploadTime;
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 合同被授权人 VO
*
* @author 芋道源码
*/
@Data
public class ContractAuthorizedVO {
@Schema(description = "主键ID", example = "1")
private Long id;
@Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
private String name;
@Schema(description = "电话", requiredMode = Schema.RequiredMode.REQUIRED, example = "13800138000")
private String phone;
@Schema(description = "身份证号", requiredMode = Schema.RequiredMode.REQUIRED, example = "310101199001011234")
private String idCard;
}

View File

@@ -0,0 +1,101 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 车辆租赁合同 Base VO
*
* @author 芋道源码
*/
@Data
public class ContractBaseVO {
@Schema(description = "合同编码(新增时自动生成)", example = "HT-2026-001")
private String contractCode;
@Schema(description = "合同类型1=试用 2=正式)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "合同类型不能为空")
private Integer contractType;
@Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张江高科技园区车辆租赁项目")
@NotBlank(message = "项目名称不能为空")
private String projectName;
@Schema(description = "生效日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-01-01")
@NotNull(message = "生效日期不能为空")
private LocalDate startDate;
@Schema(description = "结束日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-12-31")
@NotNull(message = "结束日期不能为空")
private LocalDate endDate;
@Schema(description = "付款方式", example = "月付")
private String paymentMethod;
@Schema(description = "付款周期", example = "每月1日")
private String paymentCycle;
@Schema(description = "签约公司(乙方)", example = "上海某某汽车租赁有限公司")
private String signingCompany;
@Schema(description = "交车省份", example = "上海市")
private String deliveryProvince;
@Schema(description = "交车城市", example = "浦东新区")
private String deliveryCity;
@Schema(description = "交车地点", example = "张江高科技园区")
private String deliveryLocation;
@Schema(description = "备注", example = "特殊要求说明")
private String remark;
@Schema(description = "客户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "客户ID不能为空")
private Long customerId;
@Schema(description = "客户名称由后端根据客户ID自动填充", example = "上海某某科技有限公司")
private String customerName;
@Schema(description = "是否三方合同", example = "false")
private Boolean thirdPartyEnabled;
@Schema(description = "丙方客户ID", example = "2")
private Long thirdPartyCustomerId;
@Schema(description = "丙方名称", example = "北京某某公司")
private String thirdPartyName;
@Schema(description = "业务部门ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "业务部门ID不能为空")
private Long businessDeptId;
@Schema(description = "业务负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "业务负责人ID不能为空")
private Long businessManagerId;
@Schema(description = "氢费承担方", example = "客户")
private String hydrogenBearer;
@Schema(description = "氢气付款方式", example = "预付")
private String hydrogenPaymentMethod;
@Schema(description = "氢气预付款", example = "5000.00")
private BigDecimal hydrogenPrepay;
@Schema(description = "退还车氢气单价", example = "35.00")
private BigDecimal hydrogenReturnPrice;
@Schema(description = "账单计算方式", example = "按自然月结算")
private String billingMethod;
@Schema(description = "主车型", example = "氢能重卡")
private String mainVehicleType;
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
/**
* 车辆租赁合同详情 Response VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 车辆租赁合同详情 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ContractDetailRespVO extends ContractRespVO {
@Schema(description = "车辆订单列表")
private List<ContractVehicleDetailVO> vehicles;
@Schema(description = "被授权人列表")
private List<ContractAuthorizedVO> authorizedPersons;
@Schema(description = "附件列表")
private List<ContractAttachmentVO> attachments;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public static class ContractVehicleDetailVO extends ContractVehicleVO {
@Schema(description = "服务项目列表")
private List<ContractVehicleServiceVO> services;
}
}

View File

@@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 车辆租赁合同 Excel 导出 VO
*
* @author 芋道源码
*/
@Data
@ExcelIgnoreUnannotated
public class ContractExcelVO {
@ExcelProperty("合同编码")
private String contractCode;
@ExcelProperty("合同类型")
private Integer contractType;
@ExcelProperty("项目名称")
private String projectName;
@ExcelProperty("客户名称")
private String customerName;
@ExcelProperty("签约公司")
private String signingCompany;
@ExcelProperty("生效日期")
private LocalDate startDate;
@ExcelProperty("结束日期")
private LocalDate endDate;
@ExcelProperty("付款方式")
private String paymentMethod;
@ExcelProperty("付款周期")
private String paymentCycle;
@ExcelProperty("交车省份")
private String deliveryProvince;
@ExcelProperty("交车城市")
private String deliveryCity;
@ExcelProperty("交车地点")
private String deliveryLocation;
@ExcelProperty("主车型")
private String mainVehicleType;
@ExcelProperty("审批状态")
private Integer approvalStatus;
@ExcelProperty("合同状态")
private Integer contractStatus;
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@ExcelProperty("备注")
private String remark;
}

View File

@@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
/**
* 车辆租赁合同分页查询 Request VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 车辆租赁合同分页查询 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ContractPageReqVO extends PageParam {
@Schema(description = "合同编码", example = "HT-2026-001")
private String contractCode;
@Schema(description = "合同类型1=试用 2=正式)", example = "1")
private Integer contractType;
@Schema(description = "项目名称(模糊搜索)", example = "张江高科技园区")
private String projectName;
@Schema(description = "客户ID", example = "1")
private Long customerId;
@Schema(description = "客户名称(模糊搜索)", example = "上海某某科技")
private String customerName;
@Schema(description = "审批状态0=草稿 1=审批中 2=审批通过 3=审批拒绝 4=已撤回)", example = "0")
private Integer approvalStatus;
@Schema(description = "合同状态0=草稿 1=待生效 2=进行中 3=已到期 4=已终止 5=已续签)", example = "0")
private Integer contractStatus;
@Schema(description = "生效日期", example = "[2026-01-01, 2026-12-31]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] startDate;
@Schema(description = "结束日期", example = "[2026-01-01, 2026-12-31]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] endDate;
@Schema(description = "业务部门ID", example = "1")
private Long businessDeptId;
@Schema(description = "签约公司", example = "嘉兴羚牛")
private String signingCompany;
@Schema(description = "业务负责人ID", example = "1")
private Long businessManagerId;
@Schema(description = "创建人", example = "admin")
private String creator;
}

View File

@@ -0,0 +1,60 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
/**
* 车辆租赁合同 Response VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 车辆租赁合同 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ContractRespVO extends ContractBaseVO {
@Schema(description = "主键ID", example = "1")
private Long id;
@Schema(description = "审批状态0=草稿 1=审批中 2=审批通过 3=审批拒绝 4=已撤回)", example = "0")
private Integer approvalStatus;
@Schema(description = "BPM流程实例ID", example = "123456")
private String bpmInstanceId;
@Schema(description = "合同状态0=草稿 1=待生效 2=进行中 3=已到期 4=已终止 5=已续签)", example = "0")
private Integer contractStatus;
@Schema(description = "实际生效时间", example = "2026-01-01 00:00:00")
private LocalDateTime effectiveTime;
@Schema(description = "终止时间", example = "2026-12-31 23:59:59")
private LocalDateTime terminateTime;
@Schema(description = "终止原因", example = "客户要求终止")
private String terminateReason;
@Schema(description = "续签后的新合同ID", example = "2")
private Long renewedContractId;
@Schema(description = "原合同ID如果是续签合同", example = "1")
private Long originalContractId;
@Schema(description = "创建时间", example = "2026-01-01 00:00:00")
private LocalDateTime createTime;
@Schema(description = "创建者", example = "admin")
private String creator;
@Schema(description = "租赁车辆数", example = "5")
private Integer vehicleCount;
@Schema(description = "已交车辆数", example = "3")
private Integer deliveredCount;
}

View File

@@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**
* 车辆租赁合同创建/更新 Request VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 车辆租赁合同创建/更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ContractSaveReqVO extends ContractBaseVO {
@Schema(description = "主键ID", example = "1")
private Long id;
@Schema(description = "车辆订单列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "车辆订单列表不能为空")
@Valid
private List<ContractVehicleSaveVO> vehicles;
@Schema(description = "被授权人列表")
@Valid
private List<ContractAuthorizedVO> authorizedPersons;
@Data
public static class ContractVehicleSaveVO extends ContractVehicleVO {
@Schema(description = "服务项目列表")
@Valid
private List<ContractVehicleServiceVO> services;
}
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 合同精简 Response VO")
@Data
public class ContractSimpleRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "合同编码", example = "HT-2026-0001")
private String contractCode;
@Schema(description = "项目名称", example = "XX物流项目")
private String projectName;
@Schema(description = "客户名称", example = "XX公司")
private String customerName;
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 合同车辆服务项目 VO
*
* @author 芋道源码
*/
@Data
public class ContractVehicleServiceVO {
@Schema(description = "主键ID", example = "1")
private Long id;
@Schema(description = "服务项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "保险")
private String serviceName;
@Schema(description = "服务费用(元)", requiredMode = Schema.RequiredMode.REQUIRED, example = "3000.00")
private BigDecimal serviceFee;
@Schema(description = "生效日期", example = "2026-01-01")
private LocalDate effectiveDate;
}

View File

@@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.asset.controller.admin.contract.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 合同车辆 VO
*
* @author 芋道源码
*/
@Data
public class ContractVehicleVO {
@Schema(description = "主键ID", example = "1")
private Long id;
@Schema(description = "车辆ID", example = "1")
private Long vehicleId;
@Schema(description = "品牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "丰田")
private String brand;
@Schema(description = "型号", requiredMode = Schema.RequiredMode.REQUIRED, example = "凯美瑞")
private String model;
@Schema(description = "车牌号", example = "沪A12345")
private String plateNo;
@Schema(description = "VIN码", example = "LVSHCAMB1CE012345")
private String vin;
@Schema(description = "月租金(元)", requiredMode = Schema.RequiredMode.REQUIRED, example = "5000.00")
private BigDecimal monthRent;
@Schema(description = "保证金(元)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000.00")
private BigDecimal deposit;
@Schema(description = "车辆状态0=待交车 1=已交车 2=已退车)", example = "0")
private Integer vehicleStatus;
@Schema(description = "备注", example = "特殊要求")
private String remark;
}

View File

@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -75,4 +76,11 @@ public class CustomerController {
return success(CustomerConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/simple-list")
@Operation(summary = "获得客户精简列表", description = "用于下拉选择")
public CommonResult<List<CustomerRespVO>> getCustomerSimpleList() {
List<CustomerDO> list = customerService.getCustomerSimpleList();
return success(CustomerConvert.INSTANCE.convertList(list));
}
}

View File

@@ -0,0 +1,79 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderDO;
import cn.iocoder.yudao.module.asset.service.delivery.DeliveryOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 交车单")
@RestController
@RequestMapping("/asset/delivery-order")
@Validated
public class DeliveryOrderController {
@Resource
private DeliveryOrderService deliveryOrderService;
@PostMapping("/create")
@Operation(summary = "创建交车单")
@PreAuthorize("@ss.hasPermission('asset:delivery-order:create')")
public CommonResult<Long> createDeliveryOrder(@Valid @RequestBody DeliveryOrderSaveReqVO createReqVO) {
return success(deliveryOrderService.createDeliveryOrder(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新交车单")
@PreAuthorize("@ss.hasPermission('asset:delivery-order:update')")
public CommonResult<Boolean> updateDeliveryOrder(@Valid @RequestBody DeliveryOrderSaveReqVO updateReqVO) {
deliveryOrderService.updateDeliveryOrder(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除交车单")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:delivery-order:delete')")
public CommonResult<Boolean> deleteDeliveryOrder(@RequestParam("id") Long id) {
deliveryOrderService.deleteDeliveryOrder(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得交车单详情")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:delivery-order:query')")
public CommonResult<DeliveryOrderRespVO> getDeliveryOrder(@RequestParam("id") Long id) {
return success(deliveryOrderService.getDeliveryOrderDetail(id));
}
@GetMapping("/page")
@Operation(summary = "获得交车单分页")
@PreAuthorize("@ss.hasPermission('asset:delivery-order:query')")
public CommonResult<PageResult<DeliveryOrderRespVO>> getDeliveryOrderPage(@Valid DeliveryOrderPageReqVO pageReqVO) {
PageResult<DeliveryOrderDO> pageResult = deliveryOrderService.getDeliveryOrderPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DeliveryOrderRespVO.class));
}
@PutMapping("/complete")
@Operation(summary = "完成交车")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:delivery-order:update')")
public CommonResult<Boolean> completeDeliveryOrder(@RequestParam("id") Long id) {
deliveryOrderService.completeDeliveryOrder(id);
return success(true);
}
}

View File

@@ -0,0 +1,102 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryTaskDO;
import cn.iocoder.yudao.module.asset.service.delivery.DeliveryTaskService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 交车任务")
@RestController
@RequestMapping("/asset/delivery-task")
@Validated
public class DeliveryTaskController {
@Resource
private DeliveryTaskService deliveryTaskService;
@PostMapping("/create")
@Operation(summary = "创建交车任务")
@PreAuthorize("@ss.hasPermission('asset:delivery-task:create')")
public CommonResult<Long> createDeliveryTask(@Valid @RequestBody DeliveryTaskSaveReqVO createReqVO) {
return success(deliveryTaskService.createDeliveryTask(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新交车任务")
@PreAuthorize("@ss.hasPermission('asset:delivery-task:update')")
public CommonResult<Boolean> updateDeliveryTask(@Valid @RequestBody DeliveryTaskSaveReqVO updateReqVO) {
deliveryTaskService.updateDeliveryTask(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除交车任务")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:delivery-task:delete')")
public CommonResult<Boolean> deleteDeliveryTask(@RequestParam("id") Long id) {
deliveryTaskService.deleteDeliveryTask(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得交车任务详情")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:delivery-task:query')")
public CommonResult<DeliveryTaskRespVO> getDeliveryTask(@RequestParam("id") Long id) {
return success(deliveryTaskService.getDeliveryTaskDetail(id));
}
@GetMapping("/page")
@Operation(summary = "获得交车任务分页")
@PreAuthorize("@ss.hasPermission('asset:delivery-task:query')")
public CommonResult<PageResult<DeliveryTaskRespVO>> getDeliveryTaskPage(@Valid DeliveryTaskPageReqVO pageReqVO) {
PageResult<DeliveryTaskDO> pageResult = deliveryTaskService.getDeliveryTaskPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DeliveryTaskRespVO.class));
}
@GetMapping("/contract-page")
@Operation(summary = "获得交车任务按合同分组分页")
@PreAuthorize("@ss.hasPermission('asset:delivery-task:query')")
public CommonResult<PageResult<DeliveryTaskContractGroupRespVO>> getDeliveryTaskContractPage(
@Valid DeliveryTaskPageReqVO pageReqVO) {
return success(deliveryTaskService.getDeliveryTaskContractPage(pageReqVO));
}
@GetMapping("/simple-list")
@Operation(summary = "获得交车任务精简列表", description = "用于下拉选择")
public CommonResult<java.util.List<DeliveryTaskSimpleRespVO>> getDeliveryTaskSimpleList() {
java.util.List<DeliveryTaskDO> list = deliveryTaskService.getDeliveryTaskSimpleList();
return success(BeanUtils.toBean(list, DeliveryTaskSimpleRespVO.class));
}
@PutMapping("/suspend")
@Operation(summary = "挂起交车任务")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:delivery-task:update')")
public CommonResult<Boolean> suspendDeliveryTask(@RequestParam("id") Long id) {
deliveryTaskService.suspendDeliveryTask(id);
return success(true);
}
@PutMapping("/activate")
@Operation(summary = "激活交车任务")
@PreAuthorize("@ss.hasPermission('asset:delivery-task:update')")
public CommonResult<Boolean> activateDeliveryTask(@Valid @RequestBody DeliveryTaskActivateReqVO reqVO) {
deliveryTaskService.activateDeliveryTask(reqVO);
return success(true);
}
}

View File

@@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 交车单分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DeliveryOrderPageReqVO extends PageParam {
@Schema(description = "交车单编码")
private String orderCode;
@Schema(description = "任务编码")
private String taskCode;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "交车人")
private String deliveryPerson;
@Schema(description = "交车地区")
private String deliveryRegion;
@Schema(description = "状态")
private Integer status;
@Schema(description = "交车日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] deliveryDate;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,65 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 交车单创建/更新 Request VO")
@Data
public class DeliveryOrderSaveReqVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "交车任务ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "交车任务ID不能为空")
private Long taskId;
@Schema(description = "交车日期", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "交车日期不能为空")
private LocalDateTime deliveryDate;
@Schema(description = "交车人", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "交车人不能为空")
private String deliveryPerson;
@Schema(description = "交车地点")
private String deliveryLocation;
@Schema(description = "被授权人ID")
private Long authorizedPersonId;
@Schema(description = "被授权人姓名")
private String authorizedPersonName;
@Schema(description = "被授权人电话")
private String authorizedPersonPhone;
@Schema(description = "被授权人身份证")
private String authorizedPersonIdCard;
@Schema(description = "交车照片")
private String deliveryPhotos;
@Schema(description = "司机姓名")
private String driverName;
@Schema(description = "司机身份证")
private String driverIdCard;
@Schema(description = "司机手机号")
private String driverPhone;
@Schema(description = "交检清单JSON")
private String inspectionData;
@Schema(description = "费用信息JSON")
private String costList;
@Schema(description = "车辆列表")
private List<DeliveryOrderVehicleVO> vehicles;
}

View File

@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "交车单车辆 VO")
@Data
public class DeliveryOrderVehicleVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "交车任务车辆ID")
private Long taskVehicleId;
@Schema(description = "车辆ID")
private Long vehicleId;
@Schema(description = "车牌号")
private String plateNo;
@Schema(description = "VIN码")
private String vin;
@Schema(description = "品牌")
private String brand;
@Schema(description = "型号")
private String model;
@Schema(description = "交车时里程")
private Integer mileage;
@Schema(description = "交车时氢气量kg")
private BigDecimal hydrogenLevel;
@Schema(description = "交车时电量(%")
private BigDecimal batteryLevel;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDate;
@Schema(description = "管理后台 - 交车任务激活 Request VO")
@Data
public class DeliveryTaskActivateReqVO {
@Schema(description = "任务ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "任务ID不能为空")
private Long id;
@Schema(description = "预计交车开始日期", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "预计交车开始日期不能为空")
private LocalDate expectedDeliveryDateStart;
@Schema(description = "预计交车结束日期")
private LocalDate expectedDeliveryDateEnd;
@Schema(description = "开始计费日期", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始计费日期不能为空")
private LocalDate billingStartDate;
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
@Schema(description = "管理后台 - 交车任务按合同分组 Response VO")
@Data
public class DeliveryTaskContractGroupRespVO {
@Schema(description = "合同ID")
private Long contractId;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "业务部门名称")
private String businessDeptName;
@Schema(description = "业务负责人名称")
private String businessManagerName;
@Schema(description = "合同生效日期")
private LocalDate startDate;
@Schema(description = "合同结束日期")
private LocalDate endDate;
@Schema(description = "交车任务列表")
private List<DeliveryTaskRespVO> tasks;
}

View File

@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 交车任务分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DeliveryTaskPageReqVO extends PageParam {
@Schema(description = "任务编码")
private String taskCode;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "任务状态")
private Integer taskStatus;
@Schema(description = "交车状态")
private Integer deliveryStatus;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,71 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 交车任务 Response VO")
@Data
public class DeliveryTaskRespVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "任务编码")
private String taskCode;
@Schema(description = "合同ID")
private Long contractId;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户ID")
private Long customerId;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "预计交车开始日期")
private LocalDate expectedDeliveryDateStart;
@Schema(description = "预计交车结束日期")
private LocalDate expectedDeliveryDateEnd;
@Schema(description = "开始计费日期")
private LocalDate billingStartDate;
@Schema(description = "交车省份")
private String deliveryProvince;
@Schema(description = "交车城市")
private String deliveryCity;
@Schema(description = "交车地点")
private String deliveryLocation;
@Schema(description = "交车数量")
private Integer vehicleCount;
@Schema(description = "任务状态")
private Integer taskStatus;
@Schema(description = "交车状态")
private Integer deliveryStatus;
@Schema(description = "是否需要还车")
private Boolean needReturn;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "车辆列表")
private List<DeliveryTaskVehicleVO> vehicles;
}

View File

@@ -0,0 +1,58 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
@Schema(description = "管理后台 - 交车任务创建/更新 Request VO")
@Data
public class DeliveryTaskSaveReqVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "合同ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "合同ID不能为空")
private Long contractId;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户ID")
private Long customerId;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "预计交车开始日期")
private LocalDate expectedDeliveryDateStart;
@Schema(description = "预计交车结束日期")
private LocalDate expectedDeliveryDateEnd;
@Schema(description = "开始计费日期", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始计费日期不能为空")
private LocalDate billingStartDate;
@Schema(description = "交车省份")
private String deliveryProvince;
@Schema(description = "交车城市")
private String deliveryCity;
@Schema(description = "交车地点")
private String deliveryLocation;
@Schema(description = "是否需要还车")
private Boolean needReturn;
@Schema(description = "车辆列表")
private List<DeliveryTaskVehicleVO> vehicles;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 交车任务精简 Response VO")
@Data
public class DeliveryTaskSimpleRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "任务编码", example = "HT-2026-0001JC0001")
private String taskCode;
@Schema(description = "合同编码", example = "HT-2026-0001")
private String contractCode;
@Schema(description = "项目名称", example = "XX物流项目")
private String projectName;
@Schema(description = "客户名称", example = "XX公司")
private String customerName;
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "交车任务车辆 VO")
@Data
public class DeliveryTaskVehicleVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "合同车辆ID")
private Long contractVehicleId;
@Schema(description = "车辆ID")
private Long vehicleId;
@Schema(description = "车牌号")
private String plateNo;
@Schema(description = "VIN码")
private String vin;
@Schema(description = "品牌")
private String brand;
@Schema(description = "型号")
private String model;
@Schema(description = "月租金")
private BigDecimal monthRent;
@Schema(description = "保证金")
private BigDecimal deposit;
@Schema(description = "是否已交车")
private Boolean isDelivered;
@Schema(description = "实际交车日期")
private java.time.LocalDateTime actualDeliveryDate;
@Schema(description = "交车人")
private String deliveryPerson;
}

View File

@@ -0,0 +1,80 @@
package cn.iocoder.yudao.module.asset.controller.admin.prepare;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asset.controller.admin.prepare.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.prepare.VehiclePrepareDO;
import cn.iocoder.yudao.module.asset.service.prepare.VehiclePrepareService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 备车管理")
@RestController
@RequestMapping("/asset/vehicle-prepare")
@Validated
public class VehiclePrepareController {
@Resource
private VehiclePrepareService vehiclePrepareService;
@PostMapping("/create")
@Operation(summary = "创建备车记录")
@PreAuthorize("@ss.hasPermission('asset:vehicle-prepare:create')")
public CommonResult<Long> createVehiclePrepare(@Valid @RequestBody VehiclePrepareSaveReqVO createReqVO) {
return success(vehiclePrepareService.createVehiclePrepare(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新备车记录")
@PreAuthorize("@ss.hasPermission('asset:vehicle-prepare:update')")
public CommonResult<Boolean> updateVehiclePrepare(@Valid @RequestBody VehiclePrepareSaveReqVO updateReqVO) {
vehiclePrepareService.updateVehiclePrepare(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除备车记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:vehicle-prepare:delete')")
public CommonResult<Boolean> deleteVehiclePrepare(@RequestParam("id") Long id) {
vehiclePrepareService.deleteVehiclePrepare(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得备车记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:vehicle-prepare:query')")
public CommonResult<VehiclePrepareRespVO> getVehiclePrepare(@RequestParam("id") Long id) {
VehiclePrepareDO prepare = vehiclePrepareService.getVehiclePrepare(id);
return success(BeanUtils.toBean(prepare, VehiclePrepareRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得备车记录分页")
@PreAuthorize("@ss.hasPermission('asset:vehicle-prepare:query')")
public CommonResult<PageResult<VehiclePrepareRespVO>> getVehiclePreparePage(@Valid VehiclePreparePageReqVO pageReqVO) {
PageResult<VehiclePrepareDO> pageResult = vehiclePrepareService.getVehiclePreparePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, VehiclePrepareRespVO.class));
}
@PutMapping("/complete")
@Operation(summary = "完成备车")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:vehicle-prepare:update')")
public CommonResult<Boolean> completeVehiclePrepare(@RequestParam("id") Long id) {
vehiclePrepareService.completeVehiclePrepare(id);
return success(true);
}
}

View File

@@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.asset.controller.admin.prepare.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 备车记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class VehiclePreparePageReqVO extends PageParam {
@Schema(description = "车牌号")
private String plateNo;
@Schema(description = "VIN码")
private String vin;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "车辆类型")
private String vehicleType;
@Schema(description = "品牌")
private String brand;
@Schema(description = "停车场")
private String parkingLot;
@Schema(description = "状态")
private Integer status;
@Schema(description = "备车日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] completeTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,97 @@
package cn.iocoder.yudao.module.asset.controller.admin.prepare.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 备车记录创建/更新 Request VO")
@Data
public class VehiclePrepareSaveReqVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "车辆ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "车辆ID不能为空")
private Long vehicleId;
@Schema(description = "车牌号")
private String plateNo;
@Schema(description = "VIN码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "VIN码不能为空")
private String vin;
@Schema(description = "车型ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "车型ID不能为空")
private Long vehicleModelId;
@Schema(description = "品牌")
private String brand;
@Schema(description = "型号")
private String model;
@Schema(description = "车辆类型")
private String vehicleType;
@Schema(description = "停车场")
private String parkingLot;
@Schema(description = "合同ID")
private Long contractId;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "整备类型")
private String preparationType;
@Schema(description = "里程(km)")
private Integer mileage;
@Schema(description = "剩余氢量")
private BigDecimal hydrogenRemaining;
@Schema(description = "氢量单位")
private String hydrogenUnit;
@Schema(description = "剩余电量(%)")
private BigDecimal batteryRemaining;
@Schema(description = "是否有车身广告")
private Boolean hasBodyAd;
@Schema(description = "广告照片")
private String bodyAdPhotos;
@Schema(description = "放大字照片")
private String enlargedTextPhoto;
@Schema(description = "是否有尾板")
private Boolean hasTailLift;
@Schema(description = "备胎胎纹深度(mm)")
private BigDecimal spareTireDepth;
@Schema(description = "备胎照片")
private String spareTirePhoto;
@Schema(description = "挂车牌号")
private String trailerPlateNo;
@Schema(description = "瑕疵照片")
private String defectPhotos;
@Schema(description = "检查清单JSON")
private String checkList;
@Schema(description = "备注")
private String remark;
@Schema(description = "状态")
private Integer status;
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 还车单分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ReturnOrderPageReqVO extends PageParam {
@Schema(description = "还车单编码")
private String orderCode;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "状态")
private Integer status;
@Schema(description = "还车原因")
private String returnReason;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,77 @@
package cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 还车单 Response VO")
@Data
public class ReturnOrderRespVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "还车单编码")
private String orderCode;
@Schema(description = "合同ID")
private Long contractId;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户ID")
private Long customerId;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "还车日期")
private LocalDateTime returnDate;
@Schema(description = "还车验收人")
private String returnPerson;
@Schema(description = "还车地点")
private String returnLocation;
@Schema(description = "还车原因")
private String returnReason;
@Schema(description = "还车原因说明")
private String returnReasonDesc;
@Schema(description = "退还总金额")
private BigDecimal totalRefundAmount;
@Schema(description = "退还保证金")
private BigDecimal depositRefund;
@Schema(description = "氢气退款")
private BigDecimal hydrogenRefund;
@Schema(description = "其他费用")
private BigDecimal otherCharges;
@Schema(description = "还车照片")
private String returnPhotos;
@Schema(description = "状态")
private Integer status;
@Schema(description = "审批状态")
private Integer approvalStatus;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "车辆列表")
private List<ReturnOrderVehicleVO> vehicles;
}

View File

@@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 还车单创建/更新 Request VO")
@Data
public class ReturnOrderSaveReqVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "合同ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "合同ID不能为空")
private Long contractId;
@Schema(description = "合同编码")
private String contractCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "客户ID")
private Long customerId;
@Schema(description = "客户名称")
private String customerName;
@Schema(description = "还车日期", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "还车日期不能为空")
private LocalDateTime returnDate;
@Schema(description = "还车验收人", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "还车验收人不能为空")
private String returnPerson;
@Schema(description = "还车地点")
private String returnLocation;
@Schema(description = "还车原因")
private String returnReason;
@Schema(description = "还车原因说明")
private String returnReasonDesc;
@Schema(description = "退还保证金")
private BigDecimal depositRefund;
@Schema(description = "氢气退款")
private BigDecimal hydrogenRefund;
@Schema(description = "其他费用")
private BigDecimal otherCharges;
@Schema(description = "还车照片")
private String returnPhotos;
@Schema(description = "车辆列表")
private List<ReturnOrderVehicleVO> vehicles;
}

View File

@@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "还车车辆 VO")
@Data
public class ReturnOrderVehicleVO {
@Schema(description = "主键")
private Long id;
@Schema(description = "车辆ID")
private Long vehicleId;
@Schema(description = "车牌号")
private String plateNo;
@Schema(description = "VIN码")
private String vin;
@Schema(description = "品牌")
private String brand;
@Schema(description = "型号")
private String model;
@Schema(description = "还车时里程")
private Integer returnMileage;
@Schema(description = "还车时氢气量")
private BigDecimal returnHydrogenLevel;
@Schema(description = "交车时氢气量")
private BigDecimal deliveryHydrogenLevel;
@Schema(description = "氢气差值")
private BigDecimal hydrogenDiff;
@Schema(description = "氢气单价")
private BigDecimal hydrogenUnitPrice;
@Schema(description = "氢气退款金额")
private BigDecimal hydrogenRefundAmount;
@Schema(description = "检查清单JSON")
private String checkList;
@Schema(description = "瑕疵照片")
private String defectPhotos;
@Schema(description = "车损费")
private BigDecimal vehicleDamageFee;
@Schema(description = "工具损坏费")
private BigDecimal toolDamageFee;
@Schema(description = "未结算保养费")
private BigDecimal unpaidMaintenanceFee;
@Schema(description = "未结算维修费")
private BigDecimal unpaidRepairFee;
@Schema(description = "违章费用")
private BigDecimal violationFee;
@Schema(description = "其他费用")
private BigDecimal otherFee;
}

View File

@@ -0,0 +1,84 @@
package cn.iocoder.yudao.module.asset.controller.admin.station;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asset.controller.admin.station.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.station.HydrogenStationDO;
import cn.iocoder.yudao.module.asset.service.station.HydrogenStationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* 加氢站管理 Controller
*
* @author 芋道源码
*/
@Tag(name = "管理后台 - 加氢站管理")
@RestController
@RequestMapping("/asset/hydrogen-station")
@Validated
public class HydrogenStationController {
@Resource
private HydrogenStationService hydrogenStationService;
@PostMapping("/create")
@Operation(summary = "创建加氢站")
@PreAuthorize("@ss.hasPermission('asset:hydrogen-station:create')")
public CommonResult<Long> createHydrogenStation(@Valid @RequestBody HydrogenStationSaveReqVO createReqVO) {
return success(hydrogenStationService.createHydrogenStation(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新加氢站")
@PreAuthorize("@ss.hasPermission('asset:hydrogen-station:update')")
public CommonResult<Boolean> updateHydrogenStation(@Valid @RequestBody HydrogenStationSaveReqVO updateReqVO) {
hydrogenStationService.updateHydrogenStation(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除加氢站")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('asset:hydrogen-station:delete')")
public CommonResult<Boolean> deleteHydrogenStation(@RequestParam("id") Long id) {
hydrogenStationService.deleteHydrogenStation(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得加氢站")
@Parameter(name = "id", description = "编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('asset:hydrogen-station:query')")
public CommonResult<HydrogenStationRespVO> getHydrogenStation(@RequestParam("id") Long id) {
HydrogenStationDO hydrogenStation = hydrogenStationService.getHydrogenStation(id);
return success(BeanUtils.toBean(hydrogenStation, HydrogenStationRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得加氢站分页")
@PreAuthorize("@ss.hasPermission('asset:hydrogen-station:query')")
public CommonResult<PageResult<HydrogenStationRespVO>> getHydrogenStationPage(@Valid HydrogenStationPageReqVO pageReqVO) {
PageResult<HydrogenStationDO> pageResult = hydrogenStationService.getHydrogenStationPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, HydrogenStationRespVO.class));
}
@GetMapping("/simple-list")
@Operation(summary = "获得加氢站精简列表", description = "用于下拉选择")
public CommonResult<List<HydrogenStationSimpleRespVO>> getHydrogenStationSimpleList() {
List<HydrogenStationDO> list = hydrogenStationService.getHydrogenStationSimpleList();
return success(BeanUtils.toBean(list, HydrogenStationSimpleRespVO.class));
}
}

View File

@@ -0,0 +1,84 @@
package cn.iocoder.yudao.module.asset.controller.admin.station.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import java.time.LocalDate;
import java.time.LocalTime;
/**
* 加氢站 Base VO
*
* @author 芋道源码
*/
@Data
public class HydrogenStationBaseVO {
@Schema(description = "站点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "嘉兴嘉燃经开站")
@NotBlank(message = "站点名称不能为空")
private String name;
@Schema(description = "简称", example = "经开站")
private String shortName;
@Schema(description = "站点编码", example = "JX001")
private String stationNo;
@Schema(description = "所属城市", example = "嘉兴")
private String city;
@Schema(description = "站点地址", example = "浙江省嘉兴市经济开发区岗山路")
private String address;
@Schema(description = "经度", example = "120.123456")
@Pattern(regexp = "^-?((0|[1-9]\\d?|1[0-7]\\d)(\\.\\d{1,6})?|180(\\.0{1,6})?)$", message = "经度格式不正确,范围:-180~180")
private String longitude;
@Schema(description = "纬度", example = "30.123456")
@Pattern(regexp = "^-?((0|[1-8]?\\d)(\\.\\d{1,6})?|90(\\.0{1,6})?)$", message = "纬度格式不正确,范围:-90~90")
private String latitude;
@Schema(description = "联系人", example = "张三")
private String contact;
@Schema(description = "联系电话", example = "13800138000")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
@Schema(description = "站点类型(字典)", example = "1")
private Integer stationType;
@Schema(description = "合作类型0=合作 1=非合作)", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "合作类型不能为空")
private Integer cooperationType;
@Schema(description = "是否自动扣款1=是 0=否)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否自动扣款不能为空")
private Boolean autoDeduct;
@Schema(description = "是否需要预约1=是 0=否)", example = "false")
private Boolean bookingRequired;
@Schema(description = "站点状态0=停用 1=启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "站点状态不能为空")
private Integer stationStatus;
@Schema(description = "开始营业时间", example = "08:00:00")
private LocalTime startBusiness;
@Schema(description = "结束营业时间", example = "18:00:00")
private LocalTime endBusiness;
@Schema(description = "结算方式(字典)", example = "1")
private Integer billingMethod;
@Schema(description = "合作期限", example = "2027-12-31")
private LocalDate cooperationTerm;
@Schema(description = "备注", example = "合作站点,自动扣款")
private String remark;
}

View File

@@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.asset.controller.admin.station.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 加氢站 - 分页查询 Request VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 加氢站分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class HydrogenStationPageReqVO extends PageParam {
@Schema(description = "站点名称", example = "嘉兴嘉燃经开站")
private String name;
@Schema(description = "站点编码", example = "JX001")
private String stationNo;
@Schema(description = "所属城市", example = "嘉兴")
private String city;
@Schema(description = "合作类型0=合作 1=非合作)", example = "0")
private Integer cooperationType;
@Schema(description = "站点状态0=停用 1=启用)", example = "1")
private Integer stationStatus;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.asset.controller.admin.station.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
/**
* 加氢站 - Response VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 加氢站 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class HydrogenStationRespVO extends HydrogenStationBaseVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.asset.controller.admin.station.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 加氢站 - 创建/更新 Request VO
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 加氢站创建/更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class HydrogenStationSaveReqVO extends HydrogenStationBaseVO {
@Schema(description = "主键", example = "1")
private Long id;
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.asset.controller.admin.station.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 加氢站 - 精简信息 Response VO
* 用于下拉选择
*
* @author 芋道源码
*/
@Schema(description = "管理后台 - 加氢站精简信息 Response VO")
@Data
public class HydrogenStationSimpleRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "站点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "嘉兴嘉燃经开站")
private String name;
}

View File

@@ -21,6 +21,9 @@ import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -58,6 +61,23 @@ public class VehicleRegistrationController {
return success(result);
}
@PostMapping("/ocr")
@Operation(summary = "通过文件URL识别行驶证")
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:recognize')")
public CommonResult<VehicleLicenseRecognizeRespVO> ocrVehicleLicense(
@RequestBody Map<String, String> body) throws IOException {
String fileUrl = body.get("fileUrl");
if (fileUrl == null || fileUrl.isBlank()) {
throw new IllegalArgumentException("fileUrl 不能为空");
}
log.info("[ocrVehicleLicense][通过URL识别行驶证{}]", fileUrl);
try (InputStream is = URI.create(fileUrl).toURL().openStream()) {
byte[] imageData = is.readAllBytes();
VehicleLicenseRecognizeRespVO result = vehicleRegistrationService.recognizeVehicleLicense(imageData);
return success(result);
}
}
@PostMapping("/create")
@Operation(summary = "创建车辆上牌记录")
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:create')")
@@ -99,7 +119,7 @@ public class VehicleRegistrationController {
return success(VehicleRegistrationConvert.INSTANCE.convertPage(pageResult));
}
@PostMapping("/confirm")
@PutMapping("/confirm")
@Operation(summary = "确认上牌记录(更新车辆信息)")
@Parameter(name = "id", description = "上牌记录ID", required = true)
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:update')")
@@ -108,4 +128,13 @@ public class VehicleRegistrationController {
return success(true);
}
@PutMapping("/void")
@Operation(summary = "作废上牌记录")
@Parameter(name = "id", description = "上牌记录ID", required = true)
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:update')")
public CommonResult<Boolean> voidRegistration(@RequestParam("id") Long id) {
vehicleRegistrationService.voidRegistration(id);
return success(true);
}
}

View File

@@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.asset.convert.contract;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.asset.controller.admin.contract.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.*;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 车辆租赁合同 Convert
*
* @author 芋道源码
*/
@Mapper
public interface ContractConvert {
ContractConvert INSTANCE = Mappers.getMapper(ContractConvert.class);
ContractDO convert(ContractSaveReqVO bean);
ContractRespVO convert(ContractDO bean);
ContractDetailRespVO convertDetail(ContractDO bean);
PageResult<ContractRespVO> convertPage(PageResult<ContractDO> page);
List<ContractVehicleDO> convertVehicleList(List<ContractSaveReqVO.ContractVehicleSaveVO> list);
ContractVehicleDO convertVehicle(ContractSaveReqVO.ContractVehicleSaveVO bean);
List<ContractVehicleServiceDO> convertServiceList(List<ContractVehicleServiceVO> list);
ContractVehicleServiceDO convertService(ContractVehicleServiceVO bean);
List<ContractAuthorizedDO> convertAuthorizedList(List<ContractAuthorizedVO> list);
ContractAuthorizedDO convertAuthorized(ContractAuthorizedVO bean);
List<ContractDetailRespVO.ContractVehicleDetailVO> convertVehicleDetailList(List<ContractVehicleDO> list);
ContractDetailRespVO.ContractVehicleDetailVO convertVehicleDetail(ContractVehicleDO bean);
List<ContractVehicleServiceVO> convertServiceVOList(List<ContractVehicleServiceDO> list);
List<ContractAuthorizedVO> convertAuthorizedVOList(List<ContractAuthorizedDO> list);
List<ContractAttachmentVO> convertAttachmentVOList(List<ContractAttachmentDO> list);
ContractAttachmentDO convertAttachment(ContractAttachmentVO bean);
List<ContractAttachmentDO> convertAttachmentList(List<ContractAttachmentVO> list);
}

View File

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.asset.dal.dataobject.customer.CustomerDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 客户 Convert
*
@@ -23,4 +25,6 @@ public interface CustomerConvert {
PageResult<CustomerRespVO> convertPage(PageResult<CustomerDO> page);
List<CustomerRespVO> convertList(List<CustomerDO> list);
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.asset.convert.station;
import cn.iocoder.yudao.module.asset.controller.admin.station.vo.HydrogenStationRespVO;
import cn.iocoder.yudao.module.asset.controller.admin.station.vo.HydrogenStationSimpleRespVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.station.HydrogenStationDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 加氢站 Convert
*
* @author 芋道源码
*/
@Mapper
public interface HydrogenStationConvert {
HydrogenStationConvert INSTANCE = Mappers.getMapper(HydrogenStationConvert.class);
/**
* 转换为响应 VO
*/
HydrogenStationRespVO convert(HydrogenStationDO bean);
/**
* 转换为精简响应 VO
*/
HydrogenStationSimpleRespVO convertSimple(HydrogenStationDO bean);
/**
* 批量转换为精简响应 VO
*/
List<HydrogenStationSimpleRespVO> convertSimpleList(List<HydrogenStationDO> list);
}

View File

@@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.contract;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 合同附件 DO
*
* @author 芋道源码
*/
@TableName("asset_contract_attachment")
@KeySequence("asset_contract_attachment_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContractAttachmentDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 合同ID
*/
private Long contractId;
/**
* 附件类型1=合同原件 2=盖章合同)
*/
private Integer attachmentType;
/**
* 文件ID关联 infra_file
*/
private Long fileId;
/**
* 文件名称
*/
private String fileName;
/**
* 文件URL
*/
private String fileUrl;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* 上传时间
*/
private LocalDateTime uploadTime;
/**
* 上传人
*/
private String uploader;
}

View File

@@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.contract;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 合同被授权人 DO
*
* @author 芋道源码
*/
@TableName("asset_contract_authorized")
@KeySequence("asset_contract_authorized_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContractAuthorizedDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 合同ID
*/
private Long contractId;
/**
* 姓名
*/
private String name;
/**
* 电话
*/
private String phone;
/**
* 身份证号
*/
private String idCard;
}

View File

@@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.contract;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 合同变更历史 DO
*
* @author 芋道源码
*/
@TableName("asset_contract_change_history")
@KeySequence("asset_contract_change_history_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContractChangeHistoryDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 合同ID
*/
private Long contractId;
/**
* 变更类型
*/
private String changeType;
/**
* 变更内容
*/
private String changeContent;
/**
* 操作人
*/
private String operator;
/**
* 操作时间
*/
private LocalDateTime operateTime;
}

View File

@@ -0,0 +1,199 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.contract;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 车辆租赁合同 DO
*
* @author 芋道源码
*/
@TableName("asset_contract")
@KeySequence("asset_contract_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContractDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 合同编码
*/
private String contractCode;
/**
* 合同类型1=试用 2=正式)
*/
private Integer contractType;
/**
* 项目名称
*/
private String projectName;
/**
* 生效日期
*/
private LocalDate startDate;
/**
* 结束日期
*/
private LocalDate endDate;
/**
* 付款方式
*/
private String paymentMethod;
/**
* 付款周期
*/
private String paymentCycle;
/**
* 签约公司(乙方)
*/
private String signingCompany;
/**
* 交车省份
*/
private String deliveryProvince;
/**
* 交车城市
*/
private String deliveryCity;
/**
* 交车地点
*/
private String deliveryLocation;
/**
* 备注
*/
private String remark;
/**
* 客户ID
*/
private Long customerId;
/**
* 客户名称(冗余)
*/
private String customerName;
/**
* 是否三方合同
*/
private Boolean thirdPartyEnabled;
/**
* 丙方客户ID
*/
private Long thirdPartyCustomerId;
/**
* 丙方名称
*/
private String thirdPartyName;
/**
* 业务部门ID
*/
private Long businessDeptId;
/**
* 业务负责人ID
*/
private Long businessManagerId;
/**
* 审批状态0=草稿 1=审批中 2=审批通过 3=审批拒绝 4=已撤回)
*/
private Integer approvalStatus;
/**
* BPM流程实例ID
*/
private String bpmInstanceId;
/**
* 合同状态0=草稿 1=待生效 2=进行中 3=已到期 4=已终止 5=已续签)
*/
private Integer contractStatus;
/**
* 实际生效时间
*/
private LocalDateTime effectiveTime;
/**
* 终止时间
*/
private LocalDateTime terminateTime;
/**
* 终止原因
*/
private String terminateReason;
/**
* 续签后的新合同ID
*/
private Long renewedContractId;
/**
* 原合同ID如果是续签合同
*/
private Long originalContractId;
/**
* 氢费承担方
*/
private String hydrogenBearer;
/**
* 氢气付款方式
*/
private String hydrogenPaymentMethod;
/**
* 氢气预付款
*/
private BigDecimal hydrogenPrepay;
/**
* 退还车氢气单价
*/
private BigDecimal hydrogenReturnPrice;
/**
* 账单计算方式
*/
private String billingMethod;
/**
* 主车型
*/
private String mainVehicleType;
}

View File

@@ -0,0 +1,93 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.contract;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 合同车辆租赁订单 DO
*
* @author 芋道源码
*/
@TableName("asset_contract_vehicle")
@KeySequence("asset_contract_vehicle_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContractVehicleDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 合同ID
*/
private Long contractId;
/**
* 车辆ID关联 asset_vehicle_base
*/
private Long vehicleId;
/**
* 品牌
*/
private String brand;
/**
* 型号
*/
private String model;
/**
* 车牌号
*/
private String plateNo;
/**
* VIN码
*/
private String vin;
/**
* 月租金(元)
*/
private BigDecimal monthRent;
/**
* 保证金(元)
*/
private BigDecimal deposit;
/**
* 车辆状态0=待交车 1=已交车 2=已退车)
*/
private Integer vehicleStatus;
/**
* 实际交车时间
*/
private LocalDateTime actualDeliveryTime;
/**
* 交车人
*/
private String deliveryPerson;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.contract;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 合同车辆服务项目 DO
*
* @author 芋道源码
*/
@TableName("asset_contract_vehicle_service")
@KeySequence("asset_contract_vehicle_service_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContractVehicleServiceDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 合同车辆ID
*/
private Long contractVehicleId;
/**
* 服务项目名称
*/
private String serviceName;
/**
* 服务费用(元)
*/
private BigDecimal serviceFee;
/**
* 生效日期
*/
private LocalDate effectiveDate;
}

View File

@@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.delivery;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
/**
* 交车单车辆 DO
*/
@TableName("asset_delivery_order_vehicle")
@KeySequence("asset_delivery_order_vehicle_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryOrderVehicleDO extends BaseDO {
@TableId
private Long id;
private Long orderId;
private Long taskVehicleId;
private Long vehicleId;
private String plateNo;
private String vin;
private String brand;
private String model;
private Integer mileage;
private BigDecimal hydrogenLevel;
private BigDecimal batteryLevel;
}

View File

@@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.delivery;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDate;
/**
* 交车任务 DO
*/
@TableName("asset_delivery_task")
@KeySequence("asset_delivery_task_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryTaskDO extends BaseDO {
@TableId
private Long id;
private String taskCode;
private Long contractId;
private String contractCode;
private String projectName;
private Long customerId;
private String customerName;
private LocalDate expectedDeliveryDateStart;
private LocalDate expectedDeliveryDateEnd;
private LocalDate billingStartDate;
private String deliveryProvince;
private String deliveryCity;
private String deliveryLocation;
private Integer vehicleCount;
/**
* 任务状态0=激活 1=挂起)
*/
private Integer taskStatus;
/**
* 交车状态0=未交车 1=已交车)
*/
private Integer deliveryStatus;
private Boolean needReturn;
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.delivery;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 交车任务车辆 DO
*/
@TableName("asset_delivery_task_vehicle")
@KeySequence("asset_delivery_task_vehicle_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryTaskVehicleDO extends BaseDO {
@TableId
private Long id;
private Long taskId;
private Long contractVehicleId;
private Long vehicleId;
private String plateNo;
private String vin;
private String brand;
private String model;
private BigDecimal monthRent;
private BigDecimal deposit;
private LocalDateTime actualDeliveryDate;
private String deliveryPerson;
private Boolean isDelivered;
}

View File

@@ -0,0 +1,128 @@
package cn.iocoder.yudao.module.asset.dal.dataobject.station;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDate;
import java.time.LocalTime;
/**
* 加氢站 DO
*
* @author 芋道源码
*/
@TableName("asset_hydrogen_station")
@KeySequence("asset_hydrogen_station_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class HydrogenStationDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 站点名称
*/
private String name;
/**
* 简称
*/
private String shortName;
/**
* 站点编码
*/
private String stationNo;
/**
* 所属城市
*/
private String city;
/**
* 站点地址
*/
private String address;
/**
* 经度
*/
private String longitude;
/**
* 纬度
*/
private String latitude;
/**
* 联系人
*/
private String contact;
/**
* 联系电话
*/
private String phone;
/**
* 站点类型(字典)
*/
private Integer stationType;
/**
* 合作类型0=合作 1=非合作)
*/
private Integer cooperationType;
/**
* 是否自动扣款1=是 0=否)
*/
private Boolean autoDeduct;
/**
* 是否需要预约1=是 0=否)
*/
private Boolean bookingRequired;
/**
* 站点状态0=停用 1=启用)
*/
private Integer stationStatus;
/**
* 开始营业时间
*/
private LocalTime startBusiness;
/**
* 结束营业时间
*/
private LocalTime endBusiness;
/**
* 结算方式(字典)
*/
private Integer billingMethod;
/**
* 合作期限
*/
private LocalDate cooperationTerm;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.asset.dal.mysql.contract;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractAttachmentDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 合同附件 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ContractAttachmentMapper extends BaseMapperX<ContractAttachmentDO> {
default List<ContractAttachmentDO> selectListByContractId(Long contractId) {
return selectList(new LambdaQueryWrapperX<ContractAttachmentDO>()
.eq(ContractAttachmentDO::getContractId, contractId)
.orderByAsc(ContractAttachmentDO::getId));
}
default int deleteByContractId(Long contractId) {
return delete(new LambdaQueryWrapperX<ContractAttachmentDO>()
.eq(ContractAttachmentDO::getContractId, contractId));
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.asset.dal.mysql.contract;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractAuthorizedDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 合同被授权人 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ContractAuthorizedMapper extends BaseMapperX<ContractAuthorizedDO> {
default List<ContractAuthorizedDO> selectListByContractId(Long contractId) {
return selectList(new LambdaQueryWrapperX<ContractAuthorizedDO>()
.eq(ContractAuthorizedDO::getContractId, contractId)
.orderByAsc(ContractAuthorizedDO::getId));
}
default int deleteByContractId(Long contractId) {
return delete(new LambdaQueryWrapperX<ContractAuthorizedDO>()
.eq(ContractAuthorizedDO::getContractId, contractId));
}
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.asset.dal.mysql.contract;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractChangeHistoryDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 合同变更历史 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ContractChangeHistoryMapper extends BaseMapperX<ContractChangeHistoryDO> {
default List<ContractChangeHistoryDO> selectListByContractId(Long contractId) {
return selectList(new LambdaQueryWrapperX<ContractChangeHistoryDO>()
.eq(ContractChangeHistoryDO::getContractId, contractId)
.orderByDesc(ContractChangeHistoryDO::getOperateTime));
}
}

View File

@@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.asset.dal.mysql.contract;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.controller.admin.contract.vo.ContractPageReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDate;
/**
* 车辆租赁合同 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ContractMapper extends BaseMapperX<ContractDO> {
default PageResult<ContractDO> selectPage(ContractPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ContractDO>()
.likeIfPresent(ContractDO::getContractCode, reqVO.getContractCode())
.eqIfPresent(ContractDO::getContractType, reqVO.getContractType())
.likeIfPresent(ContractDO::getProjectName, reqVO.getProjectName())
.eqIfPresent(ContractDO::getCustomerId, reqVO.getCustomerId())
.likeIfPresent(ContractDO::getCustomerName, reqVO.getCustomerName())
.eqIfPresent(ContractDO::getApprovalStatus, reqVO.getApprovalStatus())
.eqIfPresent(ContractDO::getContractStatus, reqVO.getContractStatus())
.betweenIfPresent(ContractDO::getStartDate, reqVO.getStartDate())
.betweenIfPresent(ContractDO::getEndDate, reqVO.getEndDate())
.eqIfPresent(ContractDO::getBusinessDeptId, reqVO.getBusinessDeptId())
.eqIfPresent(ContractDO::getSigningCompany, reqVO.getSigningCompany())
.eqIfPresent(ContractDO::getBusinessManagerId, reqVO.getBusinessManagerId())
.likeIfPresent(ContractDO::getCreator, reqVO.getCreator())
.orderByDesc(ContractDO::getId));
}
@Select("SELECT contract_code FROM asset_contract WHERE contract_code LIKE CONCAT(#{prefix}, '%') AND deleted = 0 ORDER BY contract_code DESC LIMIT 1")
String selectMaxContractCodeByPrefix(@Param("prefix") String prefix);
/**
* 检查车辆在指定时间段内是否有有效合同
*/
@Select("SELECT COUNT(*) FROM asset_contract c " +
"INNER JOIN asset_contract_vehicle cv ON c.id = cv.contract_id " +
"WHERE cv.vehicle_id = #{vehicleId} " +
"AND c.contract_status IN (1, 2) " +
"AND c.deleted = 0 AND cv.deleted = 0 " +
"AND NOT (c.end_date < #{startDate} OR c.start_date > #{endDate})")
int countActiveContractsByVehicleAndDateRange(@Param("vehicleId") Long vehicleId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.asset.dal.mysql.contract;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractVehicleDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 合同车辆租赁订单 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ContractVehicleMapper extends BaseMapperX<ContractVehicleDO> {
default List<ContractVehicleDO> selectListByContractId(Long contractId) {
return selectList(new LambdaQueryWrapperX<ContractVehicleDO>()
.eq(ContractVehicleDO::getContractId, contractId)
.orderByAsc(ContractVehicleDO::getId));
}
default int deleteByContractId(Long contractId) {
return delete(new LambdaQueryWrapperX<ContractVehicleDO>()
.eq(ContractVehicleDO::getContractId, contractId));
}
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.asset.dal.mysql.contract;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractVehicleServiceDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 合同车辆服务项目 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ContractVehicleServiceMapper extends BaseMapperX<ContractVehicleServiceDO> {
default List<ContractVehicleServiceDO> selectListByContractVehicleId(Long contractVehicleId) {
return selectList(new LambdaQueryWrapperX<ContractVehicleServiceDO>()
.eq(ContractVehicleServiceDO::getContractVehicleId, contractVehicleId)
.orderByAsc(ContractVehicleServiceDO::getId));
}
default int deleteByContractVehicleId(Long contractVehicleId) {
return delete(new LambdaQueryWrapperX<ContractVehicleServiceDO>()
.eq(ContractVehicleServiceDO::getContractVehicleId, contractVehicleId));
}
default int deleteByContractVehicleIds(List<Long> contractVehicleIds) {
return delete(new LambdaQueryWrapperX<ContractVehicleServiceDO>()
.in(ContractVehicleServiceDO::getContractVehicleId, contractVehicleIds));
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.asset.dal.mysql.delivery;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryOrderPageReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DeliveryOrderMapper extends BaseMapperX<DeliveryOrderDO> {
default PageResult<DeliveryOrderDO> selectPage(DeliveryOrderPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DeliveryOrderDO>()
.likeIfPresent(DeliveryOrderDO::getOrderCode, reqVO.getOrderCode())
.likeIfPresent(DeliveryOrderDO::getTaskCode, reqVO.getTaskCode())
.likeIfPresent(DeliveryOrderDO::getContractCode, reqVO.getContractCode())
.likeIfPresent(DeliveryOrderDO::getProjectName, reqVO.getProjectName())
.likeIfPresent(DeliveryOrderDO::getCustomerName, reqVO.getCustomerName())
.likeIfPresent(DeliveryOrderDO::getDeliveryPerson, reqVO.getDeliveryPerson())
.eqIfPresent(DeliveryOrderDO::getStatus, reqVO.getStatus())
.betweenIfPresent(DeliveryOrderDO::getDeliveryDate, reqVO.getDeliveryDate())
.betweenIfPresent(DeliveryOrderDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DeliveryOrderDO::getId));
}
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.asset.dal.mysql.delivery;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderVehicleDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DeliveryOrderVehicleMapper extends BaseMapperX<DeliveryOrderVehicleDO> {
default List<DeliveryOrderVehicleDO> selectListByOrderId(Long orderId) {
return selectList(DeliveryOrderVehicleDO::getOrderId, orderId);
}
default void deleteByOrderId(Long orderId) {
delete(DeliveryOrderVehicleDO::getOrderId, orderId);
}
}

View File

@@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.asset.dal.mysql.delivery;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskPageReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryTaskDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DeliveryTaskMapper extends BaseMapperX<DeliveryTaskDO> {
default PageResult<DeliveryTaskDO> selectPage(DeliveryTaskPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DeliveryTaskDO>()
.likeIfPresent(DeliveryTaskDO::getTaskCode, reqVO.getTaskCode())
.likeIfPresent(DeliveryTaskDO::getContractCode, reqVO.getContractCode())
.likeIfPresent(DeliveryTaskDO::getProjectName, reqVO.getProjectName())
.likeIfPresent(DeliveryTaskDO::getCustomerName, reqVO.getCustomerName())
.eqIfPresent(DeliveryTaskDO::getTaskStatus, reqVO.getTaskStatus())
.eqIfPresent(DeliveryTaskDO::getDeliveryStatus, reqVO.getDeliveryStatus())
.betweenIfPresent(DeliveryTaskDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DeliveryTaskDO::getId));
}
default long selectCountByContractId(Long contractId) {
return selectCount(DeliveryTaskDO::getContractId, contractId);
}
default List<DeliveryTaskDO> selectListByFilters(DeliveryTaskPageReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<DeliveryTaskDO>()
.likeIfPresent(DeliveryTaskDO::getTaskCode, reqVO.getTaskCode())
.likeIfPresent(DeliveryTaskDO::getContractCode, reqVO.getContractCode())
.likeIfPresent(DeliveryTaskDO::getProjectName, reqVO.getProjectName())
.likeIfPresent(DeliveryTaskDO::getCustomerName, reqVO.getCustomerName())
.eqIfPresent(DeliveryTaskDO::getTaskStatus, reqVO.getTaskStatus())
.eqIfPresent(DeliveryTaskDO::getDeliveryStatus, reqVO.getDeliveryStatus())
.betweenIfPresent(DeliveryTaskDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DeliveryTaskDO::getId));
}
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.asset.dal.mysql.delivery;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryTaskVehicleDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DeliveryTaskVehicleMapper extends BaseMapperX<DeliveryTaskVehicleDO> {
default List<DeliveryTaskVehicleDO> selectListByTaskId(Long taskId) {
return selectList(DeliveryTaskVehicleDO::getTaskId, taskId);
}
default void deleteByTaskId(Long taskId) {
delete(DeliveryTaskVehicleDO::getTaskId, taskId);
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.asset.dal.mysql.prepare;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.controller.admin.prepare.vo.VehiclePreparePageReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.prepare.VehiclePrepareDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface VehiclePrepareMapper extends BaseMapperX<VehiclePrepareDO> {
default PageResult<VehiclePrepareDO> selectPage(VehiclePreparePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<VehiclePrepareDO>()
.likeIfPresent(VehiclePrepareDO::getPlateNo, reqVO.getPlateNo())
.likeIfPresent(VehiclePrepareDO::getVin, reqVO.getVin())
.likeIfPresent(VehiclePrepareDO::getContractCode, reqVO.getContractCode())
.eqIfPresent(VehiclePrepareDO::getVehicleType, reqVO.getVehicleType())
.likeIfPresent(VehiclePrepareDO::getBrand, reqVO.getBrand())
.likeIfPresent(VehiclePrepareDO::getParkingLot, reqVO.getParkingLot())
.eqIfPresent(VehiclePrepareDO::getStatus, reqVO.getStatus())
.betweenIfPresent(VehiclePrepareDO::getCompleteTime, reqVO.getCompleteTime())
.betweenIfPresent(VehiclePrepareDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(VehiclePrepareDO::getId));
}
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.asset.dal.mysql.returnorder;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderPageReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ReturnOrderMapper extends BaseMapperX<ReturnOrderDO> {
default PageResult<ReturnOrderDO> selectPage(ReturnOrderPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ReturnOrderDO>()
.likeIfPresent(ReturnOrderDO::getOrderCode, reqVO.getOrderCode())
.likeIfPresent(ReturnOrderDO::getContractCode, reqVO.getContractCode())
.likeIfPresent(ReturnOrderDO::getCustomerName, reqVO.getCustomerName())
.eqIfPresent(ReturnOrderDO::getStatus, reqVO.getStatus())
.eqIfPresent(ReturnOrderDO::getReturnReason, reqVO.getReturnReason())
.betweenIfPresent(ReturnOrderDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(ReturnOrderDO::getId));
}
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.asset.dal.mysql.returnorder;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderVehicleDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ReturnOrderVehicleMapper extends BaseMapperX<ReturnOrderVehicleDO> {
default List<ReturnOrderVehicleDO> selectListByReturnOrderId(Long returnOrderId) {
return selectList(ReturnOrderVehicleDO::getReturnOrderId, returnOrderId);
}
default void deleteByReturnOrderId(Long returnOrderId) {
delete(ReturnOrderVehicleDO::getReturnOrderId, returnOrderId);
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.asset.dal.mysql.station;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.asset.controller.admin.station.vo.HydrogenStationPageReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.station.HydrogenStationDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 加氢站 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface HydrogenStationMapper extends BaseMapperX<HydrogenStationDO> {
default PageResult<HydrogenStationDO> selectPage(HydrogenStationPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<HydrogenStationDO>()
.likeIfPresent(HydrogenStationDO::getName, reqVO.getName())
.likeIfPresent(HydrogenStationDO::getStationNo, reqVO.getStationNo())
.likeIfPresent(HydrogenStationDO::getCity, reqVO.getCity())
.eqIfPresent(HydrogenStationDO::getCooperationType, reqVO.getCooperationType())
.eqIfPresent(HydrogenStationDO::getStationStatus, reqVO.getStationStatus())
.betweenIfPresent(HydrogenStationDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(HydrogenStationDO::getId));
}
default List<HydrogenStationDO> selectSimpleList() {
return selectList();
}
}

View File

@@ -20,4 +20,9 @@ public interface VehicleStatusMapper extends BaseMapperX<VehicleStatusDO> {
.in(VehicleStatusDO::getVehicleId, vehicleIds));
}
default VehicleStatusDO selectByVehicleId(Long vehicleId) {
return selectOne(new LambdaQueryWrapperX<VehicleStatusDO>()
.eq(VehicleStatusDO::getVehicleId, vehicleId));
}
}

View File

@@ -38,7 +38,8 @@ public interface ErrorCodeConstants {
ErrorCode CONTRACT_STATUS_NOT_ALLOW_ADD_VEHICLE = new ErrorCode(1_008_005_011, "当前合同状态不允许新增车辆");
ErrorCode CONTRACT_TYPE_NOT_TRIAL = new ErrorCode(1_008_005_012, "只有试用合同才能转正式");
// ========== 车辆登记 1-008-006-000 ==========
// ========== 车辆基础信息 1-008-006-000 ==========
ErrorCode VEHICLE_NOT_EXISTS = new ErrorCode(1_008_006_001, "车辆不存在");
ErrorCode VEHICLE_REGISTRATION_NOT_EXISTS = new ErrorCode(1_008_006_000, "车辆登记不存在");
// ========== 备车管理 1-008-007-000 ==========
@@ -78,4 +79,8 @@ public interface ErrorCodeConstants {
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_WITHDRAW = new ErrorCode(1_008_012_004, "当前状态不允许撤回");
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_CONFIRM = new ErrorCode(1_008_012_005, "当前状态不允许确认换回");
// ========== 加氢站管理 1-008-013-000 ==========
ErrorCode HYDROGEN_STATION_NOT_EXISTS = new ErrorCode(1_008_013_000, "加氢站不存在");
ErrorCode HYDROGEN_STATION_END_BUSINESS_BEFORE_START_BUSINESS = new ErrorCode(1_008_013_001, "结束营业时间不能早于开始营业时间");
}

View File

@@ -0,0 +1,106 @@
package cn.iocoder.yudao.module.asset.job;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
import cn.iocoder.yudao.module.asset.dal.mysql.contract.ContractMapper;
import cn.iocoder.yudao.module.asset.enums.contract.ContractStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
* 合同状态自动流转定时任务
*
* 功能:
* 1. 将待生效的合同自动转为进行中(当前日期 >= 生效日期)
* 2. 将进行中的合同自动转为已到期(当前日期 > 结束日期)
*
* @author 芋道源码
*/
@Component
@Slf4j
public class ContractStatusJob {
@Resource
private ContractMapper contractMapper;
@XxlJob("contractStatusJob")
@TenantJob
public void execute() {
log.info("[contractStatusJob] 开始执行合同状态自动流转");
try {
// 1. 处理待生效 -> 进行中
int activatedCount = activatePendingContracts();
log.info("[contractStatusJob] 激活待生效合同数量: {}", activatedCount);
// 2. 处理进行中 -> 已到期
int expiredCount = expireActiveContracts();
log.info("[contractStatusJob] 到期合同数量: {}", expiredCount);
log.info("[contractStatusJob] 执行完成,激活: {}, 到期: {}", activatedCount, expiredCount);
} catch (Exception e) {
log.error("[contractStatusJob] 执行失败", e);
}
}
/**
* 激活待生效的合同
*/
private int activatePendingContracts() {
LocalDate today = LocalDate.now();
// 查询待生效且生效日期 <= 今天的合同
List<ContractDO> contracts = contractMapper.selectList(
new LambdaQueryWrapper<ContractDO>()
.eq(ContractDO::getContractStatus, ContractStatusEnum.PENDING.getStatus())
.le(ContractDO::getStartDate, today)
);
int count = 0;
for (ContractDO contract : contracts) {
ContractDO updateObj = new ContractDO();
updateObj.setId(contract.getId());
updateObj.setContractStatus(ContractStatusEnum.IN_PROGRESS.getStatus());
updateObj.setEffectiveTime(LocalDateTime.now());
contractMapper.updateById(updateObj);
count++;
log.info("[contractStatusJob] 合同 {} 已激活", contract.getContractCode());
}
return count;
}
/**
* 将进行中的合同标记为已到期
*/
private int expireActiveContracts() {
LocalDate today = LocalDate.now();
// 查询进行中且结束日期 < 今天的合同
List<ContractDO> contracts = contractMapper.selectList(
new LambdaQueryWrapper<ContractDO>()
.eq(ContractDO::getContractStatus, ContractStatusEnum.IN_PROGRESS.getStatus())
.lt(ContractDO::getEndDate, today)
);
int count = 0;
for (ContractDO contract : contracts) {
ContractDO updateObj = new ContractDO();
updateObj.setId(contract.getId());
updateObj.setContractStatus(ContractStatusEnum.EXPIRED.getStatus());
contractMapper.updateById(updateObj);
count++;
log.info("[contractStatusJob] 合同 {} 已到期", contract.getContractCode());
}
return count;
}
}

View File

@@ -0,0 +1,145 @@
package cn.iocoder.yudao.module.asset.service.contract;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.asset.controller.admin.contract.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
import jakarta.validation.Valid;
import java.util.List;
/**
* 车辆租赁合同 Service 接口
*
* @author 芋道源码
*/
public interface ContractService {
/**
* 创建合同
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createContract(@Valid ContractSaveReqVO createReqVO);
/**
* 更新合同
*
* @param updateReqVO 更新信息
*/
void updateContract(@Valid ContractSaveReqVO updateReqVO);
/**
* 删除合同
*
* @param id 编号
*/
void deleteContract(Long id);
/**
* 获得合同
*
* @param id 编号
* @return 合同
*/
ContractDO getContract(Long id);
/**
* 获得合同分页
*
* @param pageReqVO 分页查询
* @return 合同分页
*/
PageResult<ContractDO> getContractPage(ContractPageReqVO pageReqVO);
/**
* 提交合同审批
*
* @param id 合同ID
* @return 流程实例ID
*/
String submitContractApproval(Long id);
/**
* 更新合同审批状态
*
* @param id 合同ID
* @param status 审批状态
*/
void updateContractApprovalStatus(Long id, Integer status);
/**
* 撤回合同审批
*
* @param id 合同ID
*/
void withdrawContractApproval(Long id);
/**
* 终止合同
*
* @param id 合同ID
* @param reason 终止原因
*/
void terminateContract(Long id, String reason);
/**
* 续签合同
*
* @param id 原合同ID
* @param newContractReqVO 新合同信息
* @return 新合同ID
*/
Long renewContract(Long id, ContractSaveReqVO newContractReqVO);
/**
* 获取合同详情(包含关联数据)
*
* @param id 合同ID
* @return 合同详情
*/
ContractDetailRespVO getContractDetail(Long id);
/**
* 获得合同精简列表(用于下拉选择)
*
* @return 合同列表
*/
List<ContractDO> getContractSimpleList();
/**
* 变更为三方合同
*
* @param id 原合同ID
* @param newContractReqVO 新合同信息
* @return 新合同ID
*/
Long convertToThirdParty(Long id, @Valid ContractSaveReqVO newContractReqVO);
/**
* 试用合同转正式
*
* @param id 原合同ID
* @param newContractReqVO 新合同信息
* @return 新合同ID
*/
Long convertToFormal(Long id, @Valid ContractSaveReqVO newContractReqVO);
/**
* 往现有合同追加车辆
*
* @param id 合同ID
* @param vehicles 车辆列表
*/
void addVehiclesToContract(Long id, List<ContractSaveReqVO.ContractVehicleSaveVO> vehicles);
/**
* 上传盖章合同附件
*
* @param id 合同ID
* @param fileUrl 文件URL
* @param fileName 文件名
*/
void uploadSealedContract(Long id, String fileUrl, String fileName);
}

View File

@@ -0,0 +1,609 @@
package cn.iocoder.yudao.module.asset.service.contract;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.asset.controller.admin.contract.vo.*;
import cn.iocoder.yudao.module.asset.convert.contract.ContractConvert;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.*;
import cn.iocoder.yudao.module.asset.dal.mysql.contract.*;
import cn.iocoder.yudao.module.asset.enums.contract.ContractApprovalStatusEnum;
import cn.iocoder.yudao.module.asset.enums.contract.ContractStatusEnum;
import cn.iocoder.yudao.module.asset.service.contract.listener.ContractBpmListener;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCancelReqDTO;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
/**
* 车辆租赁合同 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class ContractServiceImpl implements ContractService {
@Resource
private ContractMapper contractMapper;
@Resource
private ContractVehicleMapper contractVehicleMapper;
@Resource
private ContractVehicleServiceMapper contractVehicleServiceMapper;
@Resource
private ContractAuthorizedMapper contractAuthorizedMapper;
@Resource
private ContractAttachmentMapper contractAttachmentMapper;
@Resource
private ContractChangeHistoryMapper contractChangeHistoryMapper;
@Resource
private BpmProcessInstanceApi bpmProcessInstanceApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createContract(ContractSaveReqVO createReqVO) {
// 校验合同日期
validateContractDate(createReqVO.getStartDate(), createReqVO.getEndDate());
// 转换并插入合同主表
ContractDO contract = ContractConvert.INSTANCE.convert(createReqVO);
// 生成合同编码
if (contract.getContractCode() == null || contract.getContractCode().isEmpty()) {
contract.setContractCode(generateContractCode());
}
// 设置初始状态
contract.setApprovalStatus(ContractApprovalStatusEnum.DRAFT.getStatus());
contract.setContractStatus(0); // 草稿
contractMapper.insert(contract);
// 保存车辆订单
saveContractVehicles(contract.getId(), createReqVO.getVehicles());
// 保存被授权人
saveContractAuthorized(contract.getId(), createReqVO.getAuthorizedPersons());
// 记录变更历史
saveChangeHistory(contract.getId(), "创建合同", "创建合同:" + contract.getContractCode());
return contract.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateContract(ContractSaveReqVO updateReqVO) {
// 校验存在
ContractDO existContract = validateContractExists(updateReqVO.getId());
// 校验状态:只有草稿、审批拒绝、已撤回状态才能修改
if (!canEdit(existContract.getApprovalStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_UPDATE);
}
// 校验合同日期
validateContractDate(updateReqVO.getStartDate(), updateReqVO.getEndDate());
// 转换并更新合同主表
ContractDO updateObj = ContractConvert.INSTANCE.convert(updateReqVO);
contractMapper.updateById(updateObj);
// 更新车辆订单:先删除旧的,再插入新的
List<ContractVehicleDO> oldVehicles = contractVehicleMapper.selectListByContractId(updateReqVO.getId());
List<Long> oldVehicleIds = oldVehicles.stream().map(ContractVehicleDO::getId).collect(Collectors.toList());
if (!oldVehicleIds.isEmpty()) {
contractVehicleServiceMapper.deleteByContractVehicleIds(oldVehicleIds);
}
contractVehicleMapper.deleteByContractId(updateReqVO.getId());
saveContractVehicles(updateReqVO.getId(), updateReqVO.getVehicles());
// 更新被授权人:先删除旧的,再插入新的
contractAuthorizedMapper.deleteByContractId(updateReqVO.getId());
saveContractAuthorized(updateReqVO.getId(), updateReqVO.getAuthorizedPersons());
// 记录变更历史
saveChangeHistory(updateReqVO.getId(), "更新合同", "更新合同信息");
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteContract(Long id) {
// 校验存在
ContractDO contract = validateContractExists(id);
// 校验状态:只有草稿、审批拒绝、已撤回状态才能删除
if (!canEdit(contract.getApprovalStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_DELETE);
}
// 删除合同主表
contractMapper.deleteById(id);
// 删除关联数据
List<ContractVehicleDO> vehicles = contractVehicleMapper.selectListByContractId(id);
List<Long> vehicleIds = vehicles.stream().map(ContractVehicleDO::getId).collect(Collectors.toList());
if (!vehicleIds.isEmpty()) {
contractVehicleServiceMapper.deleteByContractVehicleIds(vehicleIds);
}
contractVehicleMapper.deleteByContractId(id);
contractAuthorizedMapper.deleteByContractId(id);
contractAttachmentMapper.deleteByContractId(id);
// 记录变更历史
saveChangeHistory(id, "删除合同", "删除合同:" + contract.getContractCode());
}
@Override
public ContractDO getContract(Long id) {
return contractMapper.selectById(id);
}
@Override
public PageResult<ContractDO> getContractPage(ContractPageReqVO pageReqVO) {
return contractMapper.selectPage(pageReqVO);
}
// ==================== 私有方法 ====================
/**
* 校验合同是否存在
*/
private ContractDO validateContractExists(Long id) {
ContractDO contract = contractMapper.selectById(id);
if (contract == null) {
throw exception(CONTRACT_NOT_EXISTS);
}
return contract;
}
/**
* 校验合同日期
*/
private void validateContractDate(java.time.LocalDate startDate, java.time.LocalDate endDate) {
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
throw exception(CONTRACT_END_DATE_BEFORE_START_DATE);
}
}
/**
* 判断是否可以编辑
*/
private boolean canEdit(Integer approvalStatus) {
return ContractApprovalStatusEnum.DRAFT.getStatus().equals(approvalStatus)
|| ContractApprovalStatusEnum.REJECTED.getStatus().equals(approvalStatus)
|| ContractApprovalStatusEnum.WITHDRAWN.getStatus().equals(approvalStatus);
}
/**
* 生成合同编码
*/
private String generateContractCode() {
// 格式HT-YYYY-NNNN
String year = String.valueOf(java.time.LocalDate.now().getYear());
// 查询当年最大序号
String prefix = "HT-" + year + "-";
String maxCode = contractMapper.selectMaxContractCodeByPrefix(prefix);
int nextSeq = 1;
if (maxCode != null && maxCode.startsWith(prefix)) {
try {
String seqStr = maxCode.substring(prefix.length());
nextSeq = Integer.parseInt(seqStr) + 1;
} catch (Exception e) {
log.warn("解析合同编码失败: {}", maxCode, e);
}
}
return prefix + String.format("%04d", nextSeq);
}
/**
* 保存车辆订单
*/
private void saveContractVehicles(Long contractId, List<ContractSaveReqVO.ContractVehicleSaveVO> vehicles) {
if (vehicles == null || vehicles.isEmpty()) {
return;
}
// 获取合同信息用于校验
ContractDO contract = contractMapper.selectById(contractId);
for (ContractSaveReqVO.ContractVehicleSaveVO vehicleVO : vehicles) {
// 校验车辆时间冲突
if (vehicleVO.getVehicleId() != null && contract != null) {
validateVehicleTimeConflict(vehicleVO.getVehicleId(), contract.getStartDate(), contract.getEndDate(), contractId);
}
// 保存车辆订单
ContractVehicleDO vehicle = ContractConvert.INSTANCE.convertVehicle(vehicleVO);
vehicle.setContractId(contractId);
contractVehicleMapper.insert(vehicle);
// 保存服务项目
if (vehicleVO.getServices() != null && !vehicleVO.getServices().isEmpty()) {
List<ContractVehicleServiceDO> services = ContractConvert.INSTANCE.convertServiceList(vehicleVO.getServices());
for (ContractVehicleServiceDO service : services) {
service.setContractVehicleId(vehicle.getId());
contractVehicleServiceMapper.insert(service);
}
}
}
}
/**
* 校验车辆时间冲突
*/
private void validateVehicleTimeConflict(Long vehicleId, java.time.LocalDate startDate, java.time.LocalDate endDate, Long excludeContractId) {
int count = contractMapper.countActiveContractsByVehicleAndDateRange(vehicleId, startDate, endDate);
if (count > 0) {
throw exception(CONTRACT_VEHICLE_TIME_CONFLICT);
}
}
/**
* 保存被授权人
*/
private void saveContractAuthorized(Long contractId, List<ContractAuthorizedVO> authorizedPersons) {
if (authorizedPersons == null || authorizedPersons.isEmpty()) {
return;
}
List<ContractAuthorizedDO> authorizedList = ContractConvert.INSTANCE.convertAuthorizedList(authorizedPersons);
for (ContractAuthorizedDO authorized : authorizedList) {
authorized.setContractId(contractId);
contractAuthorizedMapper.insert(authorized);
}
}
/**
* 保存变更历史
*/
private void saveChangeHistory(Long contractId, String changeType, String changeContent) {
ContractChangeHistoryDO history = new ContractChangeHistoryDO();
history.setContractId(contractId);
history.setChangeType(changeType);
history.setChangeContent(changeContent);
// 获取当前登录用户
Long userId = SecurityFrameworkUtils.getLoginUserId();
history.setOperator(userId != null ? String.valueOf(userId) : "system");
history.setOperateTime(LocalDateTime.now());
contractChangeHistoryMapper.insert(history);
}
@Override
@Transactional(rollbackFor = Exception.class)
public String submitContractApproval(Long id) {
// 校验存在
ContractDO contract = validateContractExists(id);
// 校验状态:只有草稿、审批拒绝、已撤回状态才能提交审批
if (!canEdit(contract.getApprovalStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_SUBMIT);
}
// 创建流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("contractCode", contract.getContractCode());
variables.put("projectName", contract.getProjectName());
variables.put("customerName", contract.getCustomerName());
variables.put("startDate", contract.getStartDate());
variables.put("endDate", contract.getEndDate());
// 创建流程实例
BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
reqDTO.setProcessDefinitionKey(ContractBpmListener.PROCESS_KEY);
reqDTO.setBusinessKey(String.valueOf(id));
reqDTO.setVariables(variables);
Long userId = SecurityFrameworkUtils.getLoginUserId();
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, reqDTO).getData();
// 更新合同状态
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
updateObj.setApprovalStatus(ContractApprovalStatusEnum.APPROVING.getStatus());
updateObj.setBpmInstanceId(processInstanceId);
contractMapper.updateById(updateObj);
// 记录变更历史
saveChangeHistory(id, "提交审批", "提交合同审批流程实例ID" + processInstanceId);
return processInstanceId;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateContractApprovalStatus(Long id, Integer status) {
// 校验存在
ContractDO contract = validateContractExists(id);
// 更新审批状态
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
// 根据 BPM 状态映射到合同审批状态
if (BpmProcessInstanceStatusEnum.RUNNING.getStatus().equals(status)) {
updateObj.setApprovalStatus(ContractApprovalStatusEnum.APPROVING.getStatus());
} else if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(status)) {
updateObj.setApprovalStatus(ContractApprovalStatusEnum.APPROVED.getStatus());
updateObj.setContractStatus(ContractStatusEnum.PENDING.getStatus()); // 待生效
updateObj.setEffectiveTime(LocalDateTime.now());
} else if (BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(status)) {
updateObj.setApprovalStatus(ContractApprovalStatusEnum.REJECTED.getStatus());
} else if (BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(status)) {
updateObj.setApprovalStatus(ContractApprovalStatusEnum.WITHDRAWN.getStatus());
}
contractMapper.updateById(updateObj);
// 记录变更历史
String changeContent = "审批状态变更:" + getApprovalStatusName(updateObj.getApprovalStatus());
saveChangeHistory(id, "审批状态变更", changeContent);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void withdrawContractApproval(Long id) {
// 校验存在
ContractDO contract = validateContractExists(id);
// 校验状态:只有审批中状态才能撤回
if (!ContractApprovalStatusEnum.APPROVING.getStatus().equals(contract.getApprovalStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_WITHDRAW);
}
// 调用 BPM API 取消流程实例
if (contract.getBpmInstanceId() != null) {
BpmProcessInstanceCancelReqDTO cancelReqDTO = new BpmProcessInstanceCancelReqDTO();
cancelReqDTO.setId(contract.getBpmInstanceId());
cancelReqDTO.setReason("合同审批撤回");
Long userId = SecurityFrameworkUtils.getLoginUserId();
bpmProcessInstanceApi.cancelProcessInstance(userId, cancelReqDTO);
}
// 更新合同状态
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
updateObj.setApprovalStatus(ContractApprovalStatusEnum.WITHDRAWN.getStatus());
contractMapper.updateById(updateObj);
// 记录变更历史
saveChangeHistory(id, "撤回审批", "撤回合同审批");
}
/**
* 获取审批状态名称
*/
private String getApprovalStatusName(Integer status) {
ContractApprovalStatusEnum statusEnum = ContractApprovalStatusEnum.valueOf(status);
return statusEnum != null ? statusEnum.getName() : "未知";
}
@Override
@Transactional(rollbackFor = Exception.class)
public void terminateContract(Long id, String reason) {
// 校验存在
ContractDO contract = validateContractExists(id);
// 校验状态:只有进行中的合同才能终止
if (!ContractStatusEnum.IN_PROGRESS.getStatus().equals(contract.getContractStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_TERMINATE);
}
// 更新合同状态
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
updateObj.setContractStatus(ContractStatusEnum.TERMINATED.getStatus());
updateObj.setTerminateTime(LocalDateTime.now());
updateObj.setTerminateReason(reason);
contractMapper.updateById(updateObj);
// 记录变更历史
saveChangeHistory(id, "终止合同", "终止合同,原因:" + reason);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long renewContract(Long id, ContractSaveReqVO newContractReqVO) {
// 校验原合同存在
ContractDO oldContract = validateContractExists(id);
// 校验状态:只有进行中或已到期的合同才能续签
if (!ContractStatusEnum.IN_PROGRESS.getStatus().equals(oldContract.getContractStatus())
&& !ContractStatusEnum.EXPIRED.getStatus().equals(oldContract.getContractStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_RENEW);
}
// 创建新合同
Long newContractId = createContract(newContractReqVO);
// 更新原合同状态
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
updateObj.setContractStatus(ContractStatusEnum.RENEWED.getStatus());
updateObj.setRenewedContractId(newContractId);
contractMapper.updateById(updateObj);
// 更新新合同的原合同ID
ContractDO newContract = new ContractDO();
newContract.setId(newContractId);
newContract.setOriginalContractId(id);
contractMapper.updateById(newContract);
// 记录变更历史
saveChangeHistory(id, "续签合同", "续签合同新合同ID" + newContractId);
saveChangeHistory(newContractId, "续签合同", "由合同ID " + id + " 续签而来");
return newContractId;
}
@Override
public List<ContractDO> getContractSimpleList() {
return contractMapper.selectList();
}
@Override
public ContractDetailRespVO getContractDetail(Long id) {
ContractDO contract = validateContractExists(id);
ContractDetailRespVO result = ContractConvert.INSTANCE.convertDetail(contract);
// 查询车辆订单
List<ContractVehicleDO> vehicles = contractVehicleMapper.selectListByContractId(id);
List<ContractDetailRespVO.ContractVehicleDetailVO> vehicleDetails = ContractConvert.INSTANCE.convertVehicleDetailList(vehicles);
// 查询每个车辆的服务项目
for (int i = 0; i < vehicles.size(); i++) {
List<ContractVehicleServiceDO> services = contractVehicleServiceMapper.selectListByContractVehicleId(vehicles.get(i).getId());
vehicleDetails.get(i).setServices(ContractConvert.INSTANCE.convertServiceVOList(services));
}
result.setVehicles(vehicleDetails);
// 查询被授权人
List<ContractAuthorizedDO> authorized = contractAuthorizedMapper.selectListByContractId(id);
result.setAuthorizedPersons(ContractConvert.INSTANCE.convertAuthorizedVOList(authorized));
// 查询附件
List<ContractAttachmentDO> attachments = contractAttachmentMapper.selectListByContractId(id);
result.setAttachments(ContractConvert.INSTANCE.convertAttachmentVOList(attachments));
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long convertToThirdParty(Long id, ContractSaveReqVO newContractReqVO) {
// 校验原合同存在且进行中
ContractDO oldContract = validateContractExists(id);
if (!ContractStatusEnum.IN_PROGRESS.getStatus().equals(oldContract.getContractStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_CONVERT);
}
// 设置三方合同标记
newContractReqVO.setThirdPartyEnabled(true);
// 创建新合同
Long newContractId = createContract(newContractReqVO);
// 更新新合同的原合同ID
ContractDO newContract = new ContractDO();
newContract.setId(newContractId);
newContract.setOriginalContractId(id);
contractMapper.updateById(newContract);
// 终止原合同
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
updateObj.setContractStatus(ContractStatusEnum.TERMINATED.getStatus());
updateObj.setTerminateTime(LocalDateTime.now());
updateObj.setTerminateReason("变更为三方合同");
contractMapper.updateById(updateObj);
// 记录变更历史
saveChangeHistory(id, "变更为三方", "变更为三方合同新合同ID" + newContractId);
saveChangeHistory(newContractId, "变更为三方", "由合同ID " + id + " 变更而来");
return newContractId;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long convertToFormal(Long id, ContractSaveReqVO newContractReqVO) {
// 校验原合同存在且进行中
ContractDO oldContract = validateContractExists(id);
if (!ContractStatusEnum.IN_PROGRESS.getStatus().equals(oldContract.getContractStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_CONVERT);
}
// 校验原合同为试用合同
if (!Integer.valueOf(1).equals(oldContract.getContractType())) {
throw exception(CONTRACT_TYPE_NOT_TRIAL);
}
// 设置为正式合同
newContractReqVO.setContractType(2);
// 创建新合同
Long newContractId = createContract(newContractReqVO);
// 更新新合同的原合同ID
ContractDO newContract = new ContractDO();
newContract.setId(newContractId);
newContract.setOriginalContractId(id);
contractMapper.updateById(newContract);
// 终止原合同
ContractDO updateObj = new ContractDO();
updateObj.setId(id);
updateObj.setContractStatus(ContractStatusEnum.TERMINATED.getStatus());
updateObj.setTerminateTime(LocalDateTime.now());
updateObj.setTerminateReason("转正式合同");
contractMapper.updateById(updateObj);
// 记录变更历史
saveChangeHistory(id, "转正式", "转正式合同新合同ID" + newContractId);
saveChangeHistory(newContractId, "转正式", "由试用合同ID " + id + " 转正式而来");
return newContractId;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void addVehiclesToContract(Long id, List<ContractSaveReqVO.ContractVehicleSaveVO> vehicles) {
// 校验合同存在且进行中
ContractDO contract = validateContractExists(id);
if (!ContractStatusEnum.IN_PROGRESS.getStatus().equals(contract.getContractStatus())) {
throw exception(CONTRACT_STATUS_NOT_ALLOW_ADD_VEHICLE);
}
// 追加车辆
saveContractVehicles(id, vehicles);
// 记录变更历史
saveChangeHistory(id, "新增车辆", "追加 " + vehicles.size() + " 辆车辆");
}
@Override
@Transactional(rollbackFor = Exception.class)
public void uploadSealedContract(Long id, String fileUrl, String fileName) {
// 校验合同存在
validateContractExists(id);
// 创建附件记录
ContractAttachmentDO attachment = new ContractAttachmentDO();
attachment.setContractId(id);
attachment.setAttachmentType(2); // 盖章合同
attachment.setFileName(fileName);
attachment.setFileUrl(fileUrl);
attachment.setUploadTime(LocalDateTime.now());
Long userId = SecurityFrameworkUtils.getLoginUserId();
attachment.setUploader(userId != null ? String.valueOf(userId) : "system");
contractAttachmentMapper.insert(attachment);
// 记录变更历史
saveChangeHistory(id, "上传盖章合同", "上传盖章合同附件:" + fileName);
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.asset.service.contract.listener;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
import cn.iocoder.yudao.module.asset.service.contract.ContractService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
/**
* 车辆租赁合同审批状态监听器
*
* @author 芋道源码
*/
@Component
public class ContractBpmListener extends BpmProcessInstanceStatusEventListener {
/**
* 流程定义 Key
*/
public static final String PROCESS_KEY = "asset_contract";
@Resource
private ContractService contractService;
@Override
protected String getProcessDefinitionKey() {
return PROCESS_KEY;
}
@Override
protected void onEvent(BpmProcessInstanceStatusEvent event) {
contractService.updateContractApprovalStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
}
}

View File

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.asset.controller.admin.customer.vo.CustomerSaveRe
import cn.iocoder.yudao.module.asset.dal.dataobject.customer.CustomerDO;
import jakarta.validation.Valid;
import java.util.List;
/**
* 客户信息 Service 接口
@@ -52,4 +53,11 @@ public interface CustomerService {
*/
PageResult<CustomerDO> getCustomerPage(CustomerPageReqVO pageReqVO);
/**
* 获得客户精简列表(用于下拉选择)
*
* @return 客户列表
*/
List<CustomerDO> getCustomerSimpleList();
}

View File

@@ -98,6 +98,11 @@ public class CustomerServiceImpl implements CustomerService {
return customerMapper.selectPage(pageReqVO);
}
@Override
public List<CustomerDO> getCustomerSimpleList() {
return customerMapper.selectList();
}
/**
* 生成客户编号
*/

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.asset.service.delivery;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryOrderPageReqVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryOrderRespVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryOrderSaveReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderDO;
import jakarta.validation.Valid;
public interface DeliveryOrderService {
Long createDeliveryOrder(@Valid DeliveryOrderSaveReqVO createReqVO);
void updateDeliveryOrder(@Valid DeliveryOrderSaveReqVO updateReqVO);
void deleteDeliveryOrder(Long id);
DeliveryOrderDO getDeliveryOrder(Long id);
DeliveryOrderRespVO getDeliveryOrderDetail(Long id);
PageResult<DeliveryOrderDO> getDeliveryOrderPage(DeliveryOrderPageReqVO pageReqVO);
void completeDeliveryOrder(Long id);
}

View File

@@ -8,6 +8,8 @@ import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordD
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.*;
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
import cn.iocoder.yudao.module.asset.service.delivery.event.DeliveryCompletedEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -37,6 +39,9 @@ public class DeliveryOrderServiceImpl implements DeliveryOrderService {
@Resource
private InspectionRecordService inspectionRecordService;
@Resource
private ApplicationEventPublisher eventPublisher;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createDeliveryOrder(DeliveryOrderSaveReqVO createReqVO) {
@@ -169,6 +174,11 @@ public class DeliveryOrderServiceImpl implements DeliveryOrderService {
deliveryTaskMapper.updateById(DeliveryTaskDO.builder().id(task.getId()).deliveryStatus(1).build());
}
}
// Publish delivery completed events for each vehicle
for (DeliveryOrderVehicleDO ov : orderVehicles) {
eventPublisher.publishEvent(new DeliveryCompletedEvent(id, ov.getVehicleId()));
}
}
private DeliveryOrderDO validateDeliveryOrderExists(Long id) {

View File

@@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.asset.service.delivery;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskActivateReqVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskContractGroupRespVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskPageReqVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskRespVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskSaveReqVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryTaskDO;
import jakarta.validation.Valid;
import java.util.List;
public interface DeliveryTaskService {
Long createDeliveryTask(@Valid DeliveryTaskSaveReqVO createReqVO);
void updateDeliveryTask(@Valid DeliveryTaskSaveReqVO updateReqVO);
void deleteDeliveryTask(Long id);
DeliveryTaskDO getDeliveryTask(Long id);
DeliveryTaskRespVO getDeliveryTaskDetail(Long id);
PageResult<DeliveryTaskDO> getDeliveryTaskPage(DeliveryTaskPageReqVO pageReqVO);
void suspendDeliveryTask(Long id);
void activateDeliveryTask(Long id);
/**
* 激活交车任务(带日期参数)
*/
void activateDeliveryTask(DeliveryTaskActivateReqVO reqVO);
/**
* 获得按合同分组的交车任务分页
*/
PageResult<DeliveryTaskContractGroupRespVO> getDeliveryTaskContractPage(DeliveryTaskPageReqVO pageReqVO);
List<DeliveryTaskDO> getDeliveryTaskSimpleList();
}

View File

@@ -0,0 +1,264 @@
package cn.iocoder.yudao.module.asset.service.delivery;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.*;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskActivateReqVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskContractGroupRespVO;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.DeliveryTaskVehicleVO;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryTaskDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryTaskVehicleDO;
import cn.iocoder.yudao.module.asset.dal.mysql.contract.ContractMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryTaskMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryTaskVehicleMapper;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
@Service
@Validated
public class DeliveryTaskServiceImpl implements DeliveryTaskService {
@Resource
private DeliveryTaskMapper deliveryTaskMapper;
@Resource
private DeliveryTaskVehicleMapper deliveryTaskVehicleMapper;
@Resource
private ContractMapper contractMapper;
@Resource
private DeptApi deptApi;
@Resource
private AdminUserApi adminUserApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createDeliveryTask(DeliveryTaskSaveReqVO createReqVO) {
// 校验合同是否存在
if (contractMapper.selectById(createReqVO.getContractId()) == null) {
throw exception(CONTRACT_NOT_EXISTS);
}
// Generate task code: contractCode + JC + sequence
String taskCode = generateTaskCode(createReqVO.getContractId(), createReqVO.getContractCode());
DeliveryTaskDO task = BeanUtils.toBean(createReqVO, DeliveryTaskDO.class);
task.setTaskCode(taskCode);
task.setTaskStatus(0); // active
task.setDeliveryStatus(0); // not delivered
task.setVehicleCount(createReqVO.getVehicles() != null ? createReqVO.getVehicles().size() : 0);
deliveryTaskMapper.insert(task);
// Insert vehicles
if (createReqVO.getVehicles() != null) {
for (DeliveryTaskVehicleVO vehicleVO : createReqVO.getVehicles()) {
DeliveryTaskVehicleDO vehicle = BeanUtils.toBean(vehicleVO, DeliveryTaskVehicleDO.class);
vehicle.setTaskId(task.getId());
vehicle.setIsDelivered(false);
deliveryTaskVehicleMapper.insert(vehicle);
}
}
return task.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateDeliveryTask(DeliveryTaskSaveReqVO updateReqVO) {
DeliveryTaskDO task = validateDeliveryTaskExists(updateReqVO.getId());
if (task.getDeliveryStatus().equals(1)) {
throw exception(DELIVERY_TASK_ALREADY_DELIVERED);
}
DeliveryTaskDO updateObj = BeanUtils.toBean(updateReqVO, DeliveryTaskDO.class);
updateObj.setVehicleCount(updateReqVO.getVehicles() != null ? updateReqVO.getVehicles().size() : 0);
deliveryTaskMapper.updateById(updateObj);
// Update vehicles: delete old, insert new
if (updateReqVO.getVehicles() != null) {
deliveryTaskVehicleMapper.deleteByTaskId(updateReqVO.getId());
for (DeliveryTaskVehicleVO vehicleVO : updateReqVO.getVehicles()) {
DeliveryTaskVehicleDO vehicle = BeanUtils.toBean(vehicleVO, DeliveryTaskVehicleDO.class);
vehicle.setTaskId(updateReqVO.getId());
vehicle.setIsDelivered(false);
deliveryTaskVehicleMapper.insert(vehicle);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteDeliveryTask(Long id) {
validateDeliveryTaskExists(id);
deliveryTaskMapper.deleteById(id);
deliveryTaskVehicleMapper.deleteByTaskId(id);
}
@Override
public DeliveryTaskDO getDeliveryTask(Long id) {
return deliveryTaskMapper.selectById(id);
}
@Override
public DeliveryTaskRespVO getDeliveryTaskDetail(Long id) {
DeliveryTaskDO task = validateDeliveryTaskExists(id);
DeliveryTaskRespVO respVO = BeanUtils.toBean(task, DeliveryTaskRespVO.class);
List<DeliveryTaskVehicleDO> vehicles = deliveryTaskVehicleMapper.selectListByTaskId(id);
respVO.setVehicles(BeanUtils.toBean(vehicles, DeliveryTaskVehicleVO.class));
return respVO;
}
@Override
public PageResult<DeliveryTaskDO> getDeliveryTaskPage(DeliveryTaskPageReqVO pageReqVO) {
return deliveryTaskMapper.selectPage(pageReqVO);
}
@Override
public void suspendDeliveryTask(Long id) {
DeliveryTaskDO task = validateDeliveryTaskExists(id);
if (task.getDeliveryStatus().equals(1)) {
throw exception(DELIVERY_TASK_ALREADY_DELIVERED);
}
deliveryTaskMapper.updateById(DeliveryTaskDO.builder().id(id).taskStatus(1).build());
}
@Override
public void activateDeliveryTask(Long id) {
validateDeliveryTaskExists(id);
deliveryTaskMapper.updateById(DeliveryTaskDO.builder().id(id).taskStatus(0).build());
}
@Override
public void activateDeliveryTask(DeliveryTaskActivateReqVO reqVO) {
validateDeliveryTaskExists(reqVO.getId());
DeliveryTaskDO updateObj = DeliveryTaskDO.builder()
.id(reqVO.getId())
.taskStatus(0)
.expectedDeliveryDateStart(reqVO.getExpectedDeliveryDateStart())
.expectedDeliveryDateEnd(reqVO.getExpectedDeliveryDateEnd())
.billingStartDate(reqVO.getBillingStartDate())
.build();
deliveryTaskMapper.updateById(updateObj);
}
@Override
public PageResult<DeliveryTaskContractGroupRespVO> getDeliveryTaskContractPage(DeliveryTaskPageReqVO pageReqVO) {
// 1. 查询所有匹配的交车任务
List<DeliveryTaskDO> allTasks = deliveryTaskMapper.selectListByFilters(pageReqVO);
if (allTasks.isEmpty()) {
return new PageResult<>(Collections.emptyList(), 0L);
}
// 2. 按合同 ID 分组
Map<Long, List<DeliveryTaskDO>> groupedByContract = allTasks.stream()
.collect(Collectors.groupingBy(DeliveryTaskDO::getContractId,
LinkedHashMap::new, Collectors.toList()));
// 3. 对合同分组进行分页
List<Long> contractIds = new ArrayList<>(groupedByContract.keySet());
long total = contractIds.size();
int start = (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize();
int end = Math.min(start + pageReqVO.getPageSize(), contractIds.size());
if (start >= contractIds.size()) {
return new PageResult<>(Collections.emptyList(), total);
}
List<Long> pageContractIds = contractIds.subList(start, end);
// 4. 批量查询合同信息
List<ContractDO> contracts = contractMapper.selectBatchIds(pageContractIds);
Map<Long, ContractDO> contractMap = contracts.stream()
.collect(Collectors.toMap(ContractDO::getId, c -> c, (a, b) -> a));
// 5. 批量查询部门和用户名称
Set<Long> deptIds = new HashSet<>();
Set<Long> userIds = new HashSet<>();
contracts.forEach(c -> {
if (c.getBusinessDeptId() != null) deptIds.add(c.getBusinessDeptId());
if (c.getBusinessManagerId() != null) userIds.add(c.getBusinessManagerId());
});
Map<Long, DeptRespDTO> deptMap = deptIds.isEmpty() ? Collections.emptyMap() : deptApi.getDeptMap(deptIds);
Map<Long, AdminUserRespDTO> userMap = userIds.isEmpty() ? Collections.emptyMap() : adminUserApi.getUserMap(userIds);
// 6. 批量查询车辆信息(用于 popover 展示)
List<Long> taskIds = pageContractIds.stream()
.flatMap(cid -> groupedByContract.get(cid).stream())
.map(DeliveryTaskDO::getId)
.toList();
List<DeliveryTaskVehicleDO> allVehicles = taskIds.isEmpty() ? Collections.emptyList()
: deliveryTaskVehicleMapper.selectList(
new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<DeliveryTaskVehicleDO>()
.in(DeliveryTaskVehicleDO::getTaskId, taskIds));
Map<Long, List<DeliveryTaskVehicleDO>> vehiclesByTask = allVehicles.stream()
.collect(Collectors.groupingBy(DeliveryTaskVehicleDO::getTaskId));
// 7. 组装响应
List<DeliveryTaskContractGroupRespVO> result = new ArrayList<>();
for (Long contractId : pageContractIds) {
DeliveryTaskContractGroupRespVO group = new DeliveryTaskContractGroupRespVO();
ContractDO contract = contractMap.get(contractId);
if (contract != null) {
group.setContractId(contract.getId());
group.setContractCode(contract.getContractCode());
group.setProjectName(contract.getProjectName());
group.setCustomerName(contract.getCustomerName());
group.setStartDate(contract.getStartDate());
group.setEndDate(contract.getEndDate());
DeptRespDTO dept = deptMap.get(contract.getBusinessDeptId());
group.setBusinessDeptName(dept != null ? dept.getName() : null);
AdminUserRespDTO user = userMap.get(contract.getBusinessManagerId());
group.setBusinessManagerName(user != null ? user.getNickname() : null);
} else {
DeliveryTaskDO firstTask = groupedByContract.get(contractId).get(0);
group.setContractId(contractId);
group.setContractCode(firstTask.getContractCode());
group.setProjectName(firstTask.getProjectName());
group.setCustomerName(firstTask.getCustomerName());
}
List<DeliveryTaskRespVO> taskVOs = groupedByContract.get(contractId).stream().map(task -> {
DeliveryTaskRespVO vo = BeanUtils.toBean(task, DeliveryTaskRespVO.class);
List<DeliveryTaskVehicleDO> vehicles = vehiclesByTask.getOrDefault(task.getId(), Collections.emptyList());
vo.setVehicles(BeanUtils.toBean(vehicles, DeliveryTaskVehicleVO.class));
return vo;
}).toList();
group.setTasks(taskVOs);
result.add(group);
}
return new PageResult<>(result, total);
}
@Override
public List<DeliveryTaskDO> getDeliveryTaskSimpleList() {
return deliveryTaskMapper.selectList();
}
private DeliveryTaskDO validateDeliveryTaskExists(Long id) {
DeliveryTaskDO task = deliveryTaskMapper.selectById(id);
if (task == null) {
throw exception(DELIVERY_TASK_NOT_EXISTS);
}
return task;
}
private String generateTaskCode(Long contractId, String contractCode) {
long count = deliveryTaskMapper.selectCountByContractId(contractId);
return contractCode + "JC" + String.format("%04d", count + 1);
}
}

Some files were not shown because too many files have changed in this diff Show More