3 Commits

Author SHA1 Message Date
zhangsz
e4f52c949e fix: project change 2025-08-01 15:12:37 +08:00
zhangsz
0ee3af1187 feat: sql list support cbc broadcast 2025-08-01 15:11:38 +08:00
zhangsz
1b4cb6399e feat: support CBC broadcast 2025-08-01 14:50:55 +08:00
26 changed files with 1463 additions and 0 deletions

4
.gitignore vendored
View File

@@ -17,6 +17,10 @@
*.bak
*.bak*
*.exe
__debug_bin*
debug/
*.log.*
main
# Build Output
local/omc_db.sqlite

View File

@@ -0,0 +1,21 @@
-- ----------------------------
-- Table structure for cbc_message
-- ----------------------------
-- ----------------------------
-- Table structure for cbc_message
-- ----------------------------
DROP TABLE IF EXISTS `cbc_message`;
CREATE TABLE `cbc_message` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`ne_type` TEXT,
`ne_id` TEXT,
`message_json` TEXT,
`status` TEXT DEFAULT 'INACTIVE' CHECK(`status` IN ('ACTIVE', 'INACTIVE')),
`detail` TEXT,
`created_at` INTEGER DEFAULT (strftime('%s', 'now') * 1000000),
`updated_at` INTEGER
);
-- Create indexes
CREATE INDEX `idx_id` ON `cbc_message`(`id`);
CREATE INDEX `idx_ne_time` ON `cbc_message`(`ne_type`, `ne_id`, `created_at`);

View File

@@ -932,3 +932,22 @@ INSERT INTO "sys_i18n" VALUES (756, 'dictData.trace_interfaces.14', 'N14', 'N14'
INSERT INTO "sys_i18n" VALUES (757, 'dictData.trace_interfaces.5', 'N5', 'N5');
INSERT INTO "sys_i18n" VALUES (758, "alarm.export.alarmCode", "告警编码", "Alarm Code");
INSERT INTO "sys_i18n" VALUES (759, "config.sys.user.fristPasswdChangeRemark", "关闭改为false 开启改为true, 建议同时设置密码有效期", "Off to false On to true, it is recommended to set the password expiration date at the same time.");
INSERT INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent');
INSERT INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information');
INSERT INTO `sys_i18n` VALUES (2002, 'menu.psap.agent.callback', '回拨管理', 'Callback Management');
INSERT INTO `sys_i18n` VALUES (2003, 'callback.status.NEW', '新建', 'New');
INSERT INTO `sys_i18n` VALUES (2004, 'callback.status.IN_PROGRESS', '处理中', 'In Progress');
INSERT INTO `sys_i18n` VALUES (2005, 'callback.status.NO_ANSWER_1', '未应答1', 'No Answer 1');
INSERT INTO `sys_i18n` VALUES (2006, 'callback.status.NO_ANSWER_2', '未应答2', 'No Answer 2');
INSERT INTO `sys_i18n` VALUES (2007, 'callback.status.TIMEOUT', '超时', 'Timeout');
INSERT INTO `sys_i18n` VALUES (2008, 'callback.status.PENDING', '挂起', 'Pending');
INSERT INTO `sys_i18n` VALUES (2009, 'callback.status.CLOSED', '关闭', 'Closed');
INSERT INTO `sys_i18n` VALUES (2010, 'job.export.cdr.mf', '定期导出MF话单', 'Periodic Export of MF Call Records');
INSERT INTO `sys_i18n` VALUES (2011, 'job.psap.ticket.monitor', '回拨工单监控', 'Callback Ticket Monitoring');
INSERT INTO `sys_i18n` VALUES (2012, 'menu.omc.cdr', '话单', 'Call Records');
INSERT INTO `sys_i18n` VALUES (2013, 'menu.omc.cdr.mf', '紧急呼叫话单', 'Emergency Call Records');
INSERT INTO `sys_i18n` VALUES (2014, 'menu.omc.cdr.crbt', '彩铃话单', 'Color Ring Back Tone Records');
INSERT INTO `sys_i18n` VALUES (2015, 'menu.omc.cdr.mms', '彩信话单', 'Multimedia Message Service Records');
INSERT INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '广播', 'Broadcast');
INSERT INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '广播事件', 'Broadcast Event');

View File

@@ -203,3 +203,5 @@ INSERT INTO "sys_menu" VALUES (2166, 'menu.dashboard.overview.smfUeNum', 2132, 4
INSERT INTO "sys_menu" VALUES (2167, 'menu.dashboard.overview.imsUeNum', 2132, 2, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:imsUeNum', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
INSERT INTO "sys_menu" VALUES (2168, 'menu.dashboard.overview.gnbBase', 2132, 6, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:gnbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
INSERT INTO "sys_menu" VALUES (2169, 'menu.dashboard.overview.enbBase', 2132, 8, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:enbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
INSERT INTO `sys_menu` VALUES (20000, 'menu.ue.cbc.cbe', 5, 20, 'cbe', 'cbc/cbe/index', '1', '0', 'M', '1', '1', 'cbc#dashboard:cdr:index', 'icon-tubiaoku', '0', 'system', 1711352709786, 'system', 1747796007372, '');

View File

@@ -157,6 +157,7 @@ INSERT INTO "sys_role_menu" VALUES (2, 2166);
INSERT INTO "sys_role_menu" VALUES (2, 2167);
INSERT INTO "sys_role_menu" VALUES (2, 2168);
INSERT INTO "sys_role_menu" VALUES (2, 2169);
INSERT INTO "sys_role_menu" VALUES (2, 20000);
INSERT INTO "sys_role_menu" VALUES (3, 1);
INSERT INTO "sys_role_menu" VALUES (3, 4);
@@ -232,6 +233,7 @@ INSERT INTO "sys_role_menu" VALUES (3, 2166);
INSERT INTO "sys_role_menu" VALUES (3, 2167);
INSERT INTO "sys_role_menu" VALUES (3, 2168);
INSERT INTO "sys_role_menu" VALUES (3, 2169);
INSERT INTO "sys_role_menu" VALUES (3, 20000);
INSERT INTO "sys_role_menu" VALUES (4, 1);
INSERT INTO "sys_role_menu" VALUES (4, 4);

View File

@@ -0,0 +1,17 @@
-- ----------------------------
-- Table structure for cbc_message
-- ----------------------------
CREATE TABLE IF NOT EXISTS `cbc_message` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`ne_type` TEXT,
`ne_id` TEXT,
`message_json` TEXT,
`status` TEXT DEFAULT 'INACTIVE' CHECK(`status` IN ('ACTIVE', 'INACTIVE')),
`detail` TEXT,
`created_at` INTEGER DEFAULT (strftime('%s', 'now') * 1000000),
`updated_at` INTEGER
);
-- Create indexes
CREATE INDEX IF NOT EXISTS `idx_id` ON `cbc_message`(`id`);
CREATE INDEX IF NOT EXISTS `idx_ne_time` ON `cbc_message`(`ne_type`, `ne_id`, `created_at`);

View File

@@ -931,3 +931,22 @@ REPLACE INTO "sys_i18n" VALUES (756, 'dictData.trace_interfaces.14', 'N14', 'N14
REPLACE INTO "sys_i18n" VALUES (757, 'dictData.trace_interfaces.5', 'N5', 'N5');
REPLACE INTO "sys_i18n" VALUES (758, "alarm.export.alarmCode", "告警编码", "Alarm Code");
REPLACE INTO "sys_i18n" VALUES (759, "config.sys.user.fristPasswdChangeRemark", "关闭改为false 开启改为true, 建议同时设置密码有效期", "Off to false On to true, it is recommended to set the password expiration date at the same time.");
REPLACE INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent');
REPLACE INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information');
REPLACE INTO `sys_i18n` VALUES (2002, 'menu.psap.agent.callback', '回拨管理', 'Callback Management');
REPLACE INTO `sys_i18n` VALUES (2003, 'callback.status.NEW', '新建', 'New');
REPLACE INTO `sys_i18n` VALUES (2004, 'callback.status.IN_PROGRESS', '处理中', 'In Progress');
REPLACE INTO `sys_i18n` VALUES (2005, 'callback.status.NO_ANSWER_1', '未应答1', 'No Answer 1');
REPLACE INTO `sys_i18n` VALUES (2006, 'callback.status.NO_ANSWER_2', '未应答2', 'No Answer 2');
REPLACE INTO `sys_i18n` VALUES (2007, 'callback.status.TIMEOUT', '超时', 'Timeout');
REPLACE INTO `sys_i18n` VALUES (2008, 'callback.status.PENDING', '挂起', 'Pending');
REPLACE INTO `sys_i18n` VALUES (2009, 'callback.status.CLOSED', '关闭', 'Closed');
REPLACE INTO `sys_i18n` VALUES (2010, 'job.export.cdr.mf', '定期导出MF话单', 'Periodic Export of MF Call Records');
REPLACE INTO `sys_i18n` VALUES (2011, 'job.psap.ticket.monitor', '回拨工单监控', 'Callback Ticket Monitoring');
REPLACE INTO `sys_i18n` VALUES (2012, 'menu.omc.cdr', '话单', 'Call Records');
REPLACE INTO `sys_i18n` VALUES (2013, 'menu.omc.cdr.mf', '紧急呼叫话单', 'Emergency Call Records');
REPLACE INTO `sys_i18n` VALUES (2014, 'menu.omc.cdr.crbt', '彩铃话单', 'Color Ring Back Tone Records');
REPLACE INTO `sys_i18n` VALUES (2015, 'menu.omc.cdr.mms', '彩信话单', 'Multimedia Message Service Records');
REPLACE INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '广播', 'Broadcast');
REPLACE INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '广播事件', 'Broadcast Event');

View File

@@ -202,3 +202,5 @@ REPLACE INTO "sys_menu" VALUES (2166, 'menu.dashboard.overview.smfUeNum', 2132,
REPLACE INTO "sys_menu" VALUES (2167, 'menu.dashboard.overview.imsUeNum', 2132, 2, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:imsUeNum', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
REPLACE INTO "sys_menu" VALUES (2168, 'menu.dashboard.overview.gnbBase', 2132, 6, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:gnbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
REPLACE INTO "sys_menu" VALUES (2169, 'menu.dashboard.overview.enbBase', 2132, 8, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:enbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
REPLACE INTO `sys_menu` VALUES (20000, 'menu.ue.cbc.cbe', 5, 20, 'cbe', 'cbc/cbe/index', '1', '0', 'M', '1', '1', 'cbc#dashboard:cdr:index', 'icon-tubiaoku', '0', 'system', 1711352709786, 'system', 1747796007372, '');

View File

@@ -156,6 +156,7 @@ REPLACE INTO "sys_role_menu" VALUES (2, 2166);
REPLACE INTO "sys_role_menu" VALUES (2, 2167);
REPLACE INTO "sys_role_menu" VALUES (2, 2168);
REPLACE INTO "sys_role_menu" VALUES (2, 2169);
REPLACE INTO "sys_role_menu" VALUES (2, 20000);
REPLACE INTO "sys_role_menu" VALUES (3, 1);
REPLACE INTO "sys_role_menu" VALUES (3, 4);
@@ -231,6 +232,7 @@ REPLACE INTO "sys_role_menu" VALUES (3, 2166);
REPLACE INTO "sys_role_menu" VALUES (3, 2167);
REPLACE INTO "sys_role_menu" VALUES (3, 2168);
REPLACE INTO "sys_role_menu" VALUES (3, 2169);
REPLACE INTO "sys_role_menu" VALUES (3, 20000);
REPLACE INTO "sys_role_menu" VALUES (4, 1);
REPLACE INTO "sys_role_menu" VALUES (4, 4);

View File

@@ -0,0 +1,38 @@
/*
Navicat Premium Data Transfer
Source Server : root@192.168.2.242
Source Server Type : MariaDB
Source Server Version : 100622 (10.6.22-MariaDB-0ubuntu0.22.04.1)
Source Host : 192.168.2.242:33066
Source Schema : omc_db
Target Server Type : MariaDB
Target Server Version : 100622 (10.6.22-MariaDB-0ubuntu0.22.04.1)
File Encoding : 65001
Date: 01/08/2025 10:07:00
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for cbc_message
-- ----------------------------
DROP TABLE IF EXISTS `cbc_message`;
CREATE TABLE `cbc_message` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`message_json` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`status` enum('ACTIVE','INACTIVE') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'INACTIVE',
`detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`created_at` bigint(20) NULL DEFAULT current_timestamp(),
`updated_at` bigint(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `id`(`id`) USING BTREE,
INDEX `idx_ne_time`(`ne_type`, `ne_id`, `created_at`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 64 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'CDR事件_MF' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -775,4 +775,23 @@ INSERT INTO `sys_i18n` VALUES (757, 'dictData.trace_interfaces.5', 'N5', 'N5');
INSERT INTO `sys_i18n` VALUES (758, "alarm.export.alarmCode", "告警编码", "Alarm Code");
INSERT INTO `sys_i18n` VALUES (759, "config.sys.user.fristPasswdChangeRemark", "关闭改为false 开启改为true, 建议同时设置密码有效期", "Off to false On to true, it is recommended to set the password expiration date at the same time.");
INSERT INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent');
INSERT INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information');
INSERT INTO `sys_i18n` VALUES (2002, 'menu.psap.agent.callback', '回拨管理', 'Callback Management');
INSERT INTO `sys_i18n` VALUES (2003, 'callback.status.NEW', '新建', 'New');
INSERT INTO `sys_i18n` VALUES (2004, 'callback.status.IN_PROGRESS', '处理中', 'In Progress');
INSERT INTO `sys_i18n` VALUES (2005, 'callback.status.NO_ANSWER_1', '未应答1', 'No Answer 1');
INSERT INTO `sys_i18n` VALUES (2006, 'callback.status.NO_ANSWER_2', '未应答2', 'No Answer 2');
INSERT INTO `sys_i18n` VALUES (2007, 'callback.status.TIMEOUT', '超时', 'Timeout');
INSERT INTO `sys_i18n` VALUES (2008, 'callback.status.PENDING', '挂起', 'Pending');
INSERT INTO `sys_i18n` VALUES (2009, 'callback.status.CLOSED', '关闭', 'Closed');
INSERT INTO `sys_i18n` VALUES (2010, 'job.export.cdr.mf', '定期导出MF话单', 'Periodic Export of MF Call Records');
INSERT INTO `sys_i18n` VALUES (2011, 'job.psap.ticket.monitor', '回拨工单监控', 'Callback Ticket Monitoring');
INSERT INTO `sys_i18n` VALUES (2012, 'menu.omc.cdr', '话单', 'Call Records');
INSERT INTO `sys_i18n` VALUES (2013, 'menu.omc.cdr.mf', '紧急呼叫话单', 'Emergency Call Records');
INSERT INTO `sys_i18n` VALUES (2014, 'menu.omc.cdr.crbt', '彩铃话单', 'Color Ring Back Tone Records');
INSERT INTO `sys_i18n` VALUES (2015, 'menu.omc.cdr.mms', '彩信话单', 'Multimedia Message Service Records');
INSERT INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '广播', 'Broadcast');
INSERT INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '广播事件', 'Broadcast Event');
-- Dump completed on 2025-02-14 15:26:56

View File

@@ -209,6 +209,8 @@ INSERT INTO `sys_menu` VALUES (2167, 'menu.dashboard.overview.imsUeNum', 2132, 2
INSERT INTO `sys_menu` VALUES (2168, 'menu.dashboard.overview.gnbBase', 2132, 6, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:gnbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
INSERT INTO `sys_menu` VALUES (2169, 'menu.dashboard.overview.enbBase', 2132, 8, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:enbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
INSERT INTO `sys_menu` VALUES (20000, 'menu.ue.cbc.cbe', 5, 20, 'cbe', 'cbc/cbe/index', '1', '0', 'M', '1', '1', 'cbc#dashboard:cdr:index', 'icon-tubiaoku', '0', 'system', 1711352709786, 'system', 1747796007372, '');
SET FOREIGN_KEY_CHECKS = 1;
-- Dump completed on 2025-02-14 15:26:56

View File

@@ -163,6 +163,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2166);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2167);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2168);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2169);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 20000);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 4);
@@ -238,6 +239,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2166);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2167);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2168);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2169);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 20000);
INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1);
INSERT IGNORE INTO `sys_role_menu` VALUES (4, 4);

View File

@@ -0,0 +1,37 @@
/*
Navicat Premium Data Transfer
Source Server : root@192.168.2.242
Source Server Type : MariaDB
Source Server Version : 100622 (10.6.22-MariaDB-0ubuntu0.22.04.1)
Source Host : 192.168.2.242:33066
Source Schema : omc_db
Target Server Type : MariaDB
Target Server Version : 100622 (10.6.22-MariaDB-0ubuntu0.22.04.1)
File Encoding : 65001
Date: 01/08/2025 10:07:00
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for cbc_message
-- ----------------------------
CREATE TABLE IF NOT EXISTS `cbc_message` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`message_json` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`status` enum('ACTIVE','INACTIVE') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'INACTIVE',
`detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`created_at` bigint(20) NULL DEFAULT current_timestamp(),
`updated_at` bigint(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `id`(`id`) USING BTREE,
INDEX `idx_ne_time`(`ne_type`, `ne_id`, `created_at`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 64 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'CDR事件_MF' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -772,4 +772,23 @@ REPLACE INTO `sys_i18n` VALUES (757, 'dictData.trace_interfaces.5', 'N5', 'N5');
REPLACE INTO `sys_i18n` VALUES (758, "alarm.export.alarmCode", "告警编码", "Alarm Code");
REPLACE INTO `sys_i18n` VALUES (759, "config.sys.user.fristPasswdChangeRemark", "关闭改为false 开启改为true, 建议同时设置密码有效期", "Off to false On to true, it is recommended to set the password expiration date at the same time.");
REPLACE INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent');
REPLACE INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information');
REPLACE INTO `sys_i18n` VALUES (2002, 'menu.psap.agent.callback', '回拨管理', 'Callback Management');
REPLACE INTO `sys_i18n` VALUES (2003, 'callback.status.NEW', '新建', 'New');
REPLACE INTO `sys_i18n` VALUES (2004, 'callback.status.IN_PROGRESS', '处理中', 'In Progress');
REPLACE INTO `sys_i18n` VALUES (2005, 'callback.status.NO_ANSWER_1', '未应答1', 'No Answer 1');
REPLACE INTO `sys_i18n` VALUES (2006, 'callback.status.NO_ANSWER_2', '未应答2', 'No Answer 2');
REPLACE INTO `sys_i18n` VALUES (2007, 'callback.status.TIMEOUT', '超时', 'Timeout');
REPLACE INTO `sys_i18n` VALUES (2008, 'callback.status.PENDING', '挂起', 'Pending');
REPLACE INTO `sys_i18n` VALUES (2009, 'callback.status.CLOSED', '关闭', 'Closed');
REPLACE INTO `sys_i18n` VALUES (2010, 'job.export.cdr.mf', '定期导出MF话单', 'Periodic Export of MF Call Records');
REPLACE INTO `sys_i18n` VALUES (2011, 'job.psap.ticket.monitor', '回拨工单监控', 'Callback Ticket Monitoring');
REPLACE INTO `sys_i18n` VALUES (2012, 'menu.omc.cdr', '话单', 'Call Records');
REPLACE INTO `sys_i18n` VALUES (2013, 'menu.omc.cdr.mf', '紧急呼叫话单', 'Emergency Call Records');
REPLACE INTO `sys_i18n` VALUES (2014, 'menu.omc.cdr.crbt', '彩铃话单', 'Color Ring Back Tone Records');
REPLACE INTO `sys_i18n` VALUES (2015, 'menu.omc.cdr.mms', '彩信话单', 'Multimedia Message Service Records');
REPLACE INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '广播', 'Broadcast');
REPLACE INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '广播事件', 'Broadcast Event');
-- Dump completed on 2025-02-14 15:26:56

View File

@@ -231,6 +231,8 @@ REPLACE INTO `sys_menu` VALUES (2167, 'menu.dashboard.overview.imsUeNum', 2132,
REPLACE INTO `sys_menu` VALUES (2168, 'menu.dashboard.overview.gnbBase', 2132, 6, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:gnbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
REPLACE INTO `sys_menu` VALUES (2169, 'menu.dashboard.overview.enbBase', 2132, 8, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:enbBase', '#', '0', 'system', 1728641403588, 'system', 1728641403588, '');
REPLACE INTO `sys_menu` VALUES (20000, 'menu.ue.cbc.cbe', 5, 20, 'cbe', 'cbc/cbe/index', '1', '0', 'M', '1', '1', 'cbc#dashboard:cdr:index', 'icon-tubiaoku', '0', 'system', 1711352709786, 'system', 1747796007372, '');
SET FOREIGN_KEY_CHECKS = 1;
-- Dump completed on 2025-02-14 15:26:56

View File

@@ -162,6 +162,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2166);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2167);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2168);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2169);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 20000);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 4);
@@ -237,6 +238,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2166);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2167);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2168);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2169);
INSERT IGNORE INTO `sys_role_menu` VALUES (3, 20000);
INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1);
INSERT IGNORE INTO `sys_role_menu` VALUES (4, 4);

27
go.sum
View File

@@ -2,6 +2,11 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
@@ -17,9 +22,11 @@ github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCN
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -82,6 +89,7 @@ github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeD
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
@@ -100,8 +108,11 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@@ -128,6 +139,7 @@ github.com/matoous/go-nanoid/v2 v2.1.0 h1:P64+dmq21hhWdtvZfEAofnvJULaRR1Yib0+PnU
github.com/matoous/go-nanoid/v2 v2.1.0/go.mod h1:KlbGNQ+FhrUNIHUxZdL63t7tl4LaPkZNpUULS8H4uVM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -141,6 +153,7 @@ github.com/mssola/useragent v1.0.0 h1:WRlDpXyxHDNfvZaPEut5Biveq86Ze4o4EMffyMxmH5
github.com/mssola/useragent v1.0.0/go.mod h1:hz9Cqz4RXusgg1EdI4Al0INR62kP7aPSRNHnpU+b85Y=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c=
@@ -180,10 +193,12 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
@@ -222,12 +237,14 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/wneessen/go-mail v0.6.2 h1:c6V7c8D2mz868z9WJ+8zDKtUyLfZ1++uAZmo2GRFji8=
github.com/wneessen/go-mail v0.6.2/go.mod h1:L/PYjPK3/2ZlNb2/FjEBIn9n1rUWjW+Toy531oVmeb4=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/xuri/efp v0.0.0-20250227110027-3491fafc2b79 h1:78nKszZqigiBRBVcoe/AuPzyLTWW5B+ltBaUX1rlIXA=
github.com/xuri/efp v0.0.0-20250227110027-3491fafc2b79/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE=
@@ -237,6 +254,7 @@ github.com/xuri/nfp v0.0.0-20250226145837-86d5fc24b2ba/go.mod h1:WwHg+CVyzlv/TX9
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
@@ -273,6 +291,7 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -302,6 +321,7 @@ golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -334,11 +354,13 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -346,8 +368,11 @@ gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
@@ -371,3 +396,5 @@ modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

View File

@@ -0,0 +1,316 @@
package controller
import (
"encoding/json"
"fmt"
"strconv"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
)
const (
neType = "CBC" // 网元类型
)
// 实例化控制层 CBCController 结构体
var NewCBC = &CBCController{
neInfoService: neService.NewNeInfo,
neCBCMessageService: neDataService.NewCBCMessage,
}
// 网元CBC
type CBCController struct {
neInfoService *neService.NeInfo // 网元信息服务
neCBCMessageService *neDataService.CBCMessage // CBC消息服务
}
func (m *CBCController) List(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neId := c.Query("neId")
if neId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
var query model.CBCMessageQuery
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
query.NeType = neType
query.NeId = neId
data, total, err := neDataService.NewCBCMessage.SelectByPage(query)
if err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
// 转换数据格式,确保 MessageJson 正确序列化
processedData := make([]map[string]interface{}, len(data))
for i, msg := range data {
var messageJson interface{}
if len(msg.MessageJson) > 0 {
// 尝试解析为 JSON 对象
if err := json.Unmarshal(msg.MessageJson, &messageJson); err != nil {
// 如果解析失败,就作为字符串
messageJson = string(msg.MessageJson)
}
}
processedData[i] = map[string]interface{}{
"id": msg.Id,
"neType": msg.NeType,
"neId": msg.NeId,
"messageJson": messageJson, // 这里是解析后的 JSON 对象
"status": msg.Status.Enum(),
"detail": msg.Detail,
"createdAt": msg.CreatedAt,
"updatedAt": msg.UpdatedAt,
}
}
c.JSON(200, resp.Ok(gin.H{
"total": total,
"data": processedData,
}))
}
// Update 更新CB消息
func (m *CBCController) Insert(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 绑定请求体
var msg model.CBCMessage
msg.NeType = neType
msg.NeId = c.Query("neId")
msg.Status = model.CBCEventStatusInactive // 默认状态为 INACTIVE
if msg.NeId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
msg.CreatedAt = time.Now().Local().UnixMicro()
msg.UpdatedAt = nil // 新增时更新时间为nil
// 使用 ShouldBindBodyWithJSON 读取请求体
var jsonData interface{}
if err := c.ShouldBindBodyWithJSON(&jsonData); err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 将绑定的数据转换为 JSON
jsonBytes, err := json.Marshal(jsonData)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
msg.MessageJson = json.RawMessage(jsonBytes)
if err := neDataService.NewCBCMessage.Insert(msg); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// Update 更新CB消息
func (m *CBCController) Update(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 获取路径参数
messageId := c.Param("id")
if messageId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
id, err := strconv.ParseInt(messageId, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 直接读取body为json.RawMessage
var jsonData interface{}
if err := c.ShouldBindBodyWithJSON(&jsonData); err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 将绑定的数据转换为 JSON
jsonBytes, err := json.Marshal(jsonData)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
messageJson := json.RawMessage(jsonBytes)
if err := neDataService.NewCBCMessage.Update(id, messageJson); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// UpdateStatus 更新CB消息状态
// 这里的 neId 参数是为了兼容性,实际更新状态时不需要使用它
// 但为了保持与原有接口一致,仍然保留该参数
// 如果需要根据 neId 进行特定的逻辑处理,可以在服务层实现
// 但在当前实现中neId 仅用于验证请求的有效性
// 实际的状态更新逻辑不依赖于 neId
// 该接口用于更新 CB 消息的状态,状态值通过查询参数传递
// 例如PUT /:neId/message/status?status=ACTIVE
func (m *CBCController) UpdateStatus(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neId := c.Query("neId")
status := c.Param("status")
if neId == "" || status == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
messageId := c.Param("id")
if messageId != "" {
id, err := strconv.ParseInt(messageId, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 如果提供了 messageId则更新特定消息的状态
if err := neDataService.NewCBCMessage.UpdateStatus(id, status); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
return
}
// 如果没有提供 messageId则更新所有消息的状态
if err := neDataService.NewCBCMessage.UpdateStatusByNeId(neId, status); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// Delete 删除CB消息
func (m *CBCController) Delete(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 获取路径参数
messageId := c.Param("id")
if messageId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
id, err := strconv.ParseInt(messageId, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
if err := neDataService.NewCBCMessage.Delete(id); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// ListById 根据ID获取CB消息
func (m *CBCController) ListById(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 获取路径参数
idStr := c.Param("id")
if idStr == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
data, err := neDataService.NewCBCMessage.SelectById(id)
if err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
if data == nil {
c.JSON(404, resp.CodeMsg(404, i18n.TKey(language, "app.common.err404")))
return
}
// 转换数据格式,确保 MessageJson 正确序列化
var messageJson interface{}
if len(data.MessageJson) > 0 {
// 尝试解析为 JSON 对象
if err := json.Unmarshal(data.MessageJson, &messageJson); err != nil {
// 如果解析失败,就作为字符串
messageJson = string(data.MessageJson)
}
}
processedData := map[string]interface{}{
"id": data.Id,
"neType": data.NeType,
"neId": data.NeId,
"messageJson": messageJson, // 这里是解析后的 JSON 对象
"status": data.Status.Enum(),
"detail": data.Detail,
"createdAt": data.CreatedAt,
"updatedAt": data.UpdatedAt,
}
c.JSON(200, resp.Ok(gin.H{
"data": processedData,
}))
}
func (m *CBCController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var query model.CBCMessageQuery
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if query.PageSize > 10000 {
query.PageSize = 10000
}
// 查询数据
rows, total, err := m.neCBCMessageService.SelectByPage(query)
if err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("cbc_message_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := m.neCBCMessageService.ExportXlsx(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -0,0 +1,112 @@
package model
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
)
type CBCEventStatus int
// CBCEventStatus CB事件状态枚举
const (
CBCEventStatusNull CBCEventStatus = iota // 未知状态
CBCEventStatusActive
CBCEventStatusInactive
)
func (status CBCEventStatus) Enum() string {
switch status {
case CBCEventStatusNull:
return "NULL"
case CBCEventStatusActive:
return "ACTIVE"
case CBCEventStatusInactive:
return "INACTIVE"
default:
return "UNKNOWN"
}
}
func (status CBCEventStatus) String() string {
return fmt.Sprintf("%d", status)
}
// ParseCBCEventStatus 将字符串转换为 枚举类型
func ParseCBCEventStatus(s string) CBCEventStatus {
if i, err := strconv.Atoi(s); err == nil {
return CBCEventStatus(i)
}
// 如果转换失败,则按名称匹配(忽略大小写)
switch strings.ToUpper(s) {
case "NULL":
return CBCEventStatusNull
case "ACTIVE":
return CBCEventStatusActive
case "INACTIVE":
return CBCEventStatusInactive
case "":
// 如果字符串为空,则返回未知状态
return CBCEventStatusNull
default:
// 默认返回未知状态
return CBCEventStatusNull
}
}
// CBCMessageQuery 查询条件结构体
type CBCMessageQuery struct {
NeType string `form:"neType"` // 网元类型
NeId string `form:"neId"` // 网元ID
EventName string `form:"eventName"` // 事件名称
Status string `form:"status"` // 消息状态
StartTime string `form:"startTime"` // 创建时间范围-起始
EndTime string `form:"endTime"` // 创建时间范围-结束
PageNum int `form:"pageNum" binding:"required"`
PageSize int `form:"pageSize" binding:"required"`
}
// @Description CBCMessage CB消息
type CBCMessage struct {
Id int64 `json:"id" gorm:"column:id"` // CB消息ID
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
NeId string `json:"neId" gorm:"column:ne_id"` // 网元ID
MessageJson json.RawMessage `json:"messageJson" gorm:"column:message_json"` // 消息内容JSON
Status CBCEventStatus `json:"status" gorm:"column:status"` // 消息状态
Detail string `json:"detail" gorm:"column:detail"` // 详情
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间
UpdatedAt *int64 `json:"updatedAt" gorm:"column:updated_at;autoUpdateTime:false"` // 更新时间
}
// TableName 表名称
func (*CBCMessage) TableName() string {
return "cbc_message"
}
// Scan 实现 sql.Scanner 接口,支持从数据库字符串转为 CBCEventStatus
func (s *CBCEventStatus) Scan(value interface{}) error {
switch v := value.(type) {
case string:
*s = ParseCBCEventStatus(v)
return nil
case []byte:
*s = ParseCBCEventStatus(string(v))
return nil
case int64:
*s = CBCEventStatus(v)
return nil
case int:
*s = CBCEventStatus(v)
return nil
default:
return errors.New("unsupported Scan type for CBCEventStatus")
}
}
// Value 实现 driver.Valuer 接口,支持将 CBCEventStatus 存为字符串
func (s CBCEventStatus) Value() (driver.Value, error) {
return s.Enum(), nil
}

View File

@@ -579,6 +579,44 @@ func Setup(router *gin.Engine) {
controller.NewPCF.RuleInfoImport,
)
}
// 网元CBC
cbcGroup := neDataGroup.Group("/cbc")
{
cbcGroup.GET("/message/list",
middleware.AuthorizeUser(nil),
controller.NewCBC.List,
)
cbcGroup.GET("/message/:id",
middleware.AuthorizeUser(nil),
controller.NewCBC.ListById,
)
cbcGroup.POST("/message",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewCBC.Insert,
)
cbcGroup.PUT("/message/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewCBC.Update,
)
cbcGroup.PUT("/message/:id/:status",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewCBC.UpdateStatus,
)
cbcGroup.DELETE("/message/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewCBC.Delete,
)
cbcGroup.GET("/message/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewCBC.Export,
)
}
}
// InitLoad 初始参数

View File

@@ -0,0 +1,254 @@
package repository
import (
"encoding/json"
"fmt"
"time"
"be.ems/src/framework/database/db"
"be.ems/src/modules/network_data/model"
"gorm.io/gorm"
)
// 实例化数据层 UEEvent 结构体
var NewCBCMessage = &CBCMessage{}
// UEEvent UE会话事件 数据层处理
type CBCMessage struct{}
// SelectCBCMessage 根据条件分页查询CB消息
func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessage, int, error) {
var msg []model.CBCMessage
var total int64
tx := db.DB("").Table("cbc_message")
if query.NeType != "" {
tx = tx.Where("ne_type = ?", query.NeType)
}
if query.NeId != "" {
tx = tx.Where("ne_id = ?", query.NeId)
}
if query.EventName != "" {
tx = tx.Where("JSON_EXTRACT(message_json, '$.eventName') = ?", query.EventName)
}
if query.Status != "" {
tx = tx.Where("status = ?", query.Status)
}
var startMicro, endMicro int64
var err error
if query.StartTime != "" {
startMicro, err = parseTimeToMicro(query.StartTime)
if err != nil {
return nil, 0, fmt.Errorf("invalid start time: %w", err)
}
}
if query.EndTime != "" {
endMicro, err = parseTimeToMicro(query.EndTime)
if err != nil {
return nil, 0, fmt.Errorf("invalid end time: %w", err)
}
}
if startMicro > 0 && endMicro > 0 {
tx = tx.Where("created_at BETWEEN ? AND ?", startMicro, endMicro)
} else if startMicro > 0 {
tx = tx.Where("created_at >= ?", startMicro)
} else if endMicro > 0 {
tx = tx.Where("created_at <= ?", endMicro)
}
// 统计总数
if err := tx.Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("failed to count CBC message: %w", err)
}
// 分页查询
offset := (query.PageNum - 1) * query.PageSize
if err := tx.Limit(query.PageSize).Offset(offset).Order("created_at desc").Find(&msg).Error; err != nil {
return nil, 0, fmt.Errorf("failed to select CBC message: %w", err)
}
return msg, int(total), nil
}
// SelectCBCMessageByPage 分页查询CB消息
// @Description 分页查询CB消息
// @param page 页码
// @param pageSize 每页大小
// @return []model.CBCMessage CB消息列表
// @return int 总记录数
// @return error 错误信息
// @example
// SelectByPage(1, 10)
// func (s *CBCMessage) SelectByPage(pageNum int, pageSize int) ([]model.CBCMessage, int, error) {
// var tickets []model.CBCMessage
// var total int64
// // 统计总数
// if err := db.DB("").Table("cbc_message").Count(&total).Error; err != nil {
// return nil, 0, fmt.Errorf("failed to count CBC message: %w", err)
// }
// // 分页查询
// offset := (pageNum - 1) * pageSize
// if err := db.DB("").Table("cbc_message").
// Limit(pageSize).
// Offset(offset).
// Find(&tickets).Error; err != nil {
// return nil, 0, fmt.Errorf("failed to select CBC message: %w", err)
// }
// return tickets, int(total), nil
// }
// InsertCBCMessage 插入CB消息
// @Description 插入CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// CBCMessage.InsertCBCMessage(msg)
func (s *CBCMessage) Insert(msg model.CBCMessage) error {
// 这里可以使用ORM或其他方式将ticket插入到数据库中
if err := db.DB("").Table("cbc_message").Create(&msg).Error; err != nil {
return fmt.Errorf("failed to insert CBC message: %w", err)
}
return nil
}
// SelectCBCMessageById 根据工单ID查询CB消息
// @Description 根据工单ID查询CB消息
// @param id 工单ID
// @return *model.CBCMessage CB消息对象
// @return error 错误信息
// @example
// CBCMessage.SelectCBCMessageById(12345)
func (s *CBCMessage) SelectById(id int64) (*model.CBCMessage, error) {
var msg model.CBCMessage
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
First(&msg).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, fmt.Errorf("failed to select CBC message: %w", err)
}
return &msg, nil
}
// SelectByEventName 根据事件名称查询CB消息
func (s *CBCMessage) SelectByEventName(eventName string) (*model.CBCMessage, error) {
var msg model.CBCMessage
if err := db.DB("").Table("cbc_message").
Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName).
First(&msg).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return &msg, nil
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// mfCBCMessageService.UpdateCBCMessage(msg)
func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error {
now := time.Now().UnixMicro()
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
Updates(map[string]interface{}{
"message_json": messageJson,
"updated_at": now,
}).Error; err != nil {
return fmt.Errorf("failed to update CBC message: %w", err)
}
return nil
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// UpdateCBCMessageDetail(msg)
func (s *CBCMessage) UpdateDetail(eventName, detail string) error {
now := time.Now().UnixMicro()
if err := db.DB("").Table("cbc_message").
Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName).
Updates(map[string]any{
"detail": detail,
"updated_at": now,
}).Error; err != nil {
return fmt.Errorf("failed to update CBC message: %w", err)
}
return nil
}
// DeleteCBCMessage 删除CB消息
// @Description 删除CB消息
// @param id 工单ID
// @return error 错误信息
// @example
// DeleteCBCMessage(12345)
func (s *CBCMessage) Delete(id int64) error {
// 执行删除操作
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
Delete(&model.CBCMessage{}).Error; err != nil {
return fmt.Errorf("failed to delete CBC message: %w", err)
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateStatus(id int64, status model.CBCEventStatus) error {
// 更新数据库状态
now := time.Now().UnixMicro()
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
Updates(map[string]interface{}{
"status": status,
"updated_at": now,
}).Error; err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
return nil
}
// Select 查询所有CB消息
func (s *CBCMessage) Select(msgs *[]model.CBCMessage) error {
if err := db.DB("").Table("cbc_message").Find(&msgs).Error; err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
return nil
}
// SelectByNeId 根据网元ID查询CB消息
func (s *CBCMessage) SelectByNeId(neId string, msgs *[]model.CBCMessage) error {
if err := db.DB("").Table("cbc_message").Where("ne_id = ?", neId).Find(&msgs).Error; err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
return nil
}
// 假设 query.StartTime 和 query.EndTime 是 "2006-01-02 15:04:05" 格式字符串
func parseTimeToMicro(ts string) (int64, error) {
if ts == "" {
return 0, nil
}
t, err := time.ParseInLocation("2006-01-02 15:04:05", ts, time.Local)
if err != nil {
return 0, err
}
return t.UnixMicro(), nil
}

View File

@@ -0,0 +1,453 @@
package service
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/file"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
neService "be.ems/src/modules/network_element/service"
"gorm.io/gorm"
)
// 实例化数据层 CBCMessage 结构体
var NewCBCMessage = &CBCMessage{
cbcMessageRepository: repository.NewCBCMessage,
}
// CBCMessage CB消息 服务层处理
type CBCMessage struct {
cbcMessageRepository *repository.CBCMessage // UE会话事件数据信息
}
// SelectByPage 根据条件分页查询CB消息
func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessage, int, error) {
return s.cbcMessageRepository.SelectByPage(query)
}
// SelectCBCMessageById 根据工单ID查询CB消息
// @Description 根据工单ID查询CB消息
// @param id 工单ID
// @return *model.CBCMessage CB消息对象
// @return error 错误信息
// @example
// CBCMessage.SelectCBCMessageById(12345)
func (s *CBCMessage) SelectById(id int64) (*model.CBCMessage, error) {
return s.cbcMessageRepository.SelectById(id)
}
func (s *CBCMessage) Insert(msg model.CBCMessage) error {
// 解析messageJson获取eventName
var messageData map[string]interface{}
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
return fmt.Errorf("failed to parse message_json: %w", err)
}
// 提取eventName
eventName, ok := messageData["eventName"].(string)
if !ok || eventName == "" {
return fmt.Errorf("eventName is required in message_json")
}
// 检查是否已存在相同的eventName
var err error
var existingMsg *model.CBCMessage
if existingMsg, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil {
return fmt.Errorf("failed to check existing CBC message: %w", err)
}
if existingMsg != nil {
return fmt.Errorf("CBC message with eventName '%s' already exists for neType '%s' and neId '%s'",
eventName, existingMsg.NeType, existingMsg.NeId)
}
return s.cbcMessageRepository.Insert(msg)
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// mfCBCMessageService.UpdateCBCMessage(msg)
func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error {
// 解析messageJson获取eventName
var messageData map[string]interface{}
if err := json.Unmarshal(messageJson, &messageData); err != nil {
return fmt.Errorf("failed to parse message_json: %w", err)
}
// 提取eventName
eventName, ok := messageData["eventName"].(string)
if !ok || eventName == "" {
return fmt.Errorf("eventName is required in message_json")
}
// 检查是否已存在相同的eventName
var err error
var msg *model.CBCMessage
if msg, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("no existing CBC message found with eventName: %s", eventName)
}
return fmt.Errorf("failed to query existing CBC message: %w", err)
}
// 如果存在,更新记录
if err := s.cbcMessageRepository.Update(id, messageJson); err != nil {
return fmt.Errorf("failed to update CBC message: %w", err)
}
// 如果状态是ACTIVE发送更新请求
if msg.Status == model.CBCEventStatusActive {
if err := s.sendUpdateRequest(*msg); err != nil {
return fmt.Errorf("failed to send update request: %w", err)
}
}
return nil
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// UpdateCBCMessageDetail(msg)
func (s *CBCMessage) UpdateDetail(eventName, detail string) error {
if err := s.cbcMessageRepository.UpdateDetail(eventName, detail); err != nil {
return fmt.Errorf("failed to update CBC message detail: %w", err)
}
return nil
}
// DeleteCBCMessage 删除CB消息
// @Description 删除CB消息
// @param id 工单ID
// @return error 错误信息
// @example
// mfCBCMessageService.DeleteCBCMessage(12345)
func (s *CBCMessage) Delete(id int64) error {
// 先查询记录状态
var err error
var msg *model.CBCMessage
if msg, err = s.cbcMessageRepository.SelectById(id); err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("CBC message with ID %d not found", id)
}
return fmt.Errorf("failed to query CBC message: %w", err)
}
// 检查状态是否为ACTIVE
if msg.Status == model.CBCEventStatusActive {
return fmt.Errorf("cannot delete an active CBC message (ID: %d)", id)
}
// 执行删除操作
if err := s.cbcMessageRepository.Delete(id); err != nil {
return fmt.Errorf("failed to delete CBC message: %w", err)
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateStatus(id int64, status string) error {
newStatus := model.ParseCBCEventStatus(status)
// 查询所有需要更新的记录
var err error
var msg *model.CBCMessage
if msg, err = s.cbcMessageRepository.SelectById(id); err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("CBC message with ID %d not found", id)
}
return fmt.Errorf("failed to query CBC message: %w", err)
}
oldStatus := msg.Status
// 检查状态是否发生变化
if oldStatus == newStatus {
return fmt.Errorf("CBC message status is already %s", newStatus.Enum())
}
// 更新数据库状态
if err := s.cbcMessageRepository.UpdateStatus(id, newStatus); err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
// 根据状态变化发送HTTP请求
if err := s.handleStatusChange(*msg, oldStatus, newStatus); err != nil {
// 记录错误但不中断处理其他消息
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateStatusByNeId(neId string, status string) error {
newStatus := model.ParseCBCEventStatus(status)
// 查询所有需要更新的记录
msgs := make([]model.CBCMessage, 0)
if err := s.cbcMessageRepository.SelectByNeId(neId, &msgs); err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
for _, msg := range msgs {
oldStatus := msg.Status
// 检查状态是否发生变化
if oldStatus == newStatus {
continue // 状态没有变化,跳过
}
// 更新数据库状态
if err := s.cbcMessageRepository.UpdateStatus(msg.Id, newStatus); err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
// 根据状态变化发送HTTP请求
if err := s.handleStatusChange(msg, oldStatus, newStatus); err != nil {
// 记录错误但不中断处理其他消息
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
}
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateAllStatus(status string) error {
newStatus := model.ParseCBCEventStatus(status)
// 查询所有需要更新的记录
msgs := make([]model.CBCMessage, 0)
if err := s.cbcMessageRepository.Select(&msgs); err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
for _, msg := range msgs {
oldStatus := msg.Status
// 检查状态是否发生变化
if oldStatus == newStatus {
continue // 状态没有变化,跳过
}
// 更新数据库状态
if err := s.cbcMessageRepository.UpdateStatus(msg.Id, newStatus); err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
// 根据状态变化发送HTTP请求
if err := s.handleStatusChange(msg, oldStatus, newStatus); err != nil {
// 记录错误但不中断处理其他消息
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
}
}
return nil
}
// ExportXlsx 导出数据到 xlsx 文件
func (r CBCMessage) ExportXlsx(rows []model.CBCMessage, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": i18n.TKey(language, "alarm.export.alarmType"),
"B1": i18n.TKey(language, "alarm.export.origSeverity"),
"C1": i18n.TKey(language, "alarm.export.alarmTitle"),
"D1": i18n.TKey(language, "alarm.export.eventTime"),
"E1": i18n.TKey(language, "alarm.export.alarmId"),
"F1": i18n.TKey(language, "alarm.export.alarmCode"),
"G1": i18n.TKey(language, "ne.common.neType"),
"H1": i18n.TKey(language, "ne.common.neName"),
"I1": i18n.TKey(language, "ne.common.neId"),
}
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
cells := map[string]any{
"A" + idx: row.NeType,
"B" + idx: row.NeId,
"C" + idx: row.MessageJson, // 这里假设 MessageJson 已经是字符串格式
"D" + idx: row.Status.Enum(),
"E" + idx: row.Detail,
"F" + idx: time.Unix(row.CreatedAt, 0).Format(time.RFC3339),
"G" + idx: time.Unix(*row.UpdatedAt, 0).Format(time.RFC3339),
}
dataCells = append(dataCells, cells)
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// handleStatusChange 处理状态变化时的HTTP请求
func (s *CBCMessage) handleStatusChange(msg model.CBCMessage, oldStatus, newStatus model.CBCEventStatus) error {
// 从NULL/INACTIVE状态修改为ACTIVE
if (oldStatus == model.CBCEventStatusNull || oldStatus == model.CBCEventStatusInactive) &&
newStatus == model.CBCEventStatusActive {
return s.sendActivateRequest(msg)
}
// 从ACTIVE更改为INACTIVE状态
if oldStatus == model.CBCEventStatusActive && newStatus == model.CBCEventStatusInactive {
return s.sendDeactivateRequest(msg)
}
return nil
}
// getCBCNetworkElement 获取CBC网元的IP和端口信息
// 这个方法需要根据你的实际网元管理系统来实现
func (s *CBCMessage) getCBCNetworkElement(neId string) (string, int64, error) {
// 查询网元信息
neInfo := neService.NewNeInfo.FindByNeTypeAndNeID("CBC", neId)
if neInfo.IP == "" {
return "", 0, fmt.Errorf("CBC network element not found for neId: %s", neId)
}
return neInfo.IP, neInfo.Port, nil
}
// CBCHTTPClient CBC网元HTTP客户端
type CBCHTTPClient struct {
client *http.Client
baseURL string
}
// NewCBCHTTPClient 创建CBC HTTP客户端
func NewCBCHTTPClient(baseURL string) *CBCHTTPClient {
return &CBCHTTPClient{
client: &http.Client{
Timeout: 10 * time.Second,
},
baseURL: baseURL,
}
}
// PostMessage 发送POST请求创建消息
func (c *CBCHTTPClient) PostMessage(messageData []byte) error {
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
return c.sendRequest("POST", url, messageData)
}
// PutMessage 发送PUT请求更新消息
func (c *CBCHTTPClient) PutMessage(messageData []byte) error {
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
return c.sendRequest("PUT", url, messageData)
}
// DeleteMessage 发送DELETE请求删除消息
func (c *CBCHTTPClient) DeleteMessage(eventName string, deletePayload []byte) error {
url := fmt.Sprintf("%s/api/v1/cbe/message/%s", c.baseURL, eventName)
return c.sendRequest("DELETE", url, deletePayload)
}
// sendRequest 发送HTTP请求
func (c *CBCHTTPClient) sendRequest(method, url string, body []byte) error {
req, err := http.NewRequest(method, url, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("failed to create %s request: %w", method, err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return fmt.Errorf("failed to send %s request: %w", method, err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("%s request failed with status: %d, body: %s",
method, resp.StatusCode, string(body))
}
return nil
}
// 在CBCMessageService中添加方法
func (s *CBCMessage) getCBCHTTPClient(neId string) (*CBCHTTPClient, error) {
cbcIP, cbcPort, err := s.getCBCNetworkElement(neId)
if err != nil {
return nil, fmt.Errorf("failed to get CBC network element info: %w", err)
}
baseURL := fmt.Sprintf("http://%s:%d", cbcIP, cbcPort)
return NewCBCHTTPClient(baseURL), nil
}
// 重构后的激活请求
func (s *CBCMessage) sendActivateRequest(msg model.CBCMessage) error {
client, err := s.getCBCHTTPClient(msg.NeId)
if err != nil {
return err
}
return client.PostMessage(msg.MessageJson)
}
// 重构后的更新请求
func (s *CBCMessage) sendUpdateRequest(msg model.CBCMessage) error {
client, err := s.getCBCHTTPClient(msg.NeId)
if err != nil {
return err
}
return client.PutMessage(msg.MessageJson)
}
// 重构后的停用请求
func (s *CBCMessage) sendDeactivateRequest(msg model.CBCMessage) error {
client, err := s.getCBCHTTPClient(msg.NeId)
if err != nil {
return err
}
// 解析和构造删除载荷的逻辑保持不变
var messageData map[string]interface{}
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
return fmt.Errorf("failed to parse message_json: %w", err)
}
eventName, ok := messageData["eventName"].(string)
if !ok || eventName == "" {
return fmt.Errorf("eventName not found in message_json")
}
deletePayload := make(map[string]interface{})
if messageIdProfile, exists := messageData["messageIdProfile"]; exists {
deletePayload["messageIdProfile"] = messageIdProfile
}
if warningAreaList, exists := messageData["warningAreaList"]; exists {
deletePayload["warningAreaList"] = warningAreaList
}
payloadBytes, err := json.Marshal(deletePayload)
if err != nil {
return fmt.Errorf("failed to marshal delete payload: %w", err)
}
return client.DeleteMessage(eventName, payloadBytes)
}

View File

@@ -696,3 +696,27 @@ func (s APIRestController) QuerySystemState(c *gin.Context) {
func (s APIRestController) NeConfigOMC(c *gin.Context) {
c.JSON(204, nil)
}
// @Description CBSManagement CB消息
type CBSState struct {
NeName string `json:"neName"` // 网元名称
RmUID string `json:"rmUID"` // 网元唯一标识
EventData []oamService.CBSEventData `json:"eventData"` // 事件数据
}
func (s APIRestController) ResolveCBSState(c *gin.Context) {
var state CBSState
if err := c.ShouldBindBodyWithJSON(&state); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
for _, eventData := range state.EventData {
if err := oamService.NewCBS.Resolve(eventData); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.JSON(200, resp.Ok(nil))
}

View File

@@ -33,6 +33,7 @@ func Setup(router *gin.Engine) {
aprRestGroup.POST("/cdrManagement/v1/elementType/:elementTypeValue/objectType/cdrEvent", aprRest.ResolveCDR)
aprRestGroup.POST("/performanceManagement/v1/elementType/:elementTypeValue/objectType/kpiReport/:index", aprRest.ResolveKPI)
aprRestGroup.POST("/ueManagement/v1/elementType/:elementTypeValue/objectType/nbState", aprRest.ResolveNBState)
aprRestGroup.POST("/ueManagement/v1/elementType/:elementTypeValue/objectType/cbsState", aprRest.ResolveCBSState)
aprRestGroup.POST("/logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent", aprRest.ResolveUENB)
router.POST("/upload-ue/v1/:eventType", aprRest.ResolveUENBByAMF) // AMF特殊上报
aprRestGroup.GET("/systemManagement/v1/elementType/:elementTypeValue/objectType/systemState", aprRest.QuerySystemState)

View File

@@ -0,0 +1,29 @@
package service
import (
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
)
// 实例化服务层 CDR 结构体
var NewCBS = &CBS{
neInfoService: neService.NewNeInfo,
cbcMessageService: neDataService.NewCBCMessage,
}
// CDR 消息处理
type CBS struct {
neInfoService *neService.NeInfo
cbcMessageService *neDataService.CBCMessage // CDR会话事件服务
}
type CBSEventData struct {
EventName string `json:"eventName"` // 事件名称
MessageId int64 `json:"messageId"` // 消息ID
Detail string `json:"detail"` // 详情
}
// Resolve 接收处理
func (s *CBS) Resolve(c CBSEventData) error {
return s.cbcMessageService.UpdateDetail(c.EventName, c.Detail)
}