diff --git a/ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java b/ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java index b6bda76..1afc0c4 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java @@ -140,6 +140,18 @@ public class MydoJob extends BaseEntity /** 通道匹配物料名称(非持久化字段) */ private String productName; + /** WCS 下发状态(非持久化字段) */ + private String dispatchStatus; + + /** WCS 自动重试次数(非持久化字段) */ + private Integer autoRetryCount; + + /** WCS 人工下发次数(非持久化字段) */ + private Integer manualRetryCount; + + /** WCS 最后一次下发错误(非持久化字段) */ + private String lastDispatchError; + public void setJobId(String jobId) { this.jobId = jobId; @@ -490,6 +502,46 @@ public class MydoJob extends BaseEntity this.productName = productName; } + public String getDispatchStatus() + { + return dispatchStatus; + } + + public void setDispatchStatus(String dispatchStatus) + { + this.dispatchStatus = dispatchStatus; + } + + public Integer getAutoRetryCount() + { + return autoRetryCount; + } + + public void setAutoRetryCount(Integer autoRetryCount) + { + this.autoRetryCount = autoRetryCount; + } + + public Integer getManualRetryCount() + { + return manualRetryCount; + } + + public void setManualRetryCount(Integer manualRetryCount) + { + this.manualRetryCount = manualRetryCount; + } + + public String getLastDispatchError() + { + return lastDispatchError; + } + + public void setLastDispatchError(String lastDispatchError) + { + this.lastDispatchError = lastDispatchError; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) @@ -529,6 +581,10 @@ public class MydoJob extends BaseEntity .append("projectNo", getProjectNo()) .append("productId", getProductId()) .append("productName", getProductName()) + .append("dispatchStatus", getDispatchStatus()) + .append("autoRetryCount", getAutoRetryCount()) + .append("manualRetryCount", getManualRetryCount()) + .append("lastDispatchError", getLastDispatchError()) .toString(); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/WcsJobDispatch.java b/ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/WcsJobDispatch.java new file mode 100644 index 0000000..6dff221 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/WcsJobDispatch.java @@ -0,0 +1,141 @@ +package com.ruoyi.out.dispatch.domain; + +import java.io.Serializable; +import java.util.Date; + +/** + * WCS 作业下发记录。 + */ +public class WcsJobDispatch implements Serializable +{ + private static final long serialVersionUID = 1L; + + public static final String PENDING = "PENDING"; + public static final String SENDING = "SENDING"; + public static final String BLOCKED = "BLOCKED"; + public static final String RETRY_WAIT = "RETRY_WAIT"; + public static final String SUCCESS = "SUCCESS"; + public static final String EXHAUSTED = "EXHAUSTED"; + + private String jobId; + private String dispatchStatus; + private Integer autoRetryCount; + private Integer manualRetryCount; + private String lastError; + private Date lastAttemptTime; + private Date nextRetryTime; + private Date successTime; + private Integer versionNo; + private Date createTime; + private Date updateTime; + + public String getJobId() + { + return jobId; + } + + public void setJobId(String jobId) + { + this.jobId = jobId; + } + + public String getDispatchStatus() + { + return dispatchStatus; + } + + public void setDispatchStatus(String dispatchStatus) + { + this.dispatchStatus = dispatchStatus; + } + + public Integer getAutoRetryCount() + { + return autoRetryCount; + } + + public void setAutoRetryCount(Integer autoRetryCount) + { + this.autoRetryCount = autoRetryCount; + } + + public Integer getManualRetryCount() + { + return manualRetryCount; + } + + public void setManualRetryCount(Integer manualRetryCount) + { + this.manualRetryCount = manualRetryCount; + } + + public String getLastError() + { + return lastError; + } + + public void setLastError(String lastError) + { + this.lastError = lastError; + } + + public Date getLastAttemptTime() + { + return lastAttemptTime; + } + + public void setLastAttemptTime(Date lastAttemptTime) + { + this.lastAttemptTime = lastAttemptTime; + } + + public Date getNextRetryTime() + { + return nextRetryTime; + } + + public void setNextRetryTime(Date nextRetryTime) + { + this.nextRetryTime = nextRetryTime; + } + + public Date getSuccessTime() + { + return successTime; + } + + public void setSuccessTime(Date successTime) + { + this.successTime = successTime; + } + + public Integer getVersionNo() + { + return versionNo; + } + + public void setVersionNo(Integer versionNo) + { + this.versionNo = versionNo; + } + + public Date getCreateTime() + { + return createTime; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } + + public Date getUpdateTime() + { + return updateTime; + } + + public void setUpdateTime(Date updateTime) + { + this.updateTime = updateTime; + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapper.java b/ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapper.java new file mode 100644 index 0000000..db62c28 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapper.java @@ -0,0 +1,29 @@ +package com.ruoyi.out.dispatch.mapper; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import org.apache.ibatis.annotations.Param; +import com.ruoyi.out.dispatch.domain.WcsJobDispatch; + +/** + * WCS 作业下发记录 Mapper。 + */ +public interface WcsJobDispatchMapper +{ + int insertIfAbsent(String jobId); + + WcsJobDispatch selectByJobId(String jobId); + + List selectRetryCandidates(@Param("now") Date now, @Param("limit") int limit); + + int claimForSend(Map params); + + int markBlocked(Map params); + + int markRetryWait(Map params); + + int markSuccess(Map params); + + int markExhausted(Map params); +} diff --git a/ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml b/ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml index d091c83..4ab6875 100644 --- a/ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml +++ b/ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml @@ -36,12 +36,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + - select job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id, + select mydo_job.job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id, isnull(nullif(warehouse_name, ''), (select top 1 bw.warehouse_name from bas_warehouse bw where bw.warehouse_id = mydo_job.warehouse_id)) as warehouse_name, - roadway_id, cargo_space_id, cargo_space_name, target_roadway_id, target_cargo_space_id, target_cargo_space_name, line_type, priority, height, weight, create_time, start_time, finish_time, entrance_id, exit_id, dept_id, dept_name, user_id, user_name, supplier_id, supplier_name, customer_id, customer_name from mydo_job + roadway_id, cargo_space_id, cargo_space_name, target_roadway_id, target_cargo_space_id, target_cargo_space_name, line_type, priority, height, weight, mydo_job.create_time, start_time, finish_time, entrance_id, exit_id, dept_id, dept_name, user_id, user_name, supplier_id, supplier_name, customer_id, customer_name, + wjd.dispatch_status as dispatch_status, wjd.auto_retry_count as auto_retry_count, + wjd.manual_retry_count as manual_retry_count, wjd.last_error as last_dispatch_error + from mydo_job + left join wcs_job_dispatch wjd on wjd.job_id = mydo_job.job_id select job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id, @@ -79,7 +87,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + select job_id, dispatch_status, auto_retry_count, manual_retry_count, last_error, + last_attempt_time, next_retry_time, success_time, version_no, create_time, update_time + from wcs_job_dispatch + where job_id = #{jobId} + + + + + + update wcs_job_dispatch + set dispatch_status = 'SENDING', + auto_retry_count = auto_retry_count + case when #{trigger} = 'AUTO_RETRY' then 1 else 0 end, + manual_retry_count = manual_retry_count + case when #{trigger} = 'MANUAL' then 1 else 0 end, + last_attempt_time = #{attemptTime}, + next_retry_time = null, + update_time = #{attemptTime}, + version_no = version_no + 1 + where job_id = #{jobId} + and version_no = #{versionNo} + and dispatch_status in ('PENDING', 'BLOCKED', 'RETRY_WAIT', 'EXHAUSTED', 'SENDING') + and (#{trigger} != 'AUTO_RETRY' or auto_retry_count < 5) + + + + update wcs_job_dispatch + set dispatch_status = 'BLOCKED', last_error = #{lastError}, next_retry_time = #{nextRetryTime}, + update_time = #{updateTime}, version_no = version_no + 1 + where job_id = #{jobId} and dispatch_status != 'SUCCESS' + + + + update wcs_job_dispatch + set dispatch_status = 'RETRY_WAIT', last_error = #{lastError}, next_retry_time = #{nextRetryTime}, + update_time = #{updateTime}, version_no = version_no + 1 + where job_id = #{jobId} and dispatch_status = 'SENDING' + + + + update wcs_job_dispatch + set dispatch_status = 'SUCCESS', last_error = null, next_retry_time = null, + success_time = #{successTime}, update_time = #{successTime}, version_no = version_no + 1 + where job_id = #{jobId} and dispatch_status = 'SENDING' + + + + update wcs_job_dispatch + set dispatch_status = 'EXHAUSTED', last_error = #{lastError}, next_retry_time = null, + update_time = #{updateTime}, version_no = version_no + 1 + where job_id = #{jobId} and dispatch_status = 'SENDING' + + diff --git a/ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java b/ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java new file mode 100644 index 0000000..fe1f7b5 --- /dev/null +++ b/ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java @@ -0,0 +1,81 @@ +package com.ruoyi.out.dispatch.mapper; + +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class WcsJobDispatchMapperSqlTest +{ + @Test + void dispatchMapperDefinesDurableRetryStateTransitions() throws Exception + { + String xml = Files.readString(resolvePath( + "src/main/resources/mapper/out/WcsJobDispatchMapper.xml", + "ruoyi-admin/src/main/resources/mapper/out/WcsJobDispatchMapper.xml")); + + assertThat(xml) + .contains("PENDING") + .contains("SENDING") + .contains("BLOCKED") + .contains("RETRY_WAIT") + .contains("SUCCESS") + .contains("EXHAUSTED") + .contains("auto_retry_count < 5") + .contains("dispatch_status = 'SENDING'") + .contains("version_no = version_no + 1") + .contains("selectRetryCandidates") + .contains("claimForSend") + .contains("markRetryWait") + .contains("markExhausted"); + } + + @Test + void migrationCreatesRetryTaskRelocationTypeAndDenseLaneMenu() throws Exception + { + String sql = Files.readString(resolvePath( + "../sql/20260716_dense_outbound_relocation_dispatch.sql", + "sql/20260716_dense_outbound_relocation_dispatch.sql")); + + assertThat(sql) + .contains("CREATE TABLE dbo.wcs_job_dispatch") + .contains("IF NOT EXISTS") + .contains("auto_retry_count") + .contains("manual_retry_count") + .contains("last_error") + .contains("wcsOutboundRetryTask.retryFailedJobs") + .contains("0 0/1 * * * ?") + .contains("out:denseLaneOutbound:list") + .contains("out:denseLaneOutbound:preview") + .contains("out:denseLaneOutbound:generate") + .contains("out:job:pushWcs") + .contains("N'23'") + .contains("N'移库'"); + } + + @Test + void outboundJobQueriesExposeDispatchState() throws Exception + { + String xml = Files.readString(resolvePath( + "src/main/resources/mapper/in/MydoJobMapper.xml", + "ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml")); + + assertThat(xml) + .contains("left join wcs_job_dispatch") + .contains("dispatchStatus") + .contains("autoRetryCount") + .contains("manualRetryCount") + .contains("lastDispatchError"); + } + + private Path resolvePath(String modulePath, String rootPath) + { + return Stream.of(Path.of(modulePath), Path.of(rootPath)) + .filter(Files::exists) + .findFirst() + .orElseThrow(); + } +} diff --git a/sql/20260716_dense_outbound_relocation_dispatch.sql b/sql/20260716_dense_outbound_relocation_dispatch.sql new file mode 100644 index 0000000..7a12fdf --- /dev/null +++ b/sql/20260716_dense_outbound_relocation_dispatch.sql @@ -0,0 +1,280 @@ +-- 密集库出库、移库及 WCS 下发补偿 +-- 目标库:FTC25009-WMS + +SET NOCOUNT ON; + +IF OBJECT_ID(N'dbo.wcs_job_dispatch', N'U') IS NULL +BEGIN + CREATE TABLE dbo.wcs_job_dispatch + ( + job_id nvarchar(255) NOT NULL, + dispatch_status nvarchar(20) NOT NULL CONSTRAINT DF_wcs_job_dispatch_status DEFAULT N'PENDING', + auto_retry_count int NOT NULL CONSTRAINT DF_wcs_job_dispatch_auto_retry DEFAULT 0, + manual_retry_count int NOT NULL CONSTRAINT DF_wcs_job_dispatch_manual_retry DEFAULT 0, + last_error nvarchar(1000) NULL, + last_attempt_time datetime2 NULL, + next_retry_time datetime2 NULL, + success_time datetime2 NULL, + version_no int NOT NULL CONSTRAINT DF_wcs_job_dispatch_version DEFAULT 0, + create_time datetime2 NOT NULL CONSTRAINT DF_wcs_job_dispatch_create_time DEFAULT SYSDATETIME(), + update_time datetime2 NOT NULL CONSTRAINT DF_wcs_job_dispatch_update_time DEFAULT SYSDATETIME(), + CONSTRAINT PK_wcs_job_dispatch PRIMARY KEY CLUSTERED (job_id), + CONSTRAINT CK_wcs_job_dispatch_status CHECK + (dispatch_status IN (N'PENDING', N'SENDING', N'BLOCKED', N'RETRY_WAIT', N'SUCCESS', N'EXHAUSTED')), + CONSTRAINT CK_wcs_job_dispatch_auto_retry CHECK (auto_retry_count BETWEEN 0 AND 5), + CONSTRAINT CK_wcs_job_dispatch_manual_retry CHECK (manual_retry_count >= 0) + ); +END +GO + +IF NOT EXISTS +( + SELECT 1 FROM sys.indexes + WHERE object_id = OBJECT_ID(N'dbo.wcs_job_dispatch') + AND name = N'IX_wcs_job_dispatch_retry' +) +BEGIN + CREATE NONCLUSTERED INDEX IX_wcs_job_dispatch_retry + ON dbo.wcs_job_dispatch (dispatch_status, next_retry_time, auto_retry_count, create_time) + INCLUDE (version_no); +END +GO + +IF NOT EXISTS +( + SELECT 1 FROM sys.indexes + WHERE object_id = OBJECT_ID(N'dbo.mydo_job') + AND name = N'IX_mydo_job_dense_dispatch' +) +BEGIN + CREATE NONCLUSTERED INDEX IX_mydo_job_dense_dispatch + ON dbo.mydo_job (warehouse_id, cargo_space_id, in_or_out, status, execution_phase) + INCLUDE (job_id, tray_code, task_no); +END +GO + +IF NOT EXISTS (SELECT 1 FROM dbo.bas_task_no WHERE id = N'23') +BEGIN + INSERT INTO dbo.bas_task_no (id, task_type, type_name, task_no, min_no, max_no) + VALUES (N'23', N'23', N'移库', 90000, 90001, 99999); +END +ELSE +BEGIN + UPDATE dbo.bas_task_no + SET task_type = N'23', type_name = N'移库' + WHERE id = N'23'; +END +GO + +DECLARE @retryJobId bigint; +DECLARE @retryJobIdIsIdentity bit = COLUMNPROPERTY(OBJECT_ID(N'dbo.sys_job'), 'job_id', 'IsIdentity'); + +SELECT TOP 1 @retryJobId = job_id +FROM dbo.sys_job +WHERE invoke_target = N'wcsOutboundRetryTask.retryFailedJobs()'; + +IF @retryJobId IS NULL +BEGIN + SELECT @retryJobId = ISNULL(MAX(job_id), 0) + 1 FROM dbo.sys_job; + + IF @retryJobIdIsIdentity = 1 + SET IDENTITY_INSERT dbo.sys_job ON; + + INSERT INTO dbo.sys_job + ( + job_id, job_name, job_group, invoke_target, cron_expression, + misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark + ) + VALUES + ( + @retryJobId, N'WCS出库下发失败补偿', N'DEFAULT', N'wcsOutboundRetryTask.retryFailedJobs()', N'0 0/1 * * * ?', + N'3', N'1', N'0', N'admin', GETDATE(), N'', NULL, N'每分钟补偿失败或被密集库遮挡的出库作业' + ); + + IF @retryJobIdIsIdentity = 1 + SET IDENTITY_INSERT dbo.sys_job OFF; +END +ELSE +BEGIN + UPDATE dbo.sys_job + SET job_name = N'WCS出库下发失败补偿', + job_group = N'DEFAULT', + cron_expression = N'0 0/1 * * * ?', + misfire_policy = N'3', + concurrent = N'1', + status = N'0', + update_by = N'admin', + update_time = GETDATE(), + remark = N'每分钟补偿失败或被密集库遮挡的出库作业' + WHERE job_id = @retryJobId; +END +GO + +DECLARE @outMenuId bigint; +DECLARE @denseMenuId bigint; +DECLARE @previewMenuId bigint; +DECLARE @generateMenuId bigint; +DECLARE @outJobMenuId bigint; +DECLARE @pushWcsMenuId bigint; +DECLARE @menuIdIsIdentity bit = COLUMNPROPERTY(OBJECT_ID(N'dbo.sys_menu'), 'menu_id', 'IsIdentity'); + +SELECT TOP 1 @outMenuId = menu_id +FROM dbo.sys_menu +WHERE menu_type = N'M' AND (path = N'out' OR menu_name = N'出库管理') +ORDER BY CASE WHEN menu_id = 2001 THEN 0 ELSE 1 END, menu_id; + +IF @outMenuId IS NULL + SET @outMenuId = 2001; + +SELECT TOP 1 @denseMenuId = menu_id +FROM dbo.sys_menu +WHERE menu_type = N'C' + AND (perms = N'out:denseLaneOutbound:list' + OR (path = N'denseLaneOutbound' AND component = N'out/denseLaneOutbound/index')); + +IF @denseMenuId IS NULL +BEGIN + SELECT @denseMenuId = ISNULL(MAX(menu_id), 2200) + 1 FROM dbo.sys_menu; +END + +SELECT TOP 1 @previewMenuId = menu_id +FROM dbo.sys_menu +WHERE menu_type = N'F' AND perms = N'out:denseLaneOutbound:preview'; + +IF @previewMenuId IS NULL +BEGIN + SELECT @previewMenuId = ISNULL(MAX(menu_id), @denseMenuId) + 1 FROM dbo.sys_menu; + WHILE @previewMenuId IN (@denseMenuId) OR EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @previewMenuId) + SET @previewMenuId = @previewMenuId + 1; +END + +SELECT TOP 1 @generateMenuId = menu_id +FROM dbo.sys_menu +WHERE menu_type = N'F' AND perms = N'out:denseLaneOutbound:generate'; + +IF @generateMenuId IS NULL +BEGIN + SET @generateMenuId = @previewMenuId + 1; + WHILE @generateMenuId IN (@denseMenuId, @previewMenuId) OR EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @generateMenuId) + SET @generateMenuId = @generateMenuId + 1; +END + +SELECT TOP 1 @outJobMenuId = menu_id +FROM dbo.sys_menu +WHERE menu_type = N'C' AND perms = N'out:job:list' +ORDER BY menu_id; + +SELECT TOP 1 @pushWcsMenuId = menu_id +FROM dbo.sys_menu +WHERE menu_type = N'F' AND perms = N'out:job:pushWcs'; + +IF @pushWcsMenuId IS NULL +BEGIN + SET @pushWcsMenuId = @generateMenuId + 1; + WHILE @pushWcsMenuId IN (@denseMenuId, @previewMenuId, @generateMenuId) + OR EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @pushWcsMenuId) + SET @pushWcsMenuId = @pushWcsMenuId + 1; +END + +IF @menuIdIsIdentity = 1 + SET IDENTITY_INSERT dbo.sys_menu ON; + +IF NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @denseMenuId) +BEGIN + INSERT INTO dbo.sys_menu + ( + menu_id, menu_name, parent_id, order_num, path, component, query, route_name, + is_frame, is_cache, menu_type, visible, status, perms, icon, + create_by, create_time, update_by, update_time, remark + ) + VALUES + ( + @denseMenuId, N'指定通道出库', @outMenuId, 5, N'denseLaneOutbound', N'out/denseLaneOutbound/index', NULL, N'', + 1, 0, N'C', N'0', N'0', N'out:denseLaneOutbound:list', N'table', + N'admin', GETDATE(), N'', NULL, N'03仓密集库按通道生成端头托盘出库作业' + ); +END +ELSE +BEGIN + UPDATE dbo.sys_menu + SET menu_name = N'指定通道出库', parent_id = @outMenuId, order_num = 5, + path = N'denseLaneOutbound', component = N'out/denseLaneOutbound/index', + perms = N'out:denseLaneOutbound:list', icon = N'table', visible = N'0', status = N'0', + update_by = N'admin', update_time = GETDATE() + WHERE menu_id = @denseMenuId; +END + +IF NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @previewMenuId) +BEGIN + INSERT INTO dbo.sys_menu + ( + menu_id, menu_name, parent_id, order_num, path, component, query, route_name, + is_frame, is_cache, menu_type, visible, status, perms, icon, + create_by, create_time, update_by, update_time, remark + ) + VALUES + ( + @previewMenuId, N'预览通道出库', @denseMenuId, 1, N'#', N'', NULL, N'', + 1, 0, N'F', N'0', N'0', N'out:denseLaneOutbound:preview', N'#', + N'admin', GETDATE(), N'', NULL, N'' + ); +END + +IF NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @generateMenuId) +BEGIN + INSERT INTO dbo.sys_menu + ( + menu_id, menu_name, parent_id, order_num, path, component, query, route_name, + is_frame, is_cache, menu_type, visible, status, perms, icon, + create_by, create_time, update_by, update_time, remark + ) + VALUES + ( + @generateMenuId, N'生成通道出库', @denseMenuId, 2, N'#', N'', NULL, N'', + 1, 0, N'F', N'0', N'0', N'out:denseLaneOutbound:generate', N'#', + N'admin', GETDATE(), N'', NULL, N'' + ); +END + +IF @outJobMenuId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @pushWcsMenuId) +BEGIN + INSERT INTO dbo.sys_menu + ( + menu_id, menu_name, parent_id, order_num, path, component, query, route_name, + is_frame, is_cache, menu_type, visible, status, perms, icon, + create_by, create_time, update_by, update_time, remark + ) + VALUES + ( + @pushWcsMenuId, N'手动下发WCS', @outJobMenuId, 6, N'#', N'', NULL, N'', + 1, 0, N'F', N'0', N'0', N'out:job:pushWcs', N'#', + N'admin', GETDATE(), N'', NULL, N'' + ); +END + +IF @menuIdIsIdentity = 1 + SET IDENTITY_INSERT dbo.sys_menu OFF; + +IF OBJECT_ID(N'dbo.sys_role_menu', N'U') IS NOT NULL +BEGIN + INSERT INTO dbo.sys_role_menu (role_id, menu_id) + SELECT DISTINCT rm.role_id, permission_menu.menu_id + FROM dbo.sys_role_menu rm + CROSS APPLY (VALUES (@denseMenuId), (@previewMenuId), (@generateMenuId)) permission_menu(menu_id) + WHERE rm.menu_id = @outMenuId + AND NOT EXISTS + (SELECT 1 FROM dbo.sys_role_menu current_rm + WHERE current_rm.role_id = rm.role_id AND current_rm.menu_id = permission_menu.menu_id); + + IF @outJobMenuId IS NOT NULL + BEGIN + INSERT INTO dbo.sys_role_menu (role_id, menu_id) + SELECT DISTINCT rm.role_id, @pushWcsMenuId + FROM dbo.sys_role_menu rm + WHERE rm.menu_id = @outJobMenuId + AND NOT EXISTS + (SELECT 1 FROM dbo.sys_role_menu current_rm + WHERE current_rm.role_id = rm.role_id AND current_rm.menu_id = @pushWcsMenuId); + END +END +GO