新增渠道管理

This commit is contained in:
liuminghui
2026-10-29 16:30:15 +08:00
parent c3456ca92a
commit b091d47f64
9 changed files with 898 additions and 7 deletions
@@ -1,17 +1,29 @@
package com.bms.web.controller.masterdata;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.masterdata.domain.ServiceChannel;
import com.bms.masterdata.service.IServiceChannelService;
/**
* 服务渠道(老系统镜像 srv_service_channel)
* 渠道管理(srv_service_channel)
* 下拉选项仍走 /optionselect,登录即可,供供应商绑定渠道使用。
*
* @author bms
* @date 2026-10-12
@@ -23,6 +35,32 @@ public class ServiceChannelController extends BaseController
@Autowired
private IServiceChannelService serviceChannelService;
/**
* 分页查询渠道列表。
* 渠道编码、渠道名称、服务商编码、服务商名称、目的港/目的地区域、发货人名称均可检索,名称类条件为模糊匹配。
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:list')")
@GetMapping("/list")
public TableDataInfo list(ServiceChannel query)
{
startPage();
List<ServiceChannel> list = serviceChannelService.selectServiceChannelList(query);
return getDataTable(list);
}
/**
* 导出渠道列表,筛选条件与列表一致。
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:export')")
@Log(title = "渠道管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, ServiceChannel query)
{
List<ServiceChannel> list = serviceChannelService.selectServiceChannelList(query);
ExcelUtil<ServiceChannel> util = new ExcelUtil<ServiceChannel>(ServiceChannel.class);
util.exportExcel(response, list, "渠道数据");
}
/**
* 服务渠道下拉选项(非分页)。
* 供供应商绑定渠道等场景选择渠道;不做权限控制(仍需登录)。
@@ -33,4 +71,63 @@ public class ServiceChannelController extends BaseController
List<ServiceChannel> list = serviceChannelService.selectServiceChannelList(query);
return success(list);
}
/**
* 查询渠道详情
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable String id)
{
return success(serviceChannelService.selectServiceChannelById(id));
}
/**
* 新增渠道
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:add')")
@Log(title = "渠道管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ServiceChannel channel)
{
String username = getUsername();
channel.setCreateName(username);
channel.setModifier(username);
return toAjax(serviceChannelService.insertServiceChannel(channel));
}
/**
* 修改渠道
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:edit')")
@Log(title = "渠道管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ServiceChannel channel)
{
channel.setModifier(getUsername());
return toAjax(serviceChannelService.updateServiceChannel(channel));
}
/**
* 启用或停用渠道
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:edit')")
@Log(title = "渠道管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody ServiceChannel channel)
{
channel.setModifier(getUsername());
return toAjax(serviceChannelService.updateServiceChannelStatus(channel));
}
/**
* 删除渠道。已被产品渠道或供应商引用时不允许删除。
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:remove')")
@Log(title = "渠道管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable String[] ids)
{
return toAjax(serviceChannelService.deleteServiceChannelByIds(ids));
}
}
@@ -2,6 +2,7 @@ package com.bms.masterdata.domain;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.bms.common.annotation.Excel;
import lombok.Data;
/**
@@ -17,53 +18,98 @@ public class ServiceChannel
private String id;
/** 渠道编码 */
@Excel(name = "渠道编码")
private String channelCode;
/** 渠道名称 */
@Excel(name = "渠道名称")
private String channelName;
/** 所属服务商编码 */
@Excel(name = "服务商编码")
private String serviceCode;
/** 所属服务商名称 */
@Excel(name = "服务商名称")
private String serviceName;
/** 是否启用(1启用 0停用) */
@Excel(name = "是否启用", readConverterExp = "1=启用,0=停用")
private String blOpen;
/** 是否支持多票(1是 0否) */
@Excel(name = "是否多票", readConverterExp = "1=是,0=否")
private String blMultiple;
@Excel(name = "货物类型")
private String cargoType;
@Excel(name = "付款方式")
private String payType;
@Excel(name = "发货人名称")
private String shipperName;
@Excel(name = "发货人ID")
private String shipperId;
@Excel(name = "轨迹查询类型")
private String queryType;
@Excel(name = "轨迹编码")
private String trajectoryCode;
@Excel(name = "末端服务商")
private String finalServiceName;
@Excel(name = "目的港/目的地区域")
private String desPort;
/** 重量类型 */
@Excel(name = "重量类型")
private String weightType;
/** 体积除数(抛货系数) */
@Excel(name = "抛货系数")
private Long dimDivisor;
@Excel(name = "计重规则")
private String weightRule;
@Excel(name = "发货类型")
private String shipmentType;
@Excel(name = "数据来源")
private String dataFrom;
@Excel(name = "备注")
private String remarks;
@Excel(name = "创建人")
private String createName;
private String createManCode;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "创建时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
@Excel(name = "修改人")
private String modifier;
private String modifierCode;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "修改时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date modifyDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date gmtCreate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date gmtModified;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "同步时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date syncTime;
}
@@ -4,7 +4,7 @@ import java.util.List;
import com.bms.masterdata.domain.ServiceChannel;
/**
* 服务渠道镜像表查询(MASTER 数据源)
* 服务渠道 srv_service_channel
*
* @author bms
* @date 2026-10-12
@@ -12,7 +12,48 @@ import com.bms.masterdata.domain.ServiceChannel;
public interface ServiceChannelMapper
{
/**
* 查询服务渠道列表(支持渠道编码/名称/服务商编码/启用状态过滤,非分页)
* 查询服务渠道列表。
* 渠道名称、服务商名称、目的港/目的地区域、发货人名称为模糊匹配;编码同样按包含匹配,便于列表检索。
*/
List<ServiceChannel> selectServiceChannelList(ServiceChannel query);
/**
* 按主键查询渠道
*/
ServiceChannel selectServiceChannelById(String id);
/**
* 按渠道编码精确查询(唯一性校验)
*/
ServiceChannel selectServiceChannelByCode(String channelCode);
/**
* 产品渠道关系中引用该渠道编码的数量
*/
int countProductChannelByCode(String channelCode);
/**
* 供应商绑定中引用该渠道编码的数量
*/
int countSupplierByChannelCode(String channelCode);
/**
* 新增渠道
*/
int insertServiceChannel(ServiceChannel channel);
/**
* 修改渠道
*/
int updateServiceChannel(ServiceChannel channel);
/**
* 只更新启用状态
*/
int updateServiceChannelStatus(ServiceChannel channel);
/**
* 批量删除渠道
*/
int deleteServiceChannelByIds(String[] ids);
}
@@ -4,7 +4,7 @@ import java.util.List;
import com.bms.masterdata.domain.ServiceChannel;
/**
* 服务渠道镜像 服务层
* 服务渠道 服务层
*
* @author bms
* @date 2026-10-12
@@ -12,7 +12,32 @@ import com.bms.masterdata.domain.ServiceChannel;
public interface IServiceChannelService
{
/**
* 查询服务渠道列表(非分页,供供应商绑定渠道等下拉选择场景)
* 查询服务渠道列表(分页由调用方 startPage 控制;下拉场景不传分页)
*/
List<ServiceChannel> selectServiceChannelList(ServiceChannel query);
/**
* 查询渠道详情
*/
ServiceChannel selectServiceChannelById(String id);
/**
* 新增渠道
*/
int insertServiceChannel(ServiceChannel channel);
/**
* 修改渠道
*/
int updateServiceChannel(ServiceChannel channel);
/**
* 启用或停用渠道(只改 bl_open)
*/
int updateServiceChannelStatus(ServiceChannel channel);
/**
* 批量删除渠道。已被产品渠道或供应商引用时拒绝删除。
*/
int deleteServiceChannelByIds(String[] ids);
}
@@ -3,12 +3,15 @@ package com.bms.masterdata.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bms.common.exception.ServiceException;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.uuid.IdUtils;
import com.bms.masterdata.domain.ServiceChannel;
import com.bms.masterdata.mapper.ServiceChannelMapper;
import com.bms.masterdata.service.IServiceChannelService;
/**
* 服务渠道镜像 服务实现
* 服务渠道 服务实现
*
* @author bms
* @date 2026-10-12
@@ -24,4 +27,169 @@ public class ServiceChannelServiceImpl implements IServiceChannelService
{
return serviceChannelMapper.selectServiceChannelList(query);
}
@Override
public ServiceChannel selectServiceChannelById(String id)
{
return serviceChannelMapper.selectServiceChannelById(id);
}
@Override
public int insertServiceChannel(ServiceChannel channel)
{
prepare(channel, true);
assertCodeUnique(channel);
channel.setId(IdUtils.fastSimpleUUID());
if (StringUtils.isEmpty(channel.getDataFrom()))
{
channel.setDataFrom("BMS");
}
return serviceChannelMapper.insertServiceChannel(channel);
}
@Override
public int updateServiceChannel(ServiceChannel channel)
{
if (channel == null || StringUtils.isEmpty(channel.getId()))
{
throw new ServiceException("渠道ID不能为空");
}
ServiceChannel existing = serviceChannelMapper.selectServiceChannelById(channel.getId());
if (existing == null)
{
throw new ServiceException("渠道不存在或已被删除");
}
prepare(channel, false);
assertCodeUnique(channel);
if (!StringUtils.equals(existing.getChannelCode(), channel.getChannelCode())
&& countUsage(existing.getChannelCode()) > 0)
{
throw new ServiceException("渠道「" + existing.getChannelName() + "」已被产品渠道或供应商引用,不能修改渠道编码");
}
return serviceChannelMapper.updateServiceChannel(channel);
}
@Override
public int updateServiceChannelStatus(ServiceChannel channel)
{
if (channel == null || StringUtils.isEmpty(channel.getId()))
{
throw new ServiceException("渠道ID不能为空");
}
if (!"0".equals(channel.getBlOpen()) && !"1".equals(channel.getBlOpen()))
{
throw new ServiceException("启用状态只能是启用或停用");
}
ServiceChannel existing = serviceChannelMapper.selectServiceChannelById(channel.getId());
if (existing == null)
{
throw new ServiceException("渠道不存在或已被删除");
}
return serviceChannelMapper.updateServiceChannelStatus(channel);
}
@Override
public int deleteServiceChannelByIds(String[] ids)
{
if (ids == null || ids.length == 0)
{
throw new ServiceException("请选择要删除的渠道");
}
for (String id : ids)
{
if (StringUtils.isEmpty(id))
{
continue;
}
ServiceChannel existing = serviceChannelMapper.selectServiceChannelById(id);
if (existing == null)
{
continue;
}
if (countUsage(existing.getChannelCode()) > 0)
{
throw new ServiceException("渠道「" + existing.getChannelName() + "」已被产品渠道或供应商引用,不能删除,请改为停用");
}
}
return serviceChannelMapper.deleteServiceChannelByIds(ids);
}
private void prepare(ServiceChannel channel, boolean creating)
{
if (channel == null)
{
throw new ServiceException("渠道信息不能为空");
}
channel.setChannelCode(StringUtils.trim(channel.getChannelCode()));
channel.setChannelName(StringUtils.trim(channel.getChannelName()));
channel.setServiceCode(trimToNull(channel.getServiceCode()));
channel.setServiceName(trimToNull(channel.getServiceName()));
channel.setShipperName(trimToNull(channel.getShipperName()));
channel.setDesPort(trimToNull(channel.getDesPort()));
if (StringUtils.isEmpty(channel.getChannelCode()))
{
throw new ServiceException("渠道编码不能为空");
}
if (channel.getChannelCode().length() > 64)
{
throw new ServiceException("渠道编码不能超过64个字符");
}
if (StringUtils.isEmpty(channel.getChannelName()))
{
throw new ServiceException("渠道名称不能为空");
}
if (channel.getChannelName().length() > 200)
{
throw new ServiceException("渠道名称不能超过200个字符");
}
if (StringUtils.isEmpty(channel.getBlOpen()))
{
if (creating)
{
channel.setBlOpen("1");
}
else
{
throw new ServiceException("请选择启用状态");
}
}
if (!"0".equals(channel.getBlOpen()) && !"1".equals(channel.getBlOpen()))
{
throw new ServiceException("启用状态只能是启用或停用");
}
if (StringUtils.isNotEmpty(channel.getBlMultiple())
&& !"0".equals(channel.getBlMultiple()) && !"1".equals(channel.getBlMultiple()))
{
throw new ServiceException("是否多票只能是是或否");
}
if (channel.getDimDivisor() != null && channel.getDimDivisor() < 0)
{
throw new ServiceException("抛货系数不能为负数");
}
}
private void assertCodeUnique(ServiceChannel channel)
{
ServiceChannel same = serviceChannelMapper.selectServiceChannelByCode(channel.getChannelCode());
if (same != null && !StringUtils.equals(same.getId(), channel.getId()))
{
throw new ServiceException("渠道编码「" + channel.getChannelCode() + "」已存在");
}
}
private int countUsage(String channelCode)
{
if (StringUtils.isEmpty(channelCode))
{
return 0;
}
return serviceChannelMapper.countProductChannelByCode(channelCode)
+ serviceChannelMapper.countSupplierByChannelCode(channelCode);
}
private String trimToNull(String value)
{
String text = StringUtils.trim(value);
return StringUtils.isEmpty(text) ? null : text;
}
}
@@ -34,6 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="modifyDate" column="modify_date"/>
<result property="gmtCreate" column="gmt_create"/>
<result property="gmtModified" column="gmt_modified"/>
<result property="syncTime" column="sync_time"/>
</resultMap>
<sql id="selectChannelVo">
@@ -55,15 +56,104 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND channel_name like concat('%', #{channelName}, '%')
</if>
<if test="serviceCode != null and serviceCode != ''">
AND service_code = #{serviceCode}
AND service_code like concat('%', #{serviceCode}, '%')
</if>
<if test="serviceName != null and serviceName != ''">
AND service_name like concat('%', #{serviceName}, '%')
</if>
<if test="desPort != null and desPort != ''">
AND des_port like concat('%', #{desPort}, '%')
</if>
<if test="shipperName != null and shipperName != ''">
AND shipper_name like concat('%', #{shipperName}, '%')
</if>
<if test="blOpen != null and blOpen != ''">
AND bl_open = #{blOpen}
</if>
</where>
order by service_code, channel_code
</select>
<select id="selectServiceChannelById" parameterType="String" resultMap="ServiceChannelResult">
<include refid="selectChannelVo"/>
where id = #{id}
</select>
<select id="selectServiceChannelByCode" parameterType="String" resultMap="ServiceChannelResult">
<include refid="selectChannelVo"/>
where channel_code = #{channelCode}
limit 1
</select>
<select id="countProductChannelByCode" parameterType="String" resultType="int">
select count(1) from srv_product_channel where channel_code = #{channelCode}
</select>
<select id="countSupplierByChannelCode" parameterType="String" resultType="int">
select count(1) from sup_supplier
where del_flag = '0'
and channel_ids is not null
and channel_ids != ''
and find_in_set(#{channelCode}, replace(channel_ids, ' ', ''))
</select>
<insert id="insertServiceChannel" parameterType="com.bms.masterdata.domain.ServiceChannel">
insert into srv_service_channel (
id, channel_code, channel_name, service_code, service_name,
bl_open, bl_multiple, cargo_type, pay_type, shipper_name, shipper_id,
query_type, trajectory_code, final_service_name, des_port,
weight_type, dim_divisor, weight_rule, shipment_type, data_from, remarks,
create_name, create_date, modifier, modify_date, gmt_create, gmt_modified
) values (
#{id}, #{channelCode}, #{channelName}, #{serviceCode}, #{serviceName},
#{blOpen}, #{blMultiple}, #{cargoType}, #{payType}, #{shipperName}, #{shipperId},
#{queryType}, #{trajectoryCode}, #{finalServiceName}, #{desPort},
#{weightType}, #{dimDivisor}, #{weightRule}, #{shipmentType}, #{dataFrom}, #{remarks},
#{createName}, sysdate(), #{modifier}, sysdate(), sysdate(), sysdate()
)
</insert>
<update id="updateServiceChannel" parameterType="com.bms.masterdata.domain.ServiceChannel">
update srv_service_channel
set channel_code = #{channelCode},
channel_name = #{channelName},
service_code = #{serviceCode},
service_name = #{serviceName},
bl_open = #{blOpen},
bl_multiple = #{blMultiple},
cargo_type = #{cargoType},
pay_type = #{payType},
shipper_name = #{shipperName},
shipper_id = #{shipperId},
query_type = #{queryType},
trajectory_code = #{trajectoryCode},
final_service_name = #{finalServiceName},
des_port = #{desPort},
weight_type = #{weightType},
dim_divisor = #{dimDivisor},
weight_rule = #{weightRule},
shipment_type = #{shipmentType},
data_from = #{dataFrom},
remarks = #{remarks},
modifier = #{modifier},
modify_date = sysdate(),
gmt_modified = sysdate()
where id = #{id}
</update>
<update id="updateServiceChannelStatus" parameterType="com.bms.masterdata.domain.ServiceChannel">
update srv_service_channel
set bl_open = #{blOpen},
modifier = #{modifier},
modify_date = sysdate(),
gmt_modified = sysdate()
where id = #{id}
</update>
<delete id="deleteServiceChannelByIds" parameterType="String">
delete from srv_service_channel where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>
@@ -0,0 +1,68 @@
-- 数据管理 - 渠道管理
-- 权限:data:serviceChannel:list|query|add|edit|remove|export
-- 启用/停用走修改权限 data:serviceChannel:edit
SET NAMES utf8mb4;
SET @parentId := (
SELECT menu_id FROM sys_menu
WHERE path = 'data' AND menu_type = 'M' AND parent_id = 0
ORDER BY menu_id ASC LIMIT 1
);
INSERT INTO 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, remark)
SELECT 2502, N'渠道管理', @parentId, 3, 'serviceChannel', 'data/serviceChannel/index', '', 'ServiceChannel', 1, 0, 'C', '0', '0', 'data:serviceChannel:list', 'guide', 'admin', sysdate(), N'服务渠道维护,数据表 srv_service_channel'
FROM DUAL WHERE @parentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2502 OR perms = 'data:serviceChannel:list');
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
SELECT 2503, N'查询', 2502, 1, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:query', '#', 'admin', sysdate()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2503 OR perms = 'data:serviceChannel:query');
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
SELECT 2504, N'新增', 2502, 2, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:add', '#', 'admin', sysdate()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2504 OR perms = 'data:serviceChannel:add');
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
SELECT 2505, N'修改', 2502, 3, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:edit', '#', 'admin', sysdate()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2505 OR perms = 'data:serviceChannel:edit');
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
SELECT 2506, N'删除', 2502, 4, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:remove', '#', 'admin', sysdate()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2506 OR perms = 'data:serviceChannel:remove');
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
SELECT 2507, N'导出', 2502, 5, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:export', '#', 'admin', sysdate()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2507 OR perms = 'data:serviceChannel:export');
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT 1, m.menu_id FROM (
SELECT 2502 AS menu_id UNION SELECT 2503 UNION SELECT 2504 UNION SELECT 2505 UNION SELECT 2506 UNION SELECT 2507
) m
WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = 1 AND rm.menu_id = m.menu_id);
-- 已有「数据管理-区域管理」权限的角色,同步授予对应的渠道管理权限
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT DISTINCT rm.role_id, dst.menu_id
FROM sys_role_menu rm
JOIN sys_menu src ON src.menu_id = rm.menu_id AND src.perms = 'data:region:list'
JOIN sys_menu dst ON dst.perms IN ('data:serviceChannel:list', 'data:serviceChannel:query', 'data:serviceChannel:export')
WHERE NOT EXISTS (
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = dst.menu_id
);
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT DISTINCT rm.role_id, dst.menu_id
FROM sys_role_menu rm
JOIN sys_menu src ON src.menu_id = rm.menu_id AND src.perms = 'data:region:edit'
JOIN sys_menu dst ON dst.perms IN ('data:serviceChannel:add', 'data:serviceChannel:edit')
WHERE NOT EXISTS (
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = dst.menu_id
);
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT DISTINCT rm.role_id, dst.menu_id
FROM sys_role_menu rm
JOIN sys_menu src ON src.menu_id = rm.menu_id AND src.perms = 'data:region:remove'
JOIN sys_menu dst ON dst.perms = 'data:serviceChannel:remove'
WHERE NOT EXISTS (
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = dst.menu_id
);