From 04f709711da0be83a287215480e2a5bbbbde81ee Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 2 Jul 2025 11:05:10 +0800 Subject: [PATCH 01/80] =?UTF-8?q?sql:=20=E6=B7=BB=E5=8A=A0IMS=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=8C=87=E6=A0=87IDD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/kpi_c_title.sql | 2 ++ .../database/lite/upgrade/upg_kpi_c_title.sql | 2 ++ build/database/std/install/kpi_c_title.sql | 4 ++- .../database/std/upgrade/upg_kpi_c_title.sql | 32 ++++++++++--------- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/build/database/lite/install/kpi_c_title.sql b/build/database/lite/install/kpi_c_title.sql index 19ed5903..f235d713 100644 --- a/build/database/lite/install/kpi_c_title.sql +++ b/build/database/lite/install/kpi_c_title.sql @@ -52,3 +52,5 @@ INSERT INTO "kpi_c_title" VALUES (90, 'IMS', 'IMS.C.01', 'InitReg_Success_Rate', INSERT INTO "kpi_c_title" VALUES (91, 'IMS', 'IMS.C.02', 'MO_Success_Rate', '(''SCSCF.05''/''SCSCF.06'')*100', '%', '', '1', 'admin', 1739362260083); INSERT INTO "kpi_c_title" VALUES (92, 'IMS', 'IMS.C.03', 'MT_Success_Rate', '(''SCSCF.07''/''SCSCF.08'')*100', '%', '', '1', 'admin', 1739362260083); INSERT INTO "kpi_c_title" VALUES (93, 'IMS', 'IMS.C.04', 'Service_Success_Rate', '((''SCSCF.05''+''SCSCF.07'')/(''SCSCF.06''+''SCSCF.08''))*100', '%', '', '1', 'admin', 1739362260083); +INSERT INTO "kpi_c_title" VALUES (94, 'IMS', 'IMS.C.05', 'IDDOutgoing_Success_Rate', '(''IDD.03''/''IDD.01'')*100', '%', '', '1', 'admin', 1739362260083); +INSERT INTO "kpi_c_title" VALUES (95, 'IMS', 'IMS.C.06', 'IDDIncoming_Success_Rate', '(''IDD.06''/''IDD.04'')*100', '%', '', '1', 'admin', 1739362260083); diff --git a/build/database/lite/upgrade/upg_kpi_c_title.sql b/build/database/lite/upgrade/upg_kpi_c_title.sql index 9e683954..912241e8 100644 --- a/build/database/lite/upgrade/upg_kpi_c_title.sql +++ b/build/database/lite/upgrade/upg_kpi_c_title.sql @@ -53,3 +53,5 @@ REPLACE INTO "kpi_c_title" VALUES (90, 'IMS', 'IMS.C.01', 'InitReg_Success_Rate' REPLACE INTO "kpi_c_title" VALUES (91, 'IMS', 'IMS.C.02', 'MO_Success_Rate', '(''SCSCF.05''/''SCSCF.06'')*100', '%', '', '1', 'admin', 1739362260083); REPLACE INTO "kpi_c_title" VALUES (92, 'IMS', 'IMS.C.03', 'MT_Success_Rate', '(''SCSCF.07''/''SCSCF.08'')*100', '%', '', '1', 'admin', 1739362260083); REPLACE INTO "kpi_c_title" VALUES (93, 'IMS', 'IMS.C.04', 'Service_Success_Rate', '((''SCSCF.05''+''SCSCF.07'')/(''SCSCF.06''+''SCSCF.08''))*100', '%', '', '1', 'admin', 1739362260083); +REPLACE INTO "kpi_c_title" VALUES (94, 'IMS', 'IMS.C.05', 'IDDOutgoing_Success_Rate', '(''IDD.03''/''IDD.01'')*100', '%', '', '1', 'admin', 1739362260083); +REPLACE INTO "kpi_c_title" VALUES (95, 'IMS', 'IMS.C.06', 'IDDIncoming_Success_Rate', '(''IDD.06''/''IDD.04'')*100', '%', '', '1', 'admin', 1739362260083); diff --git a/build/database/std/install/kpi_c_title.sql b/build/database/std/install/kpi_c_title.sql index 55fa97ad..7b4e5e10 100644 --- a/build/database/std/install/kpi_c_title.sql +++ b/build/database/std/install/kpi_c_title.sql @@ -25,7 +25,7 @@ INSERT INTO `kpi_c_title` VALUES (4, 'AMF', 'AMF.C.04', '5G Register Subscriber' INSERT INTO `kpi_c_title` VALUES (20, 'SMF', 'SMF.C.01', 'SA_MeanPduSession', '\'SMF.01\'', ' ', '', '1', 'admin', 1739362260083); INSERT INTO `kpi_c_title` VALUES (21, 'SMF', 'SMF.C.02', 'PDU Session Establishment Success Rate', '(\'SMF.02\'/\'SMF.03\')*100', '%', '', '1', 'admin', 1739362260083); INSERT INTO `kpi_c_title` VALUES (22, 'SMF', 'SMF.C.03', 'IMS Session Establishment Success Rate', '(\'SMF.04\'/\'SMF.05\')*100', '%', '', '1', 'admin', 1739362260083); -INSERT INTO `kpi_c_title` VALUES (23, 'SMF', 'SMF.C.06', 'IMS_DefaultBear_Success_Rate ', '(\'SMF.13\'/\'SMF.14\')*100', '%', '', '1', 'admin', 1739362260083); +INSERT INTO `kpi_c_title` VALUES (23, 'SMF', 'SMF.C.06', 'IMS_DefaultBear_Success_Rate', '(\'SMF.13\'/\'SMF.14\')*100', '%', '', '1', 'admin', 1739362260083); INSERT INTO `kpi_c_title` VALUES (24, 'SMF', 'SMF.C.07', 'Bear_Success_Rate_new', '((\'SMF.09\'+\'SMF.11\')/(\'SMF.10\'+\'SMF.12\') )*100', '%', '', '0', 'admin', 1739362260083); INSERT INTO `kpi_c_title` VALUES (40, 'MME', 'MME.C.01', 'Combine Attach Success Rate', '(\'MME.A.05\'/\'MME.A.04\')*100', '%', '', '1', 'admin', 1739362260083); @@ -46,3 +46,5 @@ INSERT INTO `kpi_c_title` VALUES (90, 'IMS', 'IMS.C.01', 'InitReg_Success_Rate', INSERT INTO `kpi_c_title` VALUES (91, 'IMS', 'IMS.C.02', 'MO_Success_Rate', '(\'SCSCF.05\'/\'SCSCF.06\')*100', '%', '', '1', 'admin', 1739362260083); INSERT INTO `kpi_c_title` VALUES (92, 'IMS', 'IMS.C.03', 'MT_Success_Rate', '(\'SCSCF.07\'/\'SCSCF.08\')*100', '%', '', '1', 'admin', 1739362260083); INSERT INTO `kpi_c_title` VALUES (93, 'IMS', 'IMS.C.04', 'Service_Success_Rate', '((\'SCSCF.05\'+\'SCSCF.07\')/(\'SCSCF.06\'+\'SCSCF.08\'))*100', '%', '', '1', 'admin', 1739362260083); +INSERT INTO `kpi_c_title` VALUES (94, 'IMS', 'IMS.C.05', 'IDDOutgoing_Success_Rate', '(\'IDD.03\'/\'IDD.01\')*100', '%', '', '1', 'admin', 1739362260083); +INSERT INTO `kpi_c_title` VALUES (95, 'IMS', 'IMS.C.06', 'IDDIncoming_Success_Rate', '(\'IDD.06\'/\'IDD.04\')*100', '%', '', '1', 'admin', 1739362260083); diff --git a/build/database/std/upgrade/upg_kpi_c_title.sql b/build/database/std/upgrade/upg_kpi_c_title.sql index 28e3c566..d7d08d68 100644 --- a/build/database/std/upgrade/upg_kpi_c_title.sql +++ b/build/database/std/upgrade/upg_kpi_c_title.sql @@ -19,6 +19,20 @@ CREATE TABLE IF NOT EXISTS `kpi_c_title` ( UNIQUE KEY `idx_ne_kpi_id` (`ne_type`,`kpi_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='KPI_自定义指标标题'; +-- ---------------------------- +-- COLUMN for kpi_c_title +-- ---------------------------- +ALTER TABLE `kpi_c_title` MODIFY COLUMN `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `id`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `kpi_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `ne_type`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `kpi_id`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `expression` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `title`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `unit` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `expression`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `unit`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '0-Inactive/1-Active/2-Deleted' AFTER `description`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `created_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `status`; +ALTER TABLE `kpi_c_title` MODIFY COLUMN `updated_at` bigint(20) NULL DEFAULT 0 AFTER `created_by`; +ALTER TABLE `kpi_c_title` COMMENT = 'KPI_自定义指标标题'; + -- ---------------------------- -- Data for kpi_c_title -- ---------------------------- @@ -31,7 +45,7 @@ REPLACE INTO `kpi_c_title` VALUES (4, 'AMF', 'AMF.C.04', '5G Register Subscriber REPLACE INTO `kpi_c_title` VALUES (20, 'SMF', 'SMF.C.01', 'SA_MeanPduSession', '\'SMF.01\'', ' ', '', '1', 'admin', 1739362260083); REPLACE INTO `kpi_c_title` VALUES (21, 'SMF', 'SMF.C.02', 'PDU Session Establishment Success Rate', '(\'SMF.02\'/\'SMF.03\')*100', '%', '', '1', 'admin', 1739362260083); REPLACE INTO `kpi_c_title` VALUES (22, 'SMF', 'SMF.C.03', 'IMS Session Establishment Success Rate', '(\'SMF.04\'/\'SMF.05\')*100', '%', '', '1', 'admin', 1739362260083); -REPLACE INTO `kpi_c_title` VALUES (23, 'SMF', 'SMF.C.06', 'IMS_DefaultBear_Success_Rate ', '(\'SMF.13\'/\'SMF.14\')*100', '%', '', '1', 'admin', 1739362260083); +REPLACE INTO `kpi_c_title` VALUES (23, 'SMF', 'SMF.C.06', 'IMS_DefaultBear_Success_Rate', '(\'SMF.13\'/\'SMF.14\')*100', '%', '', '1', 'admin', 1739362260083); REPLACE INTO `kpi_c_title` VALUES (24, 'SMF', 'SMF.C.07', 'Bear_Success_Rate_new', '((\'SMF.09\'+\'SMF.11\')/(\'SMF.10\'+\'SMF.12\') )*100', '%', '', '0', 'admin', 1739362260083); REPLACE INTO `kpi_c_title` VALUES (40, 'MME', 'MME.C.01', 'Combine Attach Success Rate', '(\'MME.A.05\'/\'MME.A.04\')*100', '%', '', '1', 'admin', 1739362260083); @@ -52,19 +66,7 @@ REPLACE INTO `kpi_c_title` VALUES (90, 'IMS', 'IMS.C.01', 'InitReg_Success_Rate' REPLACE INTO `kpi_c_title` VALUES (91, 'IMS', 'IMS.C.02', 'MO_Success_Rate', '(\'SCSCF.05\'/\'SCSCF.06\')*100', '%', '', '1', 'admin', 1739362260083); REPLACE INTO `kpi_c_title` VALUES (92, 'IMS', 'IMS.C.03', 'MT_Success_Rate', '(\'SCSCF.07\'/\'SCSCF.08\')*100', '%', '', '1', 'admin', 1739362260083); REPLACE INTO `kpi_c_title` VALUES (93, 'IMS', 'IMS.C.04', 'Service_Success_Rate', '((\'SCSCF.05\'+\'SCSCF.07\')/(\'SCSCF.06\'+\'SCSCF.08\'))*100', '%', '', '1', 'admin', 1739362260083); - --- ---------------------------- --- COLUMN for kpi_c_title --- ---------------------------- -ALTER TABLE `kpi_c_title` MODIFY COLUMN `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `id`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `kpi_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `ne_type`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `kpi_id`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `expression` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `title`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `unit` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `expression`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `unit`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '0-Inactive/1-Active/2-Deleted' AFTER `description`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `created_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `status`; -ALTER TABLE `kpi_c_title` MODIFY COLUMN `updated_at` bigint(20) NULL DEFAULT 0 AFTER `created_by`; -ALTER TABLE `kpi_c_title` COMMENT = 'KPI_自定义指标标题'; +REPLACE INTO `kpi_c_title` VALUES (94, 'IMS', 'IMS.C.05', 'IDDOutgoing_Success_Rate', '(\'IDD.03\'/\'IDD.01\')*100', '%', '', '1', 'admin', 1739362260083); +REPLACE INTO `kpi_c_title` VALUES (95, 'IMS', 'IMS.C.06', 'IDDIncoming_Success_Rate', '(\'IDD.06\'/\'IDD.04\')*100', '%', '', '1', 'admin', 1739362260083); SET FOREIGN_KEY_CHECKS = 1; From b6f3a53d945d1c2674f9f73eac38a7c0a14338a1 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 2 Jul 2025 14:52:00 +0800 Subject: [PATCH 02/80] =?UTF-8?q?sql=20=E6=9B=B4=E6=96=B0SMSC=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/common/ne_config.sql | 10 +++++----- build/database/std/common/ne_config.sql | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/database/lite/common/ne_config.sql b/build/database/lite/common/ne_config.sql index da6dc9ae..8b417820 100644 --- a/build/database/lite/common/ne_config.sql +++ b/build/database/lite/common/ne_config.sql @@ -144,11 +144,11 @@ INSERT INTO "ne_config" VALUES (261, 'OMC', 'alarmSMSForward', 'Alarm SMS Forwar INSERT INTO "ne_config" VALUES (262, 'OMC', 'trace', 'NE Signaling Trace', 'list', '[{"access":"read-write","comment":"enable or disable NE signaling trace creation","display":"Enable","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enabled","type":"bool","value":"false"},{"access":"read-write","comment":"NE signaling trace host address","display":"Host","filter":"0~128","name":"host","type":"ipv4","value":"172.16.5.100"},{"access":"read-write","comment":"NE signaling trace port","display":"Port","filter":"3000~65530","name":"port","type":"int","value":"33033"}]', 1, '', 1750993234209, 'public'); -- 更新 SMSC 配置 2025521 -INSERT INTO "ne_config" VALUES (280, 'SMSC', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"cdrFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SM Validity\",\"filter\":\"0-2147483647\",\"name\":\"smValidity\",\"type\":\"int\",\"value\":\"259200\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"logFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable local users.\",\"display\":\"Local Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable outbound roaming users.\",\"display\":\"Local Roaming Out Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localRoamingOutPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable inbound roaming users.\",\"display\":\"Visitor Roaming In Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"visitorRoamingInPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to other unattainable users.\",\"display\":\"Other Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"otherPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Define the maximum port number that the queue of pending SMS may grow to.\",\"display\":\"Polling Number\",\"filter\":\"0-64\",\"name\":\"pollingNumber\",\"type\":\"int\",\"value\":\"64\"},{\"access\":\"read-write\",\"comment\":\"Specify the priority parameter of SM_RP_PRI. true = High; false = Low.\",\"display\":\"Priority Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"priorityFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable TP-Reply-Path parameter in the SMS-DELIVER data unit.\",\"display\":\"TP Reply Path Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"tpReplyPathFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Number\",\"filter\":\"0~32\",\"name\":\"smscNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Domain\",\"filter\":\"0~16\",\"name\":\"smscDomain\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CSFB VoLTE Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"csfbVolteFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Camel Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"camelFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SCF Address\",\"filter\":\"0~16\",\"name\":\"scfAddress\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"If add plus then set false\",\"display\":\"MT Id Format Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mtIdFormatFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"enable mcast sms\",\"display\":\"Mcast Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mcastFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Level\",\"filter\":\"{\\\"0\\\":\\\"none\\\",\\\"1\\\":\\\"error\\\",\\\"2\\\":\\\"debug\\\"}\",\"name\":\"logLevel\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"The MB sizeof log file\",\"display\":\"Log Size\",\"filter\":\"1-1000\",\"name\":\"logSize\",\"type\":\"int\",\"value\":\"200\"},{\"access\":\"read-write\",\"comment\":\"The number of log file\",\"display\":\"Log Number\",\"filter\":\"1-20\",\"name\":\"logNum\",\"type\":\"int\",\"value\":\"10\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Directory\",\"filter\":\"0~128\",\"name\":\"logDir\",\"type\":\"string\",\"value\":\"/var/log/\"}]', 1, '', 1747799255683, 'public'); -INSERT INTO "ne_config" VALUES (281, 'SMSC', 'msisdnsegment', 'MSISDN Segment List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Start MSISDN\",\"filter\":\"0~32\",\"name\":\"startMSISDN\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"End MSISDN\",\"filter\":\"0~32\",\"name\":\"endMSISDN\",\"type\":\"string\",\"value\":\"0\"}]', 3, 'put', 1747799256006, 'public'); -INSERT INTO "ne_config" VALUES (282, 'SMSC', 'smpplink', 'SMPP Link List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~63\",\"display\":\"Index\",\"filter\":\"0~63\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Alias\",\"filter\":\"0~32\",\"name\":\"linkAlias\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Type\",\"filter\":\"{\\\"0\\\":\\\"bindTX\\\",\\\"1\\\":\\\"bindRX\\\",\\\"2\\\":\\\"bindTRX\\\"}\",\"name\":\"sessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Number\",\"filter\":\"0~32\",\"name\":\"serviceNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Data Coding Scheme\",\"filter\":\"{\\\"0\\\":\\\"smpp7def7\\\",\\\"1\\\":\\\"smpp8dcs4def7\\\",\\\"2\\\":\\\"smpp8dcs0def7\\\",\\\"16\\\":\\\"smpp7def8\\\",\\\"17\\\":\\\"smpp8dcs4def8\\\",\\\"18\\\":\\\"smpp8dcs0def8\\\",\\\"19\\\":\\\"smpp8dcs0Unpack7\\\",\\\"20\\\":\\\"smpp8dcs0ISO8859\\\"}\",\"name\":\"dataCodingScheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Platform Num\",\"filter\":\"{\\\"0\\\":\\\"plat0\\\",\\\"1\\\":\\\"plat1\\\",\\\"2\\\":\\\"ignore\\\"}\",\"name\":\"platformNum\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Time To Live\",\"filter\":\"0-2147483647\",\"name\":\"timeToLive\",\"type\":\"int\",\"value\":\"604800\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Manipulation Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"manipulationFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Type of Number\",\"filter\":\"{\\\"0\\\":\\\"unknown\\\",\\\"1\\\":\\\"international\\\",\\\"2\\\":\\\"national\\\",\\\"3\\\":\\\"networkSpecific\\\",\\\"4\\\":\\\"subscriberNumber\\\",\\\"5\\\":\\\"alphanumeric\\\",\\\"6\\\":\\\"abbreviated\\\"}\",\"name\":\"ton\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Number Plan Indicator\",\"filter\":\"{\\\"0\\\":\\\"unknown\\\",\\\"1\\\":\\\"isdn\\\",\\\"3\\\":\\\"data\\\",\\\"4\\\":\\\"telex\\\",\\\"6\\\":\\\"landMobile\\\",\\\"8\\\":\\\"national\\\",\\\"9\\\":\\\"private\\\",\\\"10\\\":\\\"ermes\\\",\\\"14\\\":\\\"internet\\\",\\\"18\\\":\\\"wapClientID\\\"}\",\"name\":\"npi\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Role Type\",\"filter\":\"{\\\"0\\\":\\\"server\\\",\\\"1\\\":\\\"client\\\"}\",\"name\":\"roleType\",\"type\":\"enum\",\"value\":\"0\"}]', 5, 'post,put,delete', 1747799256626, 'public'); -INSERT INTO "ne_config" VALUES (283, 'SMSC', 'convprefix', 'Conv Prefix List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~127\",\"display\":\"Index\",\"filter\":\"0~127\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Prefix\",\"filter\":\"0~16\",\"name\":\"prefix\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Delete Length\",\"filter\":\"0-16\",\"name\":\"deleteLength\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Add Length\",\"filter\":\"0-16\",\"name\":\"addLength\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Add Digits\",\"filter\":\"0~16\",\"name\":\"addDigits\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Number Length\",\"filter\":\"0-32\",\"name\":\"numberLength\",\"type\":\"int\",\"value\":\"0\"}]', 7, 'post,put,delete', 1747799256855, 'public'); -INSERT INTO "ne_config" VALUES (284, 'SMSC', 'smppparam', 'SMPP Param List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~31\",\"display\":\"Index\",\"filter\":\"0~31\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Alias\",\"filter\":\"0-8\",\"name\":\"linkAlias\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"udp\\\",\\\"1\\\":\\\"tcp\\\"}\",\"name\":\"linkType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Type\",\"filter\":\"{\\\"0\\\":\\\"client\\\",\\\"1\\\":\\\"server\\\"}\",\"name\":\"serverType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Type\",\"filter\":\"{\\\"0\\\":\\\"bindTX\\\",\\\"1\\\":\\\"bindRX\\\",\\\"2\\\":\\\"bindTRX\\\"}\",\"name\":\"sessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"System ID\",\"filter\":\"0-16\",\"name\":\"systemID\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"0-8\",\"name\":\"password\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"System Type\",\"filter\":\"0-12\",\"name\":\"systemType\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local GTT\",\"filter\":\"0-16\",\"name\":\"localGTT\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote GTT\",\"filter\":\"0-16\",\"name\":\"remoteGTT\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local IP\",\"filter\":\"0-32\",\"name\":\"localIP\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote IP\",\"filter\":\"0-32\",\"name\":\"remoteIP\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Init Timer\",\"filter\":\"0-65535\",\"name\":\"sessionInitTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enquire Link Timer\",\"filter\":\"0-65535\",\"name\":\"enquireLinkTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Inactivity Timer\",\"filter\":\"0-65535\",\"name\":\"inactivityTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Response Timer\",\"filter\":\"0-65535\",\"name\":\"responseTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local SSN\",\"filter\":\"0-255\",\"name\":\"localSSN\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote SSN\",\"filter\":\"0-255\",\"name\":\"remoteSSN\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"1\"}]', 9, 'put', 1747799257026, 'public'); +INSERT INTO "ne_config" VALUES (280, 'SMSC', 'system', 'System', 'list', '[{"access":"read-write","comment":"","display":"CDR Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"cdrFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"SM Validity","filter":"0-2147483647","name":"smValidity","type":"int","value":"259200"},{"access":"read-write","comment":"","display":"Log Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"logFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to unattainable local users.","display":"Local Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"localPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to unattainable outbound roaming users.","display":"Local Roaming Out Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"localRoamingOutPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to unattainable inbound roaming users.","display":"Visitor Roaming In Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"visitorRoamingInPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to other unattainable users.","display":"Other Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"otherPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Define the maximum port number that the queue of pending SMS may grow to.","display":"Polling Number","filter":"0-64","name":"pollingNumber","type":"int","value":"64"},{"access":"read-write","comment":"Specify the priority parameter of SM_RP_PRI. true = High; false = Low.","display":"Priority Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"priorityFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable TP-Reply-Path parameter in the SMS-DELIVER data unit.","display":"TP Reply Path Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"tpReplyPathFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"SMSC Number","filter":"0~32","name":"smscNumber","type":"string","value":"0"},{"access":"read-write","comment":"","display":"SMSC Domain","filter":"0~16","name":"smscDomain","type":"string","value":"0.0.0.0"},{"access":"read-write","comment":"","display":"CSFB VoLTE Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"csfbVolteFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"Camel Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"camelFlag","type":"bool","value":"0"},{"access":"read-write","comment":"","display":"SCF Address","filter":"0~16","name":"scfAddress","type":"string","value":"0.0.0.0"},{"access":"read-write","comment":"If add plus then set false","display":"MT Id Format Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"mtIdFormatFlag","type":"bool","value":"0"},{"access":"read-write","comment":"enable mcast sms","display":"Mcast Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"mcastFlag","type":"bool","value":"0"},{"access":"read-write","comment":"","display":"Log Level","filter":"{\"0\":\"none\",\"1\":\"error\",\"2\":\"debug\"}","name":"logLevel","type":"enum","value":"0"},{"access":"read-write","comment":"The MB sizeof log file","display":"Log Size","filter":"1-1000","name":"logSize","type":"int","value":"200"},{"access":"read-write","comment":"The number of log file","display":"Log Number","filter":"1-20","name":"logNum","type":"int","value":"10"},{"access":"read-write","comment":"","display":"Log Directory","filter":"0~128","name":"logDir","type":"string","value":"/var/log/"}]', 1, '', 1751438862010, 'public'); +INSERT INTO "ne_config" VALUES (281, 'SMSC', 'msisdnsegment', 'MSISDN Segment List', 'array', '[{"access":"read-only","comment":"0~15","display":"Index","filter":"0~15","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Start MSISDN","filter":"0~32","name":"startMSISDN","type":"string","value":"0"},{"access":"read-write","comment":"","display":"End MSISDN","filter":"0~32","name":"endMSISDN","type":"string","value":"0"}]', 3, 'put', 1751438862028, 'public'); +INSERT INTO "ne_config" VALUES (282, 'SMSC', 'smpplink', 'SMPP Link List', 'array', '[{"access":"read-only","comment":"0~63","display":"Index","filter":"0~63","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Link Alias","filter":"0~32","name":"linkAlias","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Session Type","filter":"{\"0\":\"bindTX\",\"1\":\"bindRX\",\"2\":\"bindTRX\"}","name":"sessionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Service Number","filter":"0~32","name":"serviceNumber","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Data Coding Scheme","filter":"{\"0\":\"smpp7def7\",\"1\":\"smpp8dcs4def7\",\"2\":\"smpp8dcs0def7\",\"16\":\"smpp7def8\",\"17\":\"smpp8dcs4def8\",\"18\":\"smpp8dcs0def8\",\"19\":\"smpp8dcs0Unpack7\",\"20\":\"smpp8dcs0ISO8859\"}","name":"dataCodingScheme","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Platform Num","filter":"{\"0\":\"plat0\",\"1\":\"plat1\",\"2\":\"ignore\"}","name":"platformNum","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Time To Live","filter":"0-2147483647","name":"timeToLive","type":"int","value":"604800"},{"access":"read-write","comment":"","display":"Manipulation Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"manipulationFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"Type of Number","filter":"{\"0\":\"unknown\",\"1\":\"international\",\"2\":\"national\",\"3\":\"networkSpecific\",\"4\":\"subscriberNumber\",\"5\":\"alphanumeric\",\"6\":\"abbreviated\"}","name":"ton","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Number Plan Indicator","filter":"{\"0\":\"unknown\",\"1\":\"isdn\",\"3\":\"data\",\"4\":\"telex\",\"6\":\"landMobile\",\"8\":\"national\",\"9\":\"private\",\"10\":\"ermes\",\"14\":\"internet\",\"18\":\"wapClientID\"}","name":"npi","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Role Type","filter":"{\"0\":\"server\",\"1\":\"client\"}","name":"roleType","type":"enum","value":"0"}]', 5, 'post,put,delete', 1751438862033, 'public'); +INSERT INTO "ne_config" VALUES (283, 'SMSC', 'convprefix', 'Conv Prefix List', 'array', '[{"access":"read-only","comment":"0~127","display":"Index","filter":"0~127","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Prefix","filter":"0~16","name":"prefix","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Delete Length","filter":"0-16","name":"deleteLength","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Add Length","filter":"0-16","name":"addLength","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Add Digits","filter":"0~16","name":"addDigits","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Number Length","filter":"0-32","name":"numberLength","type":"int","value":"0"}]', 7, 'post,put,delete', 1751438862037, 'public'); +INSERT INTO "ne_config" VALUES (284, 'SMSC', 'smppparam', 'SMPP Param List', 'array', '[{"access":"read-only","comment":"0~31","display":"Index","filter":"0~31","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Link Alias","filter":"0-8","name":"linkAlias","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"udp\",\"1\":\"tcp\"}","name":"linkType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Server Type","filter":"{\"0\":\"client\",\"1\":\"server\"}","name":"serverType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Session Type","filter":"{\"0\":\"bindTX\",\"1\":\"bindRX\",\"2\":\"bindTRX\"}","name":"sessionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"System ID","filter":"0-16","name":"systemID","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Password","filter":"0-8","name":"password","type":"string","value":"0"},{"access":"read-write","comment":"","display":"System Type","filter":"0-12","name":"systemType","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Local GTT","filter":"0-16","name":"localGTT","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Remote GTT","filter":"0-16","name":"remoteGTT","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Local IP","filter":"0-32","name":"localIP","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Remote IP","filter":"0-32","name":"remoteIP","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Session Init Timer","filter":"0-65535","name":"sessionInitTimer","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Enquire Link Timer","filter":"0-65535","name":"enquireLinkTimer","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Inactivity Timer","filter":"0-65535","name":"inactivityTimer","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Response Timer","filter":"0-65535","name":"responseTimer","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Local SSN","filter":"0-255","name":"localSSN","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Remote SSN","filter":"0-255","name":"remoteSSN","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Enable Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enable","type":"bool","value":"1"}]', 9, 'put', 1751438862041, 'public'); -- 更新 SGWC 配置 20241219 INSERT INTO "ne_config" VALUES (300, 'SGWC', 'sgwcSystem', 'System Config', 'list', '[{"access":"read-write","comment":"IPv4/IPv6/IPv4v6","display":"Local S11 IP Type","filter":"^(IPv4|IPv6|IPv4v6)$","name":"s11IpType","type":"string","value":""},{"access":"read-write","comment":"IPv4 Format","display":"Local S11 IPv4","filter":"","name":"s11Ipv4","type":"string","value":"172.16.5.80"},{"access":"read-write","comment":"IPv6 Format","display":"Local S11 IPv6","filter":"","name":"s11Ipv6","type":"string","value":""},{"access":"read-write","comment":"IPv4/IPv6/IPv4v6","display":"Local S5/S8 IP Type","filter":"^(IPv4|IPv6|IPv4v6)$","name":"s58IpType","type":"string","value":""},{"access":"read-write","comment":"IPv4 Format","display":"Local S5/S8 IPv4","filter":"","name":"s58Ipv4","type":"string","value":"172.16.5.81"},{"access":"read-write","comment":"IPv6 Format","display":"Local S5/S8 IPv6","filter":"","name":"s58Ipv6","type":"string","value":""},{"access":"read-write","comment":"IPv4/IPv6/IPv4v6","display":"Local Sx IP Type","filter":"^(IPv4|IPv6|IPv4v6)$","name":"sxIpType","type":"string","value":""},{"access":"read-write","comment":"IPv4 Format","display":"Local Sx IPv4","filter":"","name":"sxIpv4","type":"string","value":"172.16.5.81"},{"access":"read-write","comment":"IPv6 Format","display":"Local Sx IPv6","filter":"","name":"sxIpv6","type":"string","value":""}]', 1, '', 1734512800790, 'public'); diff --git a/build/database/std/common/ne_config.sql b/build/database/std/common/ne_config.sql index ec3ae400..5b4fa268 100644 --- a/build/database/std/common/ne_config.sql +++ b/build/database/std/common/ne_config.sql @@ -145,11 +145,11 @@ INSERT INTO `ne_config` VALUES (261, 'OMC', 'alarmSMSForward', 'Alarm SMS Forwar INSERT INTO `ne_config` VALUES (262, 'OMC', 'trace', 'NE Signaling Trace', 'list', '[{\"access\":\"read-write\",\"comment\":\"enable or disable NE signaling trace creation\",\"display\":\"Enable\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enabled\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"NE signaling trace host address\",\"display\":\"Host\",\"filter\":\"0~128\",\"name\":\"host\",\"type\":\"ipv4\",\"value\":\"172.16.5.100\"},{\"access\":\"read-write\",\"comment\":\"NE signaling trace port\",\"display\":\"Port\",\"filter\":\"3000~65530\",\"name\":\"port\",\"type\":\"int\",\"value\":\"33033\"}]', 1, '', 1750993234209, 'public'); -- 更新 SMSC 配置 2025521 -INSERT INTO `ne_config` VALUES (280, 'SMSC', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"cdrFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SM Validity\",\"filter\":\"0-2147483647\",\"name\":\"smValidity\",\"type\":\"int\",\"value\":\"259200\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"logFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable local users.\",\"display\":\"Local Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable outbound roaming users.\",\"display\":\"Local Roaming Out Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localRoamingOutPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable inbound roaming users.\",\"display\":\"Visitor Roaming In Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"visitorRoamingInPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to other unattainable users.\",\"display\":\"Other Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"otherPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Define the maximum port number that the queue of pending SMS may grow to.\",\"display\":\"Polling Number\",\"filter\":\"0-64\",\"name\":\"pollingNumber\",\"type\":\"int\",\"value\":\"64\"},{\"access\":\"read-write\",\"comment\":\"Specify the priority parameter of SM_RP_PRI. true = High; false = Low.\",\"display\":\"Priority Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"priorityFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable TP-Reply-Path parameter in the SMS-DELIVER data unit.\",\"display\":\"TP Reply Path Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"tpReplyPathFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Number\",\"filter\":\"0~32\",\"name\":\"smscNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Domain\",\"filter\":\"0~16\",\"name\":\"smscDomain\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CSFB VoLTE Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"csfbVolteFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Camel Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"camelFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SCF Address\",\"filter\":\"0~16\",\"name\":\"scfAddress\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"If add plus then set false\",\"display\":\"MT Id Format Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mtIdFormatFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"enable mcast sms\",\"display\":\"Mcast Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mcastFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Level\",\"filter\":\"{\\\"0\\\":\\\"none\\\",\\\"1\\\":\\\"error\\\",\\\"2\\\":\\\"debug\\\"}\",\"name\":\"logLevel\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"The MB sizeof log file\",\"display\":\"Log Size\",\"filter\":\"1-1000\",\"name\":\"logSize\",\"type\":\"int\",\"value\":\"200\"},{\"access\":\"read-write\",\"comment\":\"The number of log file\",\"display\":\"Log Number\",\"filter\":\"1-20\",\"name\":\"logNum\",\"type\":\"int\",\"value\":\"10\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Directory\",\"filter\":\"0~128\",\"name\":\"logDir\",\"type\":\"string\",\"value\":\"/var/log/\"}]', 1, '', 1747799255683, 'public'); -INSERT INTO `ne_config` VALUES (281, 'SMSC', 'msisdnsegment', 'MSISDN Segment List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Start MSISDN\",\"filter\":\"0~32\",\"name\":\"startMSISDN\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"End MSISDN\",\"filter\":\"0~32\",\"name\":\"endMSISDN\",\"type\":\"string\",\"value\":\"0\"}]', 3, 'put', 1747799256006, 'public'); -INSERT INTO `ne_config` VALUES (282, 'SMSC', 'smpplink', 'SMPP Link List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~63\",\"display\":\"Index\",\"filter\":\"0~63\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Alias\",\"filter\":\"0~32\",\"name\":\"linkAlias\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Type\",\"filter\":\"{\\\"0\\\":\\\"bindTX\\\",\\\"1\\\":\\\"bindRX\\\",\\\"2\\\":\\\"bindTRX\\\"}\",\"name\":\"sessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Number\",\"filter\":\"0~32\",\"name\":\"serviceNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Data Coding Scheme\",\"filter\":\"{\\\"0\\\":\\\"smpp7def7\\\",\\\"1\\\":\\\"smpp8dcs4def7\\\",\\\"2\\\":\\\"smpp8dcs0def7\\\",\\\"16\\\":\\\"smpp7def8\\\",\\\"17\\\":\\\"smpp8dcs4def8\\\",\\\"18\\\":\\\"smpp8dcs0def8\\\",\\\"19\\\":\\\"smpp8dcs0Unpack7\\\",\\\"20\\\":\\\"smpp8dcs0ISO8859\\\"}\",\"name\":\"dataCodingScheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Platform Num\",\"filter\":\"{\\\"0\\\":\\\"plat0\\\",\\\"1\\\":\\\"plat1\\\",\\\"2\\\":\\\"ignore\\\"}\",\"name\":\"platformNum\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Time To Live\",\"filter\":\"0-2147483647\",\"name\":\"timeToLive\",\"type\":\"int\",\"value\":\"604800\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Manipulation Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"manipulationFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Type of Number\",\"filter\":\"{\\\"0\\\":\\\"unknown\\\",\\\"1\\\":\\\"international\\\",\\\"2\\\":\\\"national\\\",\\\"3\\\":\\\"networkSpecific\\\",\\\"4\\\":\\\"subscriberNumber\\\",\\\"5\\\":\\\"alphanumeric\\\",\\\"6\\\":\\\"abbreviated\\\"}\",\"name\":\"ton\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Number Plan Indicator\",\"filter\":\"{\\\"0\\\":\\\"unknown\\\",\\\"1\\\":\\\"isdn\\\",\\\"3\\\":\\\"data\\\",\\\"4\\\":\\\"telex\\\",\\\"6\\\":\\\"landMobile\\\",\\\"8\\\":\\\"national\\\",\\\"9\\\":\\\"private\\\",\\\"10\\\":\\\"ermes\\\",\\\"14\\\":\\\"internet\\\",\\\"18\\\":\\\"wapClientID\\\"}\",\"name\":\"npi\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Role Type\",\"filter\":\"{\\\"0\\\":\\\"server\\\",\\\"1\\\":\\\"client\\\"}\",\"name\":\"roleType\",\"type\":\"enum\",\"value\":\"0\"}]', 5, 'post,put,delete', 1747799256626, 'public'); -INSERT INTO `ne_config` VALUES (283, 'SMSC', 'convprefix', 'Conv Prefix List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~127\",\"display\":\"Index\",\"filter\":\"0~127\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Prefix\",\"filter\":\"0~16\",\"name\":\"prefix\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Delete Length\",\"filter\":\"0-16\",\"name\":\"deleteLength\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Add Length\",\"filter\":\"0-16\",\"name\":\"addLength\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Add Digits\",\"filter\":\"0~16\",\"name\":\"addDigits\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Number Length\",\"filter\":\"0-32\",\"name\":\"numberLength\",\"type\":\"int\",\"value\":\"0\"}]', 7, 'post,put,delete', 1747799256855, 'public'); -INSERT INTO `ne_config` VALUES (284, 'SMSC', 'smppparam', 'SMPP Param List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~31\",\"display\":\"Index\",\"filter\":\"0~31\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Alias\",\"filter\":\"0-8\",\"name\":\"linkAlias\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"udp\\\",\\\"1\\\":\\\"tcp\\\"}\",\"name\":\"linkType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Type\",\"filter\":\"{\\\"0\\\":\\\"client\\\",\\\"1\\\":\\\"server\\\"}\",\"name\":\"serverType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Type\",\"filter\":\"{\\\"0\\\":\\\"bindTX\\\",\\\"1\\\":\\\"bindRX\\\",\\\"2\\\":\\\"bindTRX\\\"}\",\"name\":\"sessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"System ID\",\"filter\":\"0-16\",\"name\":\"systemID\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"0-8\",\"name\":\"password\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"System Type\",\"filter\":\"0-12\",\"name\":\"systemType\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local GTT\",\"filter\":\"0-16\",\"name\":\"localGTT\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote GTT\",\"filter\":\"0-16\",\"name\":\"remoteGTT\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local IP\",\"filter\":\"0-32\",\"name\":\"localIP\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote IP\",\"filter\":\"0-32\",\"name\":\"remoteIP\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Init Timer\",\"filter\":\"0-65535\",\"name\":\"sessionInitTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enquire Link Timer\",\"filter\":\"0-65535\",\"name\":\"enquireLinkTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Inactivity Timer\",\"filter\":\"0-65535\",\"name\":\"inactivityTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Response Timer\",\"filter\":\"0-65535\",\"name\":\"responseTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local SSN\",\"filter\":\"0-255\",\"name\":\"localSSN\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote SSN\",\"filter\":\"0-255\",\"name\":\"remoteSSN\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"1\"}]', 9, 'put', 1747799257026, 'public'); +INSERT INTO `ne_config` VALUES (280, 'SMSC', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"cdrFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SM Validity\",\"filter\":\"0-2147483647\",\"name\":\"smValidity\",\"type\":\"int\",\"value\":\"259200\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"logFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable local users.\",\"display\":\"Local Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable outbound roaming users.\",\"display\":\"Local Roaming Out Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localRoamingOutPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable inbound roaming users.\",\"display\":\"Visitor Roaming In Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"visitorRoamingInPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to other unattainable users.\",\"display\":\"Other Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"otherPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Define the maximum port number that the queue of pending SMS may grow to.\",\"display\":\"Polling Number\",\"filter\":\"0-64\",\"name\":\"pollingNumber\",\"type\":\"int\",\"value\":\"64\"},{\"access\":\"read-write\",\"comment\":\"Specify the priority parameter of SM_RP_PRI. true = High; false = Low.\",\"display\":\"Priority Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"priorityFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable TP-Reply-Path parameter in the SMS-DELIVER data unit.\",\"display\":\"TP Reply Path Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"tpReplyPathFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Number\",\"filter\":\"0~32\",\"name\":\"smscNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Domain\",\"filter\":\"0~16\",\"name\":\"smscDomain\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CSFB VoLTE Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"csfbVolteFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Camel Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"camelFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SCF Address\",\"filter\":\"0~16\",\"name\":\"scfAddress\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"If add plus then set false\",\"display\":\"MT Id Format Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mtIdFormatFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"enable mcast sms\",\"display\":\"Mcast Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mcastFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Level\",\"filter\":\"{\\\"0\\\":\\\"none\\\",\\\"1\\\":\\\"error\\\",\\\"2\\\":\\\"debug\\\"}\",\"name\":\"logLevel\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"The MB sizeof log file\",\"display\":\"Log Size\",\"filter\":\"1-1000\",\"name\":\"logSize\",\"type\":\"int\",\"value\":\"200\"},{\"access\":\"read-write\",\"comment\":\"The number of log file\",\"display\":\"Log Number\",\"filter\":\"1-20\",\"name\":\"logNum\",\"type\":\"int\",\"value\":\"10\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Directory\",\"filter\":\"0~128\",\"name\":\"logDir\",\"type\":\"string\",\"value\":\"/var/log/\"}]', 1, '', 1751438862010, 'public'); +INSERT INTO `ne_config` VALUES (281, 'SMSC', 'msisdnsegment', 'MSISDN Segment List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Start MSISDN\",\"filter\":\"0~32\",\"name\":\"startMSISDN\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"End MSISDN\",\"filter\":\"0~32\",\"name\":\"endMSISDN\",\"type\":\"string\",\"value\":\"0\"}]', 3, 'put', 1751438862028, 'public'); +INSERT INTO `ne_config` VALUES (282, 'SMSC', 'smpplink', 'SMPP Link List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~63\",\"display\":\"Index\",\"filter\":\"0~63\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Alias\",\"filter\":\"0~32\",\"name\":\"linkAlias\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Type\",\"filter\":\"{\\\"0\\\":\\\"bindTX\\\",\\\"1\\\":\\\"bindRX\\\",\\\"2\\\":\\\"bindTRX\\\"}\",\"name\":\"sessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Number\",\"filter\":\"0~32\",\"name\":\"serviceNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Data Coding Scheme\",\"filter\":\"{\\\"0\\\":\\\"smpp7def7\\\",\\\"1\\\":\\\"smpp8dcs4def7\\\",\\\"2\\\":\\\"smpp8dcs0def7\\\",\\\"16\\\":\\\"smpp7def8\\\",\\\"17\\\":\\\"smpp8dcs4def8\\\",\\\"18\\\":\\\"smpp8dcs0def8\\\",\\\"19\\\":\\\"smpp8dcs0Unpack7\\\",\\\"20\\\":\\\"smpp8dcs0ISO8859\\\"}\",\"name\":\"dataCodingScheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Platform Num\",\"filter\":\"{\\\"0\\\":\\\"plat0\\\",\\\"1\\\":\\\"plat1\\\",\\\"2\\\":\\\"ignore\\\"}\",\"name\":\"platformNum\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Time To Live\",\"filter\":\"0-2147483647\",\"name\":\"timeToLive\",\"type\":\"int\",\"value\":\"604800\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Manipulation Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"manipulationFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Type of Number\",\"filter\":\"{\\\"0\\\":\\\"unknown\\\",\\\"1\\\":\\\"international\\\",\\\"2\\\":\\\"national\\\",\\\"3\\\":\\\"networkSpecific\\\",\\\"4\\\":\\\"subscriberNumber\\\",\\\"5\\\":\\\"alphanumeric\\\",\\\"6\\\":\\\"abbreviated\\\"}\",\"name\":\"ton\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Number Plan Indicator\",\"filter\":\"{\\\"0\\\":\\\"unknown\\\",\\\"1\\\":\\\"isdn\\\",\\\"3\\\":\\\"data\\\",\\\"4\\\":\\\"telex\\\",\\\"6\\\":\\\"landMobile\\\",\\\"8\\\":\\\"national\\\",\\\"9\\\":\\\"private\\\",\\\"10\\\":\\\"ermes\\\",\\\"14\\\":\\\"internet\\\",\\\"18\\\":\\\"wapClientID\\\"}\",\"name\":\"npi\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Role Type\",\"filter\":\"{\\\"0\\\":\\\"server\\\",\\\"1\\\":\\\"client\\\"}\",\"name\":\"roleType\",\"type\":\"enum\",\"value\":\"0\"}]', 5, 'post,put,delete', 1751438862033, 'public'); +INSERT INTO `ne_config` VALUES (283, 'SMSC', 'convprefix', 'Conv Prefix List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~127\",\"display\":\"Index\",\"filter\":\"0~127\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Prefix\",\"filter\":\"0~16\",\"name\":\"prefix\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Delete Length\",\"filter\":\"0-16\",\"name\":\"deleteLength\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Add Length\",\"filter\":\"0-16\",\"name\":\"addLength\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Add Digits\",\"filter\":\"0~16\",\"name\":\"addDigits\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Number Length\",\"filter\":\"0-32\",\"name\":\"numberLength\",\"type\":\"int\",\"value\":\"0\"}]', 7, 'post,put,delete', 1751438862037, 'public'); +INSERT INTO `ne_config` VALUES (284, 'SMSC', 'smppparam', 'SMPP Param List', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~31\",\"display\":\"Index\",\"filter\":\"0~31\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Alias\",\"filter\":\"0-8\",\"name\":\"linkAlias\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"udp\\\",\\\"1\\\":\\\"tcp\\\"}\",\"name\":\"linkType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Type\",\"filter\":\"{\\\"0\\\":\\\"client\\\",\\\"1\\\":\\\"server\\\"}\",\"name\":\"serverType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Type\",\"filter\":\"{\\\"0\\\":\\\"bindTX\\\",\\\"1\\\":\\\"bindRX\\\",\\\"2\\\":\\\"bindTRX\\\"}\",\"name\":\"sessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"System ID\",\"filter\":\"0-16\",\"name\":\"systemID\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"0-8\",\"name\":\"password\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"System Type\",\"filter\":\"0-12\",\"name\":\"systemType\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local GTT\",\"filter\":\"0-16\",\"name\":\"localGTT\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote GTT\",\"filter\":\"0-16\",\"name\":\"remoteGTT\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local IP\",\"filter\":\"0-32\",\"name\":\"localIP\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote IP\",\"filter\":\"0-32\",\"name\":\"remoteIP\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Session Init Timer\",\"filter\":\"0-65535\",\"name\":\"sessionInitTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enquire Link Timer\",\"filter\":\"0-65535\",\"name\":\"enquireLinkTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Inactivity Timer\",\"filter\":\"0-65535\",\"name\":\"inactivityTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Response Timer\",\"filter\":\"0-65535\",\"name\":\"responseTimer\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Local SSN\",\"filter\":\"0-255\",\"name\":\"localSSN\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Remote SSN\",\"filter\":\"0-255\",\"name\":\"remoteSSN\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"1\"}]', 9, 'put', 1751438862041, 'public'); -- 更新 SGWC 配置 20241219 INSERT INTO `ne_config` VALUES (300, 'SGWC', 'sgwcSystem', 'System Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"IPv4/IPv6/IPv4v6\",\"display\":\"Local S11 IP Type\",\"filter\":\"^(IPv4|IPv6|IPv4v6)$\",\"name\":\"s11IpType\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"IPv4 Format\",\"display\":\"Local S11 IPv4\",\"filter\":\"\",\"name\":\"s11Ipv4\",\"type\":\"string\",\"value\":\"172.16.5.80\"},{\"access\":\"read-write\",\"comment\":\"IPv6 Format\",\"display\":\"Local S11 IPv6\",\"filter\":\"\",\"name\":\"s11Ipv6\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"IPv4/IPv6/IPv4v6\",\"display\":\"Local S5/S8 IP Type\",\"filter\":\"^(IPv4|IPv6|IPv4v6)$\",\"name\":\"s58IpType\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"IPv4 Format\",\"display\":\"Local S5/S8 IPv4\",\"filter\":\"\",\"name\":\"s58Ipv4\",\"type\":\"string\",\"value\":\"172.16.5.81\"},{\"access\":\"read-write\",\"comment\":\"IPv6 Format\",\"display\":\"Local S5/S8 IPv6\",\"filter\":\"\",\"name\":\"s58Ipv6\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"IPv4/IPv6/IPv4v6\",\"display\":\"Local Sx IP Type\",\"filter\":\"^(IPv4|IPv6|IPv4v6)$\",\"name\":\"sxIpType\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"IPv4 Format\",\"display\":\"Local Sx IPv4\",\"filter\":\"\",\"name\":\"sxIpv4\",\"type\":\"string\",\"value\":\"172.16.5.81\"},{\"access\":\"read-write\",\"comment\":\"IPv6 Format\",\"display\":\"Local Sx IPv6\",\"filter\":\"\",\"name\":\"sxIpv6\",\"type\":\"string\",\"value\":\"\"}]', 1, '', 1734512800790, 'public'); From add324087f36e714faff861e06cd7858eaa88f98 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 2 Jul 2025 18:28:48 +0800 Subject: [PATCH 03/80] =?UTF-8?q?sql=20=E6=9B=B4=E6=96=B0UDM=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/common/ne_config.sql | 30 ++++++++++++------------ build/database/std/common/ne_config.sql | 30 ++++++++++++------------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/build/database/lite/common/ne_config.sql b/build/database/lite/common/ne_config.sql index 8b417820..c99a77bc 100644 --- a/build/database/lite/common/ne_config.sql +++ b/build/database/lite/common/ne_config.sql @@ -97,21 +97,21 @@ INSERT INTO "ne_config" VALUES (191, 'SMF', 'dnnselectdhcpserver', 'DNN Select D INSERT INTO "ne_config" VALUES (192, 'SMF', 'offlineChargingConfig', 'Offline Charging Config', 'list', '[{"access":"read-write","comment":"","display":"CDR File Name","filter":"1~64","name":"cdrFileName","type":"string","value":"smf.cdr"},{"access":"read-write","comment":"","display":"CDR File Path","filter":"1~256","name":"cdrFilePath","type":"string","value":"/var/log/smfCdr"},{"access":"read-write","comment":"","display":"CDR File Num","filter":"1~999999999","name":"cdrFileNum","type":"int","value":"50"},{"access":"read-write","comment":"Megabytes","display":"CDR File Size","filter":"1~999999","name":"cdrFileSize","type":"int","value":"300"},{"access":"read-write","comment":"Days","display":"CDR File Max Age","filter":"0~9999","name":"cdrFileMaxAge","type":"int","value":"30"},{"access":"read-write","comment":"","display":"Free Subscribers CDR Enable","filter":"","name":"freeSubsCdrEnable","type":"bool","value":"false"},{"access":"read-write","comment":"Seconds","display":"Time Threshold","filter":"0~999999999","name":"timeThreshold","type":"int","value":"600"},{"access":"read-write","comment":"Bytes","display":"Volume Threshold","filter":"0~999999999999999","name":"volumeThreshold","type":"int","value":"0"}]', 25, '', 1751019165593, 'public'); -- 更新 UDM 配置 20250613 -INSERT INTO "ne_config" VALUES (200, 'UDM', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service IP\",\"filter\":\"\",\"name\":\"serviceIP\",\"type\":\"ipv4\",\"value\":\"172.16.5.140\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Port\",\"filter\":\"0~65535\",\"name\":\"servicePort\",\"type\":\"int\",\"value\":\"8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NRF URI\",\"filter\":\"\",\"name\":\"nrfUri\",\"type\":\"string\",\"value\":\"http://172.16.5.180:8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"FQDN\",\"filter\":\"\",\"name\":\"fqdn\",\"type\":\"string\",\"value\":\"omc.com\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"0~4095\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Capacity\",\"filter\":\"0~65535\",\"name\":\"capacity\",\"type\":\"int\",\"value\":\"4096\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group ID\",\"filter\":\"\",\"name\":\"groupId\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn1\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn1\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn2\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn2\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn3\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn3\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn4\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn4\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SUPI Ranges\",\"filter\":\"^imsi-\\\\d{15}~imsi-\\\\d{15}$\",\"name\":\"supiRanges\",\"type\":\"regex\",\"value\":\"imsi-001010100080000~imsi-001010100080099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"GPSI Ranges\",\"filter\":\"^msisdn-\\\\d{2,15}~msisdn-\\\\d{2,15}$\",\"name\":\"gpsiRanges\",\"type\":\"regex\",\"value\":\"msisdn-69072000~msisdn-69072099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"HTTP\\\", \\\"1\\\":\\\"HTTPS\\\"}\",\"name\":\"scheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Link\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"redisLink\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Address\",\"filter\":\"\",\"name\":\"redisAddr\",\"type\":\"string\",\"value\":\"172.16.5.140:6379\"}]', 1, '', 1749815867447, 'public'); -INSERT INTO "ne_config" VALUES (201, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"uplink\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"downlink\",\"type\":\"regex\",\"value\":\"2 Gbps\"}]', 5, '', 1749815867466, 'public'); -INSERT INTO "ne_config" VALUES (202, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Features\",\"filter\":\"^[0-9a-fA-F]{8}$\",\"name\":\"supportedFeatures\",\"type\":\"regex\",\"value\":\"00000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Single NSSAIs\",\"filter\":\"\",\"name\":\"defaultSingleNSSAIs\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Single NSSAIs\",\"filter\":\"\",\"name\":\"singleNssais\",\"type\":\"string\",\"value\":\"1-000002\"}]', 7, '', 1749815867471, 'public'); -INSERT INTO "ne_config" VALUES (203, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"}]', 9, '', 1749815867476, 'public'); -INSERT INTO "ne_config" VALUES (204, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Restriction Type\",\"filter\":\"{\\\"0\\\":\\\"Allowed Areas\\\", \\\"1\\\":\\\"Not Allowed Areas\\\"}\",\"name\":\"restrictionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max TAs\",\"filter\":\"^\\\\d{1,2}$\",\"name\":\"maxTAs\",\"type\":\"int\",\"value\":\"1\"}]', 11, '', 1749815867480, 'public'); -INSERT INTO "ne_config" VALUES (205, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SNSSAI\",\"filter\":\"^\\\\d{1,3}[A-Fa-f0-9]{6}$\",\"name\":\"snssai\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{1,32}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default DNN Indicator\",\"filter\":\"false;true;\",\"name\":\"defaultDnnInd\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LBO Roaming Allowed\",\"filter\":\"false;true;\",\"name\":\"lboRoamingAllowed\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"false;true;\",\"name\":\"iwkEpsInd\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"false;true;\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"false\"}],\"comment\":\"\",\"display\":\"DNN List\",\"filter\":\"1~4\",\"name\":\"dnnList\",\"type\":\"int\",\"value\":\"1\"}]', 13, '', 1749815867486, 'public'); -INSERT INTO "ne_config" VALUES (206, 'UDM', 'dnn', 'DNN Conf', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default PDU Session Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\"}\",\"name\":\"defaultPDUSessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed PDU Session Types\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\",\\\"5\\\":\\\"IPv4 \\u0026 IPv6\\\",\\\"6\\\":\\\"IPv4 \\u0026 IPv4v6\\\",\\\"7\\\":\\\"IPv6 \\u0026 IPv4v6\\\",\\\"8\\\":\\\"IPv4 \\u0026 IPv6 \\u0026 IPv4v6\\\"}\",\"name\":\"allowedPDUSessionTypes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"5QI\",\"filter\":\"0~255\",\"name\":\"5qi\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"1~127\",\"name\":\"priorityLevel\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default SSC Mode\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\"}\",\"name\":\"defaultSSCmode\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed SSC Modes\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\",\\\"3\\\":\\\"SSC Mode1 \\u0026 SSC Mode2\\\",\\\"4\\\":\\\"SSC Mode1 \\u0026 SSC Mode3\\\",\\\"5\\\":\\\"SSC Mode2 \\u0026 SSC Mode3\\\",\\\"6\\\":\\\"SSC Mode1 \\u0026 SSC Mode2 \\u0026 SSC Mode3\\\"}\",\"name\":\"allowedSSCmodes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"\",\"name\":\"interworkingEPSIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristics\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristics\",\"type\":\"string\",\"value\":\"0001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrUL\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrDL\",\"type\":\"regex\",\"value\":\"2 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Static IP Address\",\"filter\":\"\",\"name\":\"staticIPAddress\",\"type\":\"ipv4\",\"value\":\"192.168.1.100\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Integrity\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneIntegrity\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Confidentiality\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneConfidentiality\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority Level\",\"filter\":\"0~255\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"6\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"}]', 15, '', 1749815867491, 'public'); -INSERT INTO "ne_config" VALUES (207, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{0,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_eps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"APN OI Replacement\",\"filter\":\"^.{0,31}$\",\"name\":\"apnOIReplacement\",\"type\":\"string\",\"value\":\"money\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RFSP\",\"filter\":\"\",\"name\":\"rfsp\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RAU TAU Timer\",\"filter\":\"\",\"name\":\"rauTauTimer\",\"type\":\"int\",\"value\":\"120\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 17, '', 1749815867496, 'public'); -INSERT INTO "ne_config" VALUES (208, 'UDM', 'epsApn', 'EPS APN', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{0,127}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"IPv4 or IPv6\\\"}\",\"name\":\"pdnType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"QCI\",\"filter\":\"1~255\",\"name\":\"qci\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority\",\"filter\":\"1~127\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"8\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Context Identifier\",\"filter\":\"\",\"name\":\"contextIdentifier\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"VPLMN Dynamic Address Allowed\",\"filter\":\"false;true;\",\"name\":\"vplmnDynamicAddressAllowed\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN GW Allocation Type\",\"filter\":\"{\\\"0\\\":\\\"Static\\\",\\\"1\\\":\\\"Dynamic\\\"}\",\"name\":\"pdnGWAllocationType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 19, '', 1749815867501, 'public'); -INSERT INTO "ne_config" VALUES (209, 'UDM', 'applicationServer', 'Application Server', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AS Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Handling\",\"filter\":\"{\\\"0\\\":\\\"Session Continued\\\",\\\"1\\\":\\\"Session Terminated\\\"}\",\"name\":\"defaultHandling\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:192.168.8.26:7060\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Diameter Address\",\"filter\":\"^.{1,127}$\",\"name\":\"diameterAddress\",\"type\":\"string\",\"value\":\"mmtel.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Rep Data Size Limit\",\"filter\":\"0~65535\",\"name\":\"repDataSizeLimit\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Request\",\"filter\":\"false;true;\",\"name\":\"includeRegisterRequest\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Response\",\"filter\":\"false;true;\",\"name\":\"includeRegisterResponse\",\"type\":\"bool\",\"value\":\"false\"}]', 21, '', 1749815867506, 'public'); -INSERT INTO "ne_config" VALUES (210, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~8\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060\"}]', 23, '', 1749815867511, 'public'); -INSERT INTO "ne_config" VALUES (211, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Type CNF\",\"filter\":\"0~1\",\"name\":\"conditionTypeCNF\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Negated\",\"filter\":\"0~1\",\"name\":\"conditionNegated\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group\",\"filter\":\"0~4096\",\"name\":\"group\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Method\",\"filter\":\"^.{0,32}$\",\"name\":\"method\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Header\",\"filter\":\"^.{0,64}$\",\"name\":\"sipHeader\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Content\",\"filter\":\"^.{0,64}$\",\"name\":\"sipContent\",\"type\":\"string\",\"value\":\"\"}],\"comment\":\"\",\"display\":\"SPT List\",\"filter\":\"1~4\",\"name\":\"sptList\",\"type\":\"int\",\"value\":\"1\"}]', 25, '', 1749815867516, 'public'); -INSERT INTO "ne_config" VALUES (212, 'UDM', 's6aServer', 'S6a Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 27, '', 1749815867521, 'public'); -INSERT INTO "ne_config" VALUES (213, 'UDM', 'cxServer', 'Cx Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 29, '', 1749815867527, 'public'); -INSERT INTO "ne_config" VALUES (214, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EAP-Aka SupiOrImsi Prefix\",\"filter\":\"\",\"name\":\"eapAkaSupiImsiPrefix\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF FQDN\",\"filter\":\"0~128\",\"name\":\"ausfFqdn\",\"type\":\"string\",\"value\":\"ausf.5gc.com\"}]', 3, '', 1749815867461, 'public'); +INSERT INTO "ne_config" VALUES (200, 'UDM', 'system', 'System', 'list', '[{"access":"read-write","comment":"","display":"Service IP","filter":"","name":"serviceIP","type":"ipv4","value":"172.16.5.140"},{"access":"read-write","comment":"","display":"Service Port","filter":"0~65535","name":"servicePort","type":"int","value":"8080"},{"access":"read-write","comment":"","display":"NRF URI","filter":"","name":"nrfUri","type":"string","value":"http://172.16.5.180:8080"},{"access":"read-write","comment":"","display":"FQDN","filter":"","name":"fqdn","type":"string","value":"omc.com"},{"access":"read-write","comment":"","display":"Priority","filter":"0~4095","name":"priority","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Capacity","filter":"0~65535","name":"capacity","type":"int","value":"4096"},{"access":"read-write","comment":"","display":"Group ID","filter":"","name":"groupId","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Supported Plmn1","filter":"^\\d{5,6}$","name":"supportedPlmn1","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn2","filter":"^\\d{5,6}$","name":"supportedPlmn2","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn3","filter":"^\\d{5,6}$","name":"supportedPlmn3","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn4","filter":"^\\d{5,6}$","name":"supportedPlmn4","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"SUPI Ranges","filter":"^imsi-\\d{15}~imsi-\\d{15}$","name":"supiRanges","type":"regex","value":"imsi-001010100080000~imsi-001010100080099"},{"access":"read-write","comment":"","display":"GPSI Ranges","filter":"^msisdn-\\d{2,15}~msisdn-\\d{2,15}$","name":"gpsiRanges","type":"regex","value":"msisdn-69072000~msisdn-69072099"},{"access":"read-write","comment":"","display":"Scheme","filter":"{\"0\":\"HTTP\", \"1\":\"HTTPS\"}","name":"scheme","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Redis Link","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"redisLink","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Redis Address","filter":"","name":"redisAddr","type":"string","value":"172.16.5.140:6379"}]', 1, '', 1751451940555, 'public'); +INSERT INTO "ne_config" VALUES (201, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"Uplink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"uplink","type":"regex","value":"1 Gbps"},{"access":"read-write","comment":"","display":"Downlink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"downlink","type":"regex","value":"2 Gbps"}]', 5, '', 1751451940566, 'public'); +INSERT INTO "ne_config" VALUES (202, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_nssai"},{"access":"read-write","comment":"","display":"Supported Features","filter":"^[0-9a-fA-F]{8}$","name":"supportedFeatures","type":"regex","value":"00000001"},{"access":"read-write","comment":"","display":"Default Single NSSAIs","filter":"","name":"defaultSingleNSSAIs","type":"string","value":"1-000001"},{"access":"read-write","comment":"","display":"Single NSSAIs","filter":"","name":"singleNssais","type":"string","value":"1-000002"}]', 7, '', 1751451940570, 'public'); +INSERT INTO "ne_config" VALUES (203, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"TACs","filter":"","name":"tacs","type":"string","value":"123"},{"access":"read-write","comment":"","display":"Area Codes","filter":"","name":"areaCodes","type":"string","value":"123456"}]', 9, '', 1751451940574, 'public'); +INSERT INTO "ne_config" VALUES (204, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"Restriction Type","filter":"{\"0\":\"Allowed Areas\", \"1\":\"Not Allowed Areas\"}","name":"restrictionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"TACs","filter":"","name":"tacs","type":"string","value":"123"},{"access":"read-write","comment":"","display":"Area Codes","filter":"","name":"areaCodes","type":"string","value":"123456"},{"access":"read-write","comment":"","display":"Max TAs","filter":"^\\d{1,2}$","name":"maxTAs","type":"int","value":"1"}]', 11, '', 1751451940579, 'public'); +INSERT INTO "ne_config" VALUES (205, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_snssai"},{"access":"read-write","comment":"","display":"SNSSAI","filter":"^\\d{1,3}[A-Fa-f0-9]{6}$","name":"snssai","type":"string","value":"1-000001"},{"access":"read-only","array":[{"access":"read-only","comment":"","display":"Index","filter":"1~4","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"DNN","filter":"^.{1,32}$","name":"dnn","type":"string","value":"internet"},{"access":"read-write","comment":"","display":"Default DNN Indicator","filter":"false;true;","name":"defaultDnnInd","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"LBO Roaming Allowed","filter":"false;true;","name":"lboRoamingAllowed","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"Interworking EPS Indicator","filter":"false;true;","name":"iwkEpsInd","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"LADN Indicator","filter":"false;true;","name":"ladnIndicator","type":"bool","value":"false"}],"comment":"","display":"DNN List","filter":"1~4","name":"dnnList","type":"int","value":"1"}]', 13, '', 1751451940583, 'public'); +INSERT INTO "ne_config" VALUES (206, 'UDM', 'dnn', 'DNN Conf', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_nssai"},{"access":"read-write","comment":"","display":"Default PDU Session Type","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"Ethernet\",\"4\":\"Unstruction\"}","name":"defaultPDUSessionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Allowed PDU Session Types","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"Ethernet\",\"4\":\"Unstruction\",\"5\":\"IPv4 \u0026 IPv6\",\"6\":\"IPv4 \u0026 IPv4v6\",\"7\":\"IPv6 \u0026 IPv4v6\",\"8\":\"IPv4 \u0026 IPv6 \u0026 IPv4v6\"}","name":"allowedPDUSessionTypes","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"5QI","filter":"0~255","name":"5qi","type":"int","value":"9"},{"access":"read-write","comment":"","display":"Priority Level","filter":"1~127","name":"priorityLevel","type":"int","value":"9"},{"access":"read-write","comment":"","display":"Default SSC Mode","filter":"{\"0\":\"SSC Mode1\",\"1\":\"SSC Mode2\",\"2\":\"SSC Mode3\"}","name":"defaultSSCmode","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Allowed SSC Modes","filter":"{\"0\":\"SSC Mode1\",\"1\":\"SSC Mode2\",\"2\":\"SSC Mode3\",\"3\":\"SSC Mode1 \u0026 SSC Mode2\",\"4\":\"SSC Mode1 \u0026 SSC Mode3\",\"5\":\"SSC Mode2 \u0026 SSC Mode3\",\"6\":\"SSC Mode1 \u0026 SSC Mode2 \u0026 SSC Mode3\"}","name":"allowedSSCmodes","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Interworking EPS Indicator","filter":"","name":"interworkingEPSIndicator","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"LADN Indicator","filter":"","name":"ladnIndicator","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"Charging Characteristics","filter":"4~4","name":"chargingCharacteristics","type":"string","value":"0001"},{"access":"read-write","comment":"","display":"Subscribed Session AMBR Uplink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"subscribedSessionAmbrUL","type":"regex","value":"1 Gbps"},{"access":"read-write","comment":"","display":"Subscribed Session AMBR Downlink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"subscribedSessionAmbrDL","type":"regex","value":"2 Gbps"},{"access":"read-write","comment":"","display":"Static IP Address","filter":"","name":"staticIPAddress","type":"ipv4","value":"192.168.1.100"},{"access":"read-write","comment":"","display":"User Plane Integrity","filter":"{\"0\":\"Null\",\"1\":\"Required\",\"2\":\"Preferred\",\"3\":\"Not Needed\"}","name":"userPlaneIntegrity","type":"enum","value":"3"},{"access":"read-write","comment":"","display":"User Plane Confidentiality","filter":"{\"0\":\"Null\",\"1\":\"Required\",\"2\":\"Preferred\",\"3\":\"Not Needed\"}","name":"userPlaneConfidentiality","type":"enum","value":"3"},{"access":"read-write","comment":"","display":"ARP Priority Level","filter":"0~255","name":"arpPriorityLevel","type":"int","value":"6"},{"access":"read-write","comment":"","display":"ARP Preempt Capability","filter":"{\"0\":\"Not Preempt\",\"1\":\"May Preempt\"}","name":"arpPreemptCap","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"ARP Preempt Vulnerability","filter":"{\"0\":\"Not Preemptable\",\"1\":\"Preemptable\"}","name":"arpPreemptVuln","type":"enum","value":"0"}]', 15, '', 1751451940587, 'public'); +INSERT INTO "ne_config" VALUES (207, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{0,31}$","name":"name","type":"string","value":"def_eps"},{"access":"read-write","comment":"","display":"AMBR Uplink","filter":"0~4294967295","name":"ambrUplink","type":"int","value":"100000000"},{"access":"read-write","comment":"","display":"AMBR Downlink","filter":"0~4294967295","name":"ambrDownlink","type":"int","value":"200000000"},{"access":"read-write","comment":"","display":"APN OI Replacement","filter":"^.{0,31}$","name":"apnOIReplacement","type":"string","value":"money"},{"access":"read-write","comment":"","display":"RFSP","filter":"","name":"rfsp","type":"int","value":"1"},{"access":"read-write","comment":"","display":"RAU TAU Timer","filter":"","name":"rauTauTimer","type":"int","value":"120"},{"access":"read-write","comment":"","display":"Charging Characteristic","filter":"4~4","name":"chargingCharacteristic","type":"string","value":"0001"}]', 17, '', 1751451940591, 'public'); +INSERT INTO "ne_config" VALUES (208, 'UDM', 'epsApn', 'EPS APN', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"DNN","filter":"^.{0,127}$","name":"dnn","type":"string","value":"internet"},{"access":"read-write","comment":"","display":"PDN Type","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"IPv4 or IPv6\"}","name":"pdnType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"QCI","filter":"1~255","name":"qci","type":"int","value":"9"},{"access":"read-write","comment":"","display":"ARP Priority","filter":"1~127","name":"arpPriorityLevel","type":"int","value":"8"},{"access":"read-write","comment":"","display":"ARP Preemption Capability","filter":"{\"0\":\"Not Preempt\",\"1\":\"May Preempt\"}","name":"arpPreemptCap","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"ARP Preemption Vulnerability","filter":"{\"0\":\"Not Preemptable\",\"1\":\"Preemptable\"}","name":"arpPreemptVuln","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Context Identifier","filter":"","name":"contextIdentifier","type":"int","value":"1"},{"access":"read-write","comment":"","display":"VPLMN Dynamic Address Allowed","filter":"false;true;","name":"vplmnDynamicAddressAllowed","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"PDN GW Allocation Type","filter":"{\"0\":\"Static\",\"1\":\"Dynamic\"}","name":"pdnGWAllocationType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"AMBR Uplink","filter":"0~4294967295","name":"ambrUplink","type":"int","value":"100000000"},{"access":"read-write","comment":"","display":"AMBR Downlink","filter":"0~4294967295","name":"ambrDownlink","type":"int","value":"200000000"},{"access":"read-write","comment":"","display":"Charging Characteristic","filter":"4~4","name":"chargingCharacteristic","type":"string","value":"0001"}]', 19, '', 1751451940594, 'public'); +INSERT INTO "ne_config" VALUES (209, 'UDM', 'applicationServer', 'Application Server', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"AS Name","filter":"^.{1,31}$","name":"name","type":"string","value":"mmtel_as"},{"access":"read-write","comment":"","display":"Default Handling","filter":"{\"0\":\"Session Continued\",\"1\":\"Session Terminated\"}","name":"defaultHandling","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Server Name","filter":"^.{1,127}$","name":"serverName","type":"string","value":"sip:192.168.8.26:7060"},{"access":"read-write","comment":"","display":"Diameter Address","filter":"^.{1,127}$","name":"diameterAddress","type":"string","value":"mmtel.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Rep Data Size Limit","filter":"0~65535","name":"repDataSizeLimit","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Include Register Request","filter":"false;true;","name":"includeRegisterRequest","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"Include Register Response","filter":"false;true;","name":"includeRegisterResponse","type":"bool","value":"false"}]', 21, '', 1751451940597, 'public'); +INSERT INTO "ne_config" VALUES (210, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~8","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,31}$","name":"name","type":"string","value":"mmtel_as"},{"access":"read-write","comment":"","display":"Priority","filter":"","name":"priority","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Server Name","filter":"^.{1,127}$","name":"serverName","type":"string","value":"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060"}]', 23, '', 1751451940601, 'public'); +INSERT INTO "ne_config" VALUES (211, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_snssai"},{"access":"read-write","comment":"","display":"Condition Type CNF","filter":"0~1","name":"conditionTypeCNF","type":"int","value":"0"},{"access":"read-only","array":[{"access":"read-only","comment":"","display":"Index","filter":"1~4","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Enable","filter":"","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Condition Negated","filter":"0~1","name":"conditionNegated","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Group","filter":"0~4096","name":"group","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Method","filter":"^.{0,32}$","name":"method","type":"string","value":""},{"access":"read-write","comment":"","display":"SIP Header","filter":"^.{0,64}$","name":"sipHeader","type":"string","value":""},{"access":"read-write","comment":"","display":"SIP Content","filter":"^.{0,64}$","name":"sipContent","type":"string","value":""}],"comment":"","display":"SPT List","filter":"1~4","name":"sptList","type":"int","value":"1"}]', 25, '', 1751451940605, 'public'); +INSERT INTO "ne_config" VALUES (212, 'UDM', 's6aServer', 'S6a Server', 'list', '[{"access":"read-write","comment":"","display":"Enable","filter":"false;true;","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"netType","type":"enum","value":"1"},{"access":"read-write","comment":"","display":"Address","filter":"","name":"addr","type":"string","value":"172.16.5.140:3868"},{"access":"read-write","comment":"","display":"Host","filter":"^.{1,127}$","name":"host","type":"string","value":"hss.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Realm","filter":"^.{1,127}$","name":"realm","type":"string","value":"ims.mnc001.mcc001.3gppnetwork.org"}]', 27, '', 1751451940610, 'public'); +INSERT INTO "ne_config" VALUES (213, 'UDM', 'cxServer', 'Cx Server', 'list', '[{"access":"read-write","comment":"","display":"Enable","filter":"false;true;","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"netType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Address","filter":"","name":"addr","type":"string","value":"172.16.5.140:3868"},{"access":"read-write","comment":"","display":"Host","filter":"^.{1,127}$","name":"host","type":"string","value":"hss.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Realm","filter":"^.{1,127}$","name":"realm","type":"string","value":"ims.mnc001.mcc001.3gppnetwork.org"}]', 29, '', 1751451940614, 'public'); +INSERT INTO "ne_config" VALUES (214, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{"access":"read-write","comment":"","display":"AUSF enable","filter":"","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"EAP-Aka SupiOrImsi Prefix","filter":"","name":"eapAkaSupiImsiPrefix","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"AUSF FQDN","filter":"0~128","name":"ausfFqdn","type":"string","value":"ausf.5gc.com"}]', 3, '', 1751451940561, 'public'); -- 更新 UPF 配置 20250320 INSERT INTO "ne_config" VALUES (220, 'UPF', 'general', 'General', 'list', '[{"access":"read-write","comment":"","display":"Config File Directory","filter":"","name":"configFileDirectory","type":"string","value":"/usr/local/etc/upf/"},{"access":"read-write","comment":"","display":"EXE File Directory","filter":"","name":"exeFileDirectory","type":"string","value":"/usr/local/bin/"},{"access":"read-write","comment":"1~255","display":"System ID","filter":"","name":"systemId","type":"int","value":"1"},{"access":"read-write","comment":"1~8","display":"Data Forwarder Number","filter":"1~8","name":"dataForwarderNum","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Common Statistic Interval","filter":"","name":"commonStatisticInterval","type":"int","value":"60"},{"access":"read-write","comment":"","display":"User Statistic Interval","filter":"","name":"userStatisticInterval","type":"int","value":"60"},{"access":"read-write","comment":"","display":"RX N3 OverLoad Threshold Mbps","filter":"","name":"rxN3OverLoadThresholdMbps","type":"int","value":"0"},{"access":"read-write","comment":"","display":"RX N6 OverLoad Threshold Mbps","filter":"","name":"rxN6OverLoadThresholdMbps","type":"int","value":"0"},{"access":"read-write","comment":"0~255","display":"Checksum Offload","filter":"0~255","name":"checksumOffload","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Max Downlink Buffer Num","filter":"","name":"maxDownlinkBufferNum","type":"int","value":"50"}]', 1, '', 1742469466451, 'public'); diff --git a/build/database/std/common/ne_config.sql b/build/database/std/common/ne_config.sql index 5b4fa268..073d1845 100644 --- a/build/database/std/common/ne_config.sql +++ b/build/database/std/common/ne_config.sql @@ -98,21 +98,21 @@ INSERT INTO `ne_config` VALUES (191, 'SMF', 'dnnselectdhcpserver', 'DNN Select D INSERT INTO `ne_config` VALUES (192, 'SMF', 'offlineChargingConfig', 'Offline Charging Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR File Name\",\"filter\":\"1~64\",\"name\":\"cdrFileName\",\"type\":\"string\",\"value\":\"smf.cdr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR File Path\",\"filter\":\"1~256\",\"name\":\"cdrFilePath\",\"type\":\"string\",\"value\":\"/var/log/smfCdr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR File Num\",\"filter\":\"1~999999999\",\"name\":\"cdrFileNum\",\"type\":\"int\",\"value\":\"50\"},{\"access\":\"read-write\",\"comment\":\"Megabytes\",\"display\":\"CDR File Size\",\"filter\":\"1~999999\",\"name\":\"cdrFileSize\",\"type\":\"int\",\"value\":\"300\"},{\"access\":\"read-write\",\"comment\":\"Days\",\"display\":\"CDR File Max Age\",\"filter\":\"0~9999\",\"name\":\"cdrFileMaxAge\",\"type\":\"int\",\"value\":\"30\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Free Subscribers CDR Enable\",\"filter\":\"\",\"name\":\"freeSubsCdrEnable\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"Seconds\",\"display\":\"Time Threshold\",\"filter\":\"0~999999999\",\"name\":\"timeThreshold\",\"type\":\"int\",\"value\":\"600\"},{\"access\":\"read-write\",\"comment\":\"Bytes\",\"display\":\"Volume Threshold\",\"filter\":\"0~999999999999999\",\"name\":\"volumeThreshold\",\"type\":\"int\",\"value\":\"0\"}]', 25, '', 1751019165593, 'public'); -- 更新 UDM 配置 20250613 -INSERT INTO `ne_config` VALUES (200, 'UDM', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service IP\",\"filter\":\"\",\"name\":\"serviceIP\",\"type\":\"ipv4\",\"value\":\"172.16.5.140\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Port\",\"filter\":\"0~65535\",\"name\":\"servicePort\",\"type\":\"int\",\"value\":\"8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NRF URI\",\"filter\":\"\",\"name\":\"nrfUri\",\"type\":\"string\",\"value\":\"http://172.16.5.180:8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"FQDN\",\"filter\":\"\",\"name\":\"fqdn\",\"type\":\"string\",\"value\":\"omc.com\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"0~4095\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Capacity\",\"filter\":\"0~65535\",\"name\":\"capacity\",\"type\":\"int\",\"value\":\"4096\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group ID\",\"filter\":\"\",\"name\":\"groupId\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn1\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn1\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn2\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn2\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn3\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn3\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn4\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn4\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SUPI Ranges\",\"filter\":\"^imsi-\\\\d{15}~imsi-\\\\d{15}$\",\"name\":\"supiRanges\",\"type\":\"regex\",\"value\":\"imsi-001010100080000~imsi-001010100080099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"GPSI Ranges\",\"filter\":\"^msisdn-\\\\d{2,15}~msisdn-\\\\d{2,15}$\",\"name\":\"gpsiRanges\",\"type\":\"regex\",\"value\":\"msisdn-69072000~msisdn-69072099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"HTTP\\\", \\\"1\\\":\\\"HTTPS\\\"}\",\"name\":\"scheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Link\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"redisLink\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Address\",\"filter\":\"\",\"name\":\"redisAddr\",\"type\":\"string\",\"value\":\"172.16.5.140:6379\"}]', 1, '', 1749815867447, 'public'); -INSERT INTO `ne_config` VALUES (201, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"uplink\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"downlink\",\"type\":\"regex\",\"value\":\"2 Gbps\"}]', 5, '', 1749815867466, 'public'); -INSERT INTO `ne_config` VALUES (202, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Features\",\"filter\":\"^[0-9a-fA-F]{8}$\",\"name\":\"supportedFeatures\",\"type\":\"regex\",\"value\":\"00000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Single NSSAIs\",\"filter\":\"\",\"name\":\"defaultSingleNSSAIs\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Single NSSAIs\",\"filter\":\"\",\"name\":\"singleNssais\",\"type\":\"string\",\"value\":\"1-000002\"}]', 7, '', 1749815867471, 'public'); -INSERT INTO `ne_config` VALUES (203, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"}]', 9, '', 1749815867476, 'public'); -INSERT INTO `ne_config` VALUES (204, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Restriction Type\",\"filter\":\"{\\\"0\\\":\\\"Allowed Areas\\\", \\\"1\\\":\\\"Not Allowed Areas\\\"}\",\"name\":\"restrictionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max TAs\",\"filter\":\"^\\\\d{1,2}$\",\"name\":\"maxTAs\",\"type\":\"int\",\"value\":\"1\"}]', 11, '', 1749815867480, 'public'); -INSERT INTO `ne_config` VALUES (205, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SNSSAI\",\"filter\":\"^\\\\d{1,3}[A-Fa-f0-9]{6}$\",\"name\":\"snssai\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{1,32}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default DNN Indicator\",\"filter\":\"false;true;\",\"name\":\"defaultDnnInd\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LBO Roaming Allowed\",\"filter\":\"false;true;\",\"name\":\"lboRoamingAllowed\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"false;true;\",\"name\":\"iwkEpsInd\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"false;true;\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"false\"}],\"comment\":\"\",\"display\":\"DNN List\",\"filter\":\"1~4\",\"name\":\"dnnList\",\"type\":\"int\",\"value\":\"1\"}]', 13, '', 1749815867486, 'public'); -INSERT INTO `ne_config` VALUES (206, 'UDM', 'dnn', 'DNN Conf', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default PDU Session Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\"}\",\"name\":\"defaultPDUSessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed PDU Session Types\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\",\\\"5\\\":\\\"IPv4 \\u0026 IPv6\\\",\\\"6\\\":\\\"IPv4 \\u0026 IPv4v6\\\",\\\"7\\\":\\\"IPv6 \\u0026 IPv4v6\\\",\\\"8\\\":\\\"IPv4 \\u0026 IPv6 \\u0026 IPv4v6\\\"}\",\"name\":\"allowedPDUSessionTypes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"5QI\",\"filter\":\"0~255\",\"name\":\"5qi\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"1~127\",\"name\":\"priorityLevel\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default SSC Mode\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\"}\",\"name\":\"defaultSSCmode\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed SSC Modes\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\",\\\"3\\\":\\\"SSC Mode1 \\u0026 SSC Mode2\\\",\\\"4\\\":\\\"SSC Mode1 \\u0026 SSC Mode3\\\",\\\"5\\\":\\\"SSC Mode2 \\u0026 SSC Mode3\\\",\\\"6\\\":\\\"SSC Mode1 \\u0026 SSC Mode2 \\u0026 SSC Mode3\\\"}\",\"name\":\"allowedSSCmodes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"\",\"name\":\"interworkingEPSIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristics\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristics\",\"type\":\"string\",\"value\":\"0001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrUL\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrDL\",\"type\":\"regex\",\"value\":\"2 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Static IP Address\",\"filter\":\"\",\"name\":\"staticIPAddress\",\"type\":\"ipv4\",\"value\":\"192.168.1.100\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Integrity\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneIntegrity\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Confidentiality\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneConfidentiality\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority Level\",\"filter\":\"0~255\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"6\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"}]', 15, '', 1749815867491, 'public'); -INSERT INTO `ne_config` VALUES (207, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{0,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_eps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"APN OI Replacement\",\"filter\":\"^.{0,31}$\",\"name\":\"apnOIReplacement\",\"type\":\"string\",\"value\":\"money\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RFSP\",\"filter\":\"\",\"name\":\"rfsp\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RAU TAU Timer\",\"filter\":\"\",\"name\":\"rauTauTimer\",\"type\":\"int\",\"value\":\"120\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 17, '', 1749815867496, 'public'); -INSERT INTO `ne_config` VALUES (208, 'UDM', 'epsApn', 'EPS APN', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{0,127}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"IPv4 or IPv6\\\"}\",\"name\":\"pdnType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"QCI\",\"filter\":\"1~255\",\"name\":\"qci\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority\",\"filter\":\"1~127\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"8\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Context Identifier\",\"filter\":\"\",\"name\":\"contextIdentifier\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"VPLMN Dynamic Address Allowed\",\"filter\":\"false;true;\",\"name\":\"vplmnDynamicAddressAllowed\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN GW Allocation Type\",\"filter\":\"{\\\"0\\\":\\\"Static\\\",\\\"1\\\":\\\"Dynamic\\\"}\",\"name\":\"pdnGWAllocationType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 19, '', 1749815867501, 'public'); -INSERT INTO `ne_config` VALUES (209, 'UDM', 'applicationServer', 'Application Server', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AS Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Handling\",\"filter\":\"{\\\"0\\\":\\\"Session Continued\\\",\\\"1\\\":\\\"Session Terminated\\\"}\",\"name\":\"defaultHandling\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:192.168.8.26:7060\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Diameter Address\",\"filter\":\"^.{1,127}$\",\"name\":\"diameterAddress\",\"type\":\"string\",\"value\":\"mmtel.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Rep Data Size Limit\",\"filter\":\"0~65535\",\"name\":\"repDataSizeLimit\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Request\",\"filter\":\"false;true;\",\"name\":\"includeRegisterRequest\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Response\",\"filter\":\"false;true;\",\"name\":\"includeRegisterResponse\",\"type\":\"bool\",\"value\":\"false\"}]', 21, '', 1749815867506, 'public'); -INSERT INTO `ne_config` VALUES (210, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~8\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060\"}]', 23, '', 1749815867511, 'public'); -INSERT INTO `ne_config` VALUES (211, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Type CNF\",\"filter\":\"0~1\",\"name\":\"conditionTypeCNF\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Negated\",\"filter\":\"0~1\",\"name\":\"conditionNegated\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group\",\"filter\":\"0~4096\",\"name\":\"group\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Method\",\"filter\":\"^.{0,32}$\",\"name\":\"method\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Header\",\"filter\":\"^.{0,64}$\",\"name\":\"sipHeader\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Content\",\"filter\":\"^.{0,64}$\",\"name\":\"sipContent\",\"type\":\"string\",\"value\":\"\"}],\"comment\":\"\",\"display\":\"SPT List\",\"filter\":\"1~4\",\"name\":\"sptList\",\"type\":\"int\",\"value\":\"1\"}]', 25, '', 1749815867516, 'public'); -INSERT INTO `ne_config` VALUES (212, 'UDM', 's6aServer', 'S6a Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 27, '', 1749815867521, 'public'); -INSERT INTO `ne_config` VALUES (213, 'UDM', 'cxServer', 'Cx Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 29, '', 1749815867527, 'public'); -INSERT INTO `ne_config` VALUES (214, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EAP-Aka SupiOrImsi Prefix\",\"filter\":\"\",\"name\":\"eapAkaSupiImsiPrefix\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF FQDN\",\"filter\":\"0~128\",\"name\":\"ausfFqdn\",\"type\":\"string\",\"value\":\"ausf.5gc.com\"}]', 3, '', 1749815867461, 'public'); +INSERT INTO `ne_config` VALUES (200, 'UDM', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service IP\",\"filter\":\"\",\"name\":\"serviceIP\",\"type\":\"ipv4\",\"value\":\"172.16.5.140\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Port\",\"filter\":\"0~65535\",\"name\":\"servicePort\",\"type\":\"int\",\"value\":\"8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NRF URI\",\"filter\":\"\",\"name\":\"nrfUri\",\"type\":\"string\",\"value\":\"http://172.16.5.180:8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"FQDN\",\"filter\":\"\",\"name\":\"fqdn\",\"type\":\"string\",\"value\":\"omc.com\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"0~4095\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Capacity\",\"filter\":\"0~65535\",\"name\":\"capacity\",\"type\":\"int\",\"value\":\"4096\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group ID\",\"filter\":\"\",\"name\":\"groupId\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn1\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn1\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn2\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn2\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn3\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn3\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn4\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn4\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SUPI Ranges\",\"filter\":\"^imsi-\\\\d{15}~imsi-\\\\d{15}$\",\"name\":\"supiRanges\",\"type\":\"regex\",\"value\":\"imsi-001010100080000~imsi-001010100080099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"GPSI Ranges\",\"filter\":\"^msisdn-\\\\d{2,15}~msisdn-\\\\d{2,15}$\",\"name\":\"gpsiRanges\",\"type\":\"regex\",\"value\":\"msisdn-69072000~msisdn-69072099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"HTTP\\\", \\\"1\\\":\\\"HTTPS\\\"}\",\"name\":\"scheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Link\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"redisLink\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Address\",\"filter\":\"\",\"name\":\"redisAddr\",\"type\":\"string\",\"value\":\"172.16.5.140:6379\"}]', 1, '', 1751451940555, 'public'); +INSERT INTO `ne_config` VALUES (201, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"uplink\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"downlink\",\"type\":\"regex\",\"value\":\"2 Gbps\"}]', 5, '', 1751451940566, 'public'); +INSERT INTO `ne_config` VALUES (202, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Features\",\"filter\":\"^[0-9a-fA-F]{8}$\",\"name\":\"supportedFeatures\",\"type\":\"regex\",\"value\":\"00000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Single NSSAIs\",\"filter\":\"\",\"name\":\"defaultSingleNSSAIs\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Single NSSAIs\",\"filter\":\"\",\"name\":\"singleNssais\",\"type\":\"string\",\"value\":\"1-000002\"}]', 7, '', 1751451940570, 'public'); +INSERT INTO `ne_config` VALUES (203, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"}]', 9, '', 1751451940574, 'public'); +INSERT INTO `ne_config` VALUES (204, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Restriction Type\",\"filter\":\"{\\\"0\\\":\\\"Allowed Areas\\\", \\\"1\\\":\\\"Not Allowed Areas\\\"}\",\"name\":\"restrictionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max TAs\",\"filter\":\"^\\\\d{1,2}$\",\"name\":\"maxTAs\",\"type\":\"int\",\"value\":\"1\"}]', 11, '', 1751451940579, 'public'); +INSERT INTO `ne_config` VALUES (205, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SNSSAI\",\"filter\":\"^\\\\d{1,3}[A-Fa-f0-9]{6}$\",\"name\":\"snssai\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{1,32}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default DNN Indicator\",\"filter\":\"false;true;\",\"name\":\"defaultDnnInd\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LBO Roaming Allowed\",\"filter\":\"false;true;\",\"name\":\"lboRoamingAllowed\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"false;true;\",\"name\":\"iwkEpsInd\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"false;true;\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"false\"}],\"comment\":\"\",\"display\":\"DNN List\",\"filter\":\"1~4\",\"name\":\"dnnList\",\"type\":\"int\",\"value\":\"1\"}]', 13, '', 1751451940583, 'public'); +INSERT INTO `ne_config` VALUES (206, 'UDM', 'dnn', 'DNN Conf', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default PDU Session Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\"}\",\"name\":\"defaultPDUSessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed PDU Session Types\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\",\\\"5\\\":\\\"IPv4 \\u0026 IPv6\\\",\\\"6\\\":\\\"IPv4 \\u0026 IPv4v6\\\",\\\"7\\\":\\\"IPv6 \\u0026 IPv4v6\\\",\\\"8\\\":\\\"IPv4 \\u0026 IPv6 \\u0026 IPv4v6\\\"}\",\"name\":\"allowedPDUSessionTypes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"5QI\",\"filter\":\"0~255\",\"name\":\"5qi\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"1~127\",\"name\":\"priorityLevel\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default SSC Mode\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\"}\",\"name\":\"defaultSSCmode\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed SSC Modes\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\",\\\"3\\\":\\\"SSC Mode1 \\u0026 SSC Mode2\\\",\\\"4\\\":\\\"SSC Mode1 \\u0026 SSC Mode3\\\",\\\"5\\\":\\\"SSC Mode2 \\u0026 SSC Mode3\\\",\\\"6\\\":\\\"SSC Mode1 \\u0026 SSC Mode2 \\u0026 SSC Mode3\\\"}\",\"name\":\"allowedSSCmodes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"\",\"name\":\"interworkingEPSIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristics\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristics\",\"type\":\"string\",\"value\":\"0001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrUL\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrDL\",\"type\":\"regex\",\"value\":\"2 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Static IP Address\",\"filter\":\"\",\"name\":\"staticIPAddress\",\"type\":\"ipv4\",\"value\":\"192.168.1.100\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Integrity\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneIntegrity\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Confidentiality\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneConfidentiality\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority Level\",\"filter\":\"0~255\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"6\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"}]', 15, '', 1751451940587, 'public'); +INSERT INTO `ne_config` VALUES (207, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{0,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_eps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"APN OI Replacement\",\"filter\":\"^.{0,31}$\",\"name\":\"apnOIReplacement\",\"type\":\"string\",\"value\":\"money\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RFSP\",\"filter\":\"\",\"name\":\"rfsp\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RAU TAU Timer\",\"filter\":\"\",\"name\":\"rauTauTimer\",\"type\":\"int\",\"value\":\"120\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 17, '', 1751451940591, 'public'); +INSERT INTO `ne_config` VALUES (208, 'UDM', 'epsApn', 'EPS APN', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{0,127}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"IPv4 or IPv6\\\"}\",\"name\":\"pdnType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"QCI\",\"filter\":\"1~255\",\"name\":\"qci\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority\",\"filter\":\"1~127\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"8\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Context Identifier\",\"filter\":\"\",\"name\":\"contextIdentifier\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"VPLMN Dynamic Address Allowed\",\"filter\":\"false;true;\",\"name\":\"vplmnDynamicAddressAllowed\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN GW Allocation Type\",\"filter\":\"{\\\"0\\\":\\\"Static\\\",\\\"1\\\":\\\"Dynamic\\\"}\",\"name\":\"pdnGWAllocationType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 19, '', 1751451940594, 'public'); +INSERT INTO `ne_config` VALUES (209, 'UDM', 'applicationServer', 'Application Server', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AS Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Handling\",\"filter\":\"{\\\"0\\\":\\\"Session Continued\\\",\\\"1\\\":\\\"Session Terminated\\\"}\",\"name\":\"defaultHandling\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:192.168.8.26:7060\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Diameter Address\",\"filter\":\"^.{1,127}$\",\"name\":\"diameterAddress\",\"type\":\"string\",\"value\":\"mmtel.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Rep Data Size Limit\",\"filter\":\"0~65535\",\"name\":\"repDataSizeLimit\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Request\",\"filter\":\"false;true;\",\"name\":\"includeRegisterRequest\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Response\",\"filter\":\"false;true;\",\"name\":\"includeRegisterResponse\",\"type\":\"bool\",\"value\":\"false\"}]', 21, '', 1751451940597, 'public'); +INSERT INTO `ne_config` VALUES (210, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~8\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060\"}]', 23, '', 1751451940601, 'public'); +INSERT INTO `ne_config` VALUES (211, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Type CNF\",\"filter\":\"0~1\",\"name\":\"conditionTypeCNF\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Negated\",\"filter\":\"0~1\",\"name\":\"conditionNegated\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group\",\"filter\":\"0~4096\",\"name\":\"group\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Method\",\"filter\":\"^.{0,32}$\",\"name\":\"method\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Header\",\"filter\":\"^.{0,64}$\",\"name\":\"sipHeader\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Content\",\"filter\":\"^.{0,64}$\",\"name\":\"sipContent\",\"type\":\"string\",\"value\":\"\"}],\"comment\":\"\",\"display\":\"SPT List\",\"filter\":\"1~4\",\"name\":\"sptList\",\"type\":\"int\",\"value\":\"1\"}]', 25, '', 1751451940605, 'public'); +INSERT INTO `ne_config` VALUES (212, 'UDM', 's6aServer', 'S6a Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 27, '', 1751451940610, 'public'); +INSERT INTO `ne_config` VALUES (213, 'UDM', 'cxServer', 'Cx Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 29, '', 1751451940614, 'public'); +INSERT INTO `ne_config` VALUES (214, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EAP-Aka SupiOrImsi Prefix\",\"filter\":\"\",\"name\":\"eapAkaSupiImsiPrefix\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF FQDN\",\"filter\":\"0~128\",\"name\":\"ausfFqdn\",\"type\":\"string\",\"value\":\"ausf.5gc.com\"}]', 3, '', 1751451940561, 'public'); -- 更新 UPF 配置 20250320 INSERT INTO `ne_config` VALUES (220, 'UPF', 'general', 'General', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Config File Directory\",\"filter\":\"\",\"name\":\"configFileDirectory\",\"type\":\"string\",\"value\":\"/usr/local/etc/upf/\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EXE File Directory\",\"filter\":\"\",\"name\":\"exeFileDirectory\",\"type\":\"string\",\"value\":\"/usr/local/bin/\"},{\"access\":\"read-write\",\"comment\":\"1~255\",\"display\":\"System ID\",\"filter\":\"\",\"name\":\"systemId\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"1~8\",\"display\":\"Data Forwarder Number\",\"filter\":\"1~8\",\"name\":\"dataForwarderNum\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Common Statistic Interval\",\"filter\":\"\",\"name\":\"commonStatisticInterval\",\"type\":\"int\",\"value\":\"60\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Statistic Interval\",\"filter\":\"\",\"name\":\"userStatisticInterval\",\"type\":\"int\",\"value\":\"60\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RX N3 OverLoad Threshold Mbps\",\"filter\":\"\",\"name\":\"rxN3OverLoadThresholdMbps\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RX N6 OverLoad Threshold Mbps\",\"filter\":\"\",\"name\":\"rxN6OverLoadThresholdMbps\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"0~255\",\"display\":\"Checksum Offload\",\"filter\":\"0~255\",\"name\":\"checksumOffload\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max Downlink Buffer Num\",\"filter\":\"\",\"name\":\"maxDownlinkBufferNum\",\"type\":\"int\",\"value\":\"50\"}]', 1, '', 1742469466451, 'public'); From 6cd0136d8a3abbe245e4850af2b474f95a5c91e4 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Sat, 5 Jul 2025 10:12:35 +0800 Subject: [PATCH 04/80] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app.go b/src/app.go index 2f47f4ed..e7168a73 100644 --- a/src/app.go +++ b/src/app.go @@ -27,10 +27,6 @@ import ( // 初始应用引擎 func AppEngine() *gin.Engine { var app *gin.Engine - - // 禁止控制台日志输出的颜色 - gin.DisableConsoleColor() - // 根据运行环境注册引擎 if config.Env() == "prod" { gin.SetMode(gin.ReleaseMode) @@ -39,6 +35,8 @@ func AppEngine() *gin.Engine { } else { app = gin.Default() } + // 禁止控制台日志输出的颜色 + gin.DisableConsoleColor() app.ForwardedByClientIP = true return app } From acab82a3f612c1251dbc81adc1bd068992a50f89 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Sat, 5 Jul 2025 10:12:39 +0800 Subject: [PATCH 05/80] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2507.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 432f2e04..b389b22b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 版本发布日志 +## 2.2507.1-20250705 + +- 修复 SMSC和UDM配置在lite下无法正常显示问题 +- 更新 AMF配置缺少Gnb List Config定义,SMF配置新增GNB和远程Gy配置 +- 新增 IMS指标IDD呼入呼出,自定义指标IDD + ## 2.2506.4-20250627 - 优化 IMS-KPI隐藏掉原因值接收 From 4c63533390f855a1e96deff8369d7fcab9a5c819 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 7 Jul 2025 10:44:47 +0800 Subject: [PATCH 06/80] =?UTF-8?q?feat:=20HLR=E8=B7=9F=E8=B8=AA=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=A0=87=E8=AF=86=E4=B8=BAUDM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/trace/service/trace_task_hlr.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/trace/service/trace_task_hlr.go b/src/modules/trace/service/trace_task_hlr.go index 6642a21d..b500e403 100644 --- a/src/modules/trace/service/trace_task_hlr.go +++ b/src/modules/trace/service/trace_task_hlr.go @@ -60,7 +60,7 @@ func (r *TraceTaskHlr) DeleteByIds(ids []int64) (int64, error) { if len(rows) == len(ids) { // 停止任务 - neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "HLR"}, false, false) + neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "UDM"}, false, false) for _, r := range rows { if r.Status == "0" { continue @@ -98,7 +98,7 @@ func (r *TraceTaskHlr) Start(task model.TraceTaskHlr) (int64, error) { } // 发送创建任务 - neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "HLR"}, false, false) + neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "UDM"}, false, false) for _, neInfo := range neInfos { hlrItem := map[string]any{ "neType": neInfo.NeType, @@ -129,7 +129,7 @@ func (r *TraceTaskHlr) Start(task model.TraceTaskHlr) (int64, error) { func (r *TraceTaskHlr) Stop(task model.TraceTaskHlr) error { hlrList := []map[string]any{} // 发送停止任务 - neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "HLR"}, false, false) + neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "UDM"}, false, false) for _, neInfo := range neInfos { hlrItem := map[string]any{ "neType": neInfo.NeType, @@ -161,7 +161,7 @@ func (r *TraceTaskHlr) Stop(task model.TraceTaskHlr) error { func (r *TraceTaskHlr) File(traceId, dirPath string) ([]map[string]any, error) { hlrList := []map[string]any{} // 查询所有匹配的网元类型 - neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "HLR"}, false, false) + neInfos := r.neInfoService.Find(neModel.NeInfo{NeType: "UDM"}, false, false) if len(neInfos) == 0 { return nil, fmt.Errorf("not found network element") } From 2b2afd7423fda07f3f018e512ec0af6b2256794d Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 10 Jul 2025 11:22:26 +0800 Subject: [PATCH 07/80] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=85=E7=BD=91?= =?UTF-8?q?=E5=85=83=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_element/repository/ne_info.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/network_element/repository/ne_info.go b/src/modules/network_element/repository/ne_info.go index da3cf1a8..dc088bba 100644 --- a/src/modules/network_element/repository/ne_info.go +++ b/src/modules/network_element/repository/ne_info.go @@ -41,6 +41,11 @@ func (r NeInfo) neListSort(arr []model.NeInfo) []model.NeInfo { "CHF", "HLR", "SGWC", + "IP-SM-GW", + "MMTel-AS", + "I-CSCF", + "P-CSCF", + "S-CSCF", } // 创建优先级映射 From edd93f5769455afebc56df00b9b728123caabac4 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:38:48 +0800 Subject: [PATCH 08/80] =?UTF-8?q?del:=20=E7=A7=BB=E9=99=A4features?= =?UTF-8?q?=E3=80=81lib=E5=92=8Csshsvc=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/aaaa/aaaa.go | 142 - features/cdr/cdrevent.go | 102 - features/cm/exec_linux.go | 95 - features/cm/exec_windows.go | 83 - features/cm/ne.go | 991 ---- features/cm/omc/controller.go | 46 - features/cm/omc/implement.go | 69 - features/cm/omc/model.go | 26 - features/cm/omc/route.go | 30 - features/cm/param.go | 208 - features/cm/service.go | 17 - features/cm/software.go | 1052 ---- features/dbrest/dbrest.go | 859 --- features/event/event.go | 248 - features/features.go | 22 - features/file/file.go | 141 - features/fm/alarm.go | 567 -- features/fm/email.go | 129 - features/fm/smsforward.go | 271 - features/handle/handle.go | 565 -- features/lm/file_export/controller.go | 138 - features/lm/file_export/model.go | 30 - features/lm/file_export/route.go | 39 - features/lm/logbak.go | 103 - features/lm/service.go | 17 - features/mml/mml.go | 705 --- features/nbi/file/controller.go | 257 - features/nbi/file/model.go | 47 - features/nbi/file/route.go | 26 - features/nbi/nbi.go | 258 - features/nbi/service.go | 16 - features/nbi/snmp.go | 203 - features/pm/kpi_c_report/controller.go | 349 -- features/pm/kpi_c_report/model.go | 42 - features/pm/kpi_c_report/route.go | 43 - features/pm/kpi_c_title/controller.go | 312 - features/pm/kpi_c_title/model.go | 33 - features/pm/kpi_c_title/route.go | 39 - features/pm/performance.go | 1227 ---- features/pm/service.go | 19 - features/security/account.go | 176 - features/sm/backup.go | 45 - features/state/getstate.go | 1012 ---- features/state/state_linux.go | 243 - features/state/state_windows.go | 231 - features/state/sysinfo.go | 29 - features/ue/ue.go | 833 --- lib/aes/aes.go | 64 - lib/config/config.go | 475 -- lib/config/map.go | 111 - lib/core/ctx/ctx.go | 185 - lib/dborm/dborm.go | 1561 ----- lib/eval/evaluate.go | 119 - lib/file/file.go | 27 - lib/file/file_linux.go | 78 - lib/file/file_windows.go | 63 - lib/global/exec_linux.go | 47 - lib/global/exec_windows.go | 34 - lib/global/global.go | 65 - lib/global/kits.go | 728 --- lib/log/logger.go | 338 -- lib/log/partition.go | 71 - lib/log/syslogger.go.bak | 89 - lib/midware/midhandle.go | 80 - lib/midware/mml_log.go | 60 - lib/midware/operate_log.go | 135 - lib/mmlp/parse.go | 1059 ---- lib/oauth/oauth.go | 157 - lib/pair/pair.go | 37 - lib/routes/routes.go | 318 - lib/run/exec_linux.go | 56 - lib/run/exec_wasm.go | 45 - lib/run/exec_windows.go | 45 - lib/services/file.go | 426 -- lib/services/response.go | 39 - lib/services/services.go | 983 --- lib/session/session.go | 168 - sshsvc/.ssh/id_rsa | 38 - sshsvc/.ssh/id_rsa.pub | 1 - sshsvc/.ssh/private_key.pem | 38 - sshsvc/config/config.go | 185 - sshsvc/dborm/dborm.go | 161 - sshsvc/etc/sshsvc.yaml | 89 - sshsvc/logmml/logmml.go | 187 - sshsvc/logmml/partition.go | 71 - sshsvc/makefile | 18 - sshsvc/mibs/CINTEL-HLR-MIB.my | 7567 ------------------------ sshsvc/mibs/CINTEL-HLR-MIB.smidb | Bin 214132 -> 0 bytes sshsvc/mibs/CINTEL-MIB.my | 656 -- sshsvc/mibs/CINTEL-MIB.smidb | Bin 29052 -> 0 bytes sshsvc/mml/parse.go.bak | 901 --- sshsvc/setHLRServiceState | 26 - sshsvc/snmp/snmp.go | 553 -- sshsvc/sshsvc.go | 575 -- sshsvc/telnet/telnet.go | 198 - 95 files changed, 31062 deletions(-) delete mode 100644 features/aaaa/aaaa.go delete mode 100644 features/cdr/cdrevent.go delete mode 100644 features/cm/exec_linux.go delete mode 100644 features/cm/exec_windows.go delete mode 100644 features/cm/ne.go delete mode 100644 features/cm/omc/controller.go delete mode 100644 features/cm/omc/implement.go delete mode 100644 features/cm/omc/model.go delete mode 100644 features/cm/omc/route.go delete mode 100644 features/cm/param.go delete mode 100644 features/cm/service.go delete mode 100644 features/cm/software.go delete mode 100644 features/dbrest/dbrest.go delete mode 100644 features/event/event.go delete mode 100644 features/features.go delete mode 100644 features/file/file.go delete mode 100644 features/fm/alarm.go delete mode 100644 features/fm/email.go delete mode 100644 features/fm/smsforward.go delete mode 100644 features/handle/handle.go delete mode 100644 features/lm/file_export/controller.go delete mode 100644 features/lm/file_export/model.go delete mode 100644 features/lm/file_export/route.go delete mode 100644 features/lm/logbak.go delete mode 100644 features/lm/service.go delete mode 100644 features/mml/mml.go delete mode 100644 features/nbi/file/controller.go delete mode 100644 features/nbi/file/model.go delete mode 100644 features/nbi/file/route.go delete mode 100644 features/nbi/nbi.go delete mode 100644 features/nbi/service.go delete mode 100644 features/nbi/snmp.go delete mode 100644 features/pm/kpi_c_report/controller.go delete mode 100644 features/pm/kpi_c_report/model.go delete mode 100644 features/pm/kpi_c_report/route.go delete mode 100644 features/pm/kpi_c_title/controller.go delete mode 100644 features/pm/kpi_c_title/model.go delete mode 100644 features/pm/kpi_c_title/route.go delete mode 100644 features/pm/performance.go delete mode 100644 features/pm/service.go delete mode 100644 features/security/account.go delete mode 100644 features/sm/backup.go delete mode 100644 features/state/getstate.go delete mode 100644 features/state/state_linux.go delete mode 100644 features/state/state_windows.go delete mode 100644 features/state/sysinfo.go delete mode 100644 features/ue/ue.go delete mode 100644 lib/aes/aes.go delete mode 100644 lib/config/config.go delete mode 100644 lib/config/map.go delete mode 100644 lib/core/ctx/ctx.go delete mode 100644 lib/dborm/dborm.go delete mode 100644 lib/eval/evaluate.go delete mode 100644 lib/file/file.go delete mode 100644 lib/file/file_linux.go delete mode 100644 lib/file/file_windows.go delete mode 100644 lib/global/exec_linux.go delete mode 100644 lib/global/exec_windows.go delete mode 100644 lib/global/global.go delete mode 100644 lib/global/kits.go delete mode 100644 lib/log/logger.go delete mode 100644 lib/log/partition.go delete mode 100644 lib/log/syslogger.go.bak delete mode 100644 lib/midware/midhandle.go delete mode 100644 lib/midware/mml_log.go delete mode 100644 lib/midware/operate_log.go delete mode 100644 lib/mmlp/parse.go delete mode 100644 lib/oauth/oauth.go delete mode 100644 lib/pair/pair.go delete mode 100644 lib/routes/routes.go delete mode 100644 lib/run/exec_linux.go delete mode 100644 lib/run/exec_wasm.go delete mode 100644 lib/run/exec_windows.go delete mode 100644 lib/services/file.go delete mode 100644 lib/services/response.go delete mode 100644 lib/services/services.go delete mode 100644 lib/session/session.go delete mode 100644 sshsvc/.ssh/id_rsa delete mode 100644 sshsvc/.ssh/id_rsa.pub delete mode 100644 sshsvc/.ssh/private_key.pem delete mode 100644 sshsvc/config/config.go delete mode 100644 sshsvc/dborm/dborm.go delete mode 100644 sshsvc/etc/sshsvc.yaml delete mode 100644 sshsvc/logmml/logmml.go delete mode 100644 sshsvc/logmml/partition.go delete mode 100644 sshsvc/makefile delete mode 100644 sshsvc/mibs/CINTEL-HLR-MIB.my delete mode 100644 sshsvc/mibs/CINTEL-HLR-MIB.smidb delete mode 100644 sshsvc/mibs/CINTEL-MIB.my delete mode 100644 sshsvc/mibs/CINTEL-MIB.smidb delete mode 100644 sshsvc/mml/parse.go.bak delete mode 100644 sshsvc/setHLRServiceState delete mode 100644 sshsvc/snmp/snmp.go delete mode 100644 sshsvc/sshsvc.go delete mode 100644 sshsvc/telnet/telnet.go diff --git a/features/aaaa/aaaa.go b/features/aaaa/aaaa.go deleted file mode 100644 index c6dde188..00000000 --- a/features/aaaa/aaaa.go +++ /dev/null @@ -1,142 +0,0 @@ -package aaaa - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - "time" - - "github.com/go-resty/resty/v2" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/log" - "be.ems/lib/oauth" - "be.ems/lib/services" -) - -var ( - UriAAAASSO = config.DefaultUriPrefix + "/aaaa/{apiVersion}/security/sso" // for 4A external - - CustomUriAAAASSO = config.UriPrefix + "/aaaa/{apiVersion}/security/sso" // for 4A external -) - -var client = resty.New() - -func init() { - /* - client. - SetTimeout(10 * time.Second). - SetRetryCount(1). - SetRetryWaitTime(1 * time.Second). - SetRetryMaxWaitTime(2 * time.Second). - SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) { - return 0, errors.New("quota exceeded") - }) - */ - client.SetTimeout(3 * time.Second) -} - -type AAAATicket struct { - Ticket string `json:"ticket"` -} - -type SSOResult struct { - SSO struct { - Result string `json:"result"` - ResultMsg string `json:"result_msg"` - Ticket string `json:"ticket"` - ResultMsgcode string `json:"result_msgcode"` - Account []struct { - Accid string `json:"accid"` - } `json:"account"` - } `json:"sso"` -} - -// Get system state from NF/NFs -func GetSSOFromAAAA(w http.ResponseWriter, r *http.Request) { - log.Info("GetSSOFromAAAA processing... ") - - vars := r.URL.Query() - ticket := vars["ticket"] - if len(ticket) == 0 { - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Debug("ticket:", ticket) - - log.Debugf("r.RemoteAddr:%s r.Host: %s", r.RemoteAddr, r.Host) - - aaaaIp := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")] - omcIp := r.Host[:strings.Index(r.Host, ":")] - - log.Debugf("aaaaIp=%s omcIp=%s", aaaaIp, omcIp) - requestURI2NF := fmt.Sprintf("http://%s:8080/qryUserByTicket", aaaaIp) - - log.Debug("requestURI2NF:", requestURI2NF) - - aaaaTicket := &AAAATicket{ - Ticket: ticket[0], - } - - body, err := json.Marshal(aaaaTicket) - if err != nil { - log.Error("Failed to json.Marshal:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Post(requestURI2NF) - if err != nil { - log.Error("Failed to Post:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("response:", response) - - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - ssoResult := new(SSOResult) - json.Unmarshal(response.Body(), ssoResult) - var accid string - if len(ssoResult.SSO.Account) != 0 { - accid = ssoResult.SSO.Account[0].Accid - } - - log.Debug("accid:", accid) - exist, err := dborm.XormIsExistUser(accid) - if err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - token := oauth.GenRandToken("aaaa") // Generate new token to session ID - affected, err := dborm.XormInsertSession(accid, r.RemoteAddr, token, - config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session) - if err != nil { - log.Error("Failed to XormInsertSession:", err) - if affected == -1 { - services.ResponseForbidden403MultiLoginNotAllowed(w) - } else { - services.ResponseBadRequest400IncorrectLogin(w) - } - return - } - if exist == true { - redirectUrl := fmt.Sprintf("http://%s:8888/home.html?user=%s&token=%s", omcIp, accid, token) - services.ResponseRedirect(w, redirectUrl, accid, token) - return - } else { - services.ResponseBadRequest400IncorrectLogin(w) - return - } - default: - services.ResponseForbidden403NotPermission(w) - return - } -} diff --git a/features/cdr/cdrevent.go b/features/cdr/cdrevent.go deleted file mode 100644 index 47a74f5c..00000000 --- a/features/cdr/cdrevent.go +++ /dev/null @@ -1,102 +0,0 @@ -package cdr - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - "time" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/database/db" - neService "be.ems/src/modules/network_element/service" - wsService "be.ems/src/modules/ws/service" -) - -var ( - UriCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrEvent" - UriCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrFile" - - CustomUriCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrEvent" - CustomUriCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrFile" -) - -// PostCDREventFrom 接收CDR数据请求 -func PostCDREventFrom(w http.ResponseWriter, r *http.Request) { - log.Info("PostCDREventFrom processing... ") - neType := ctx.GetParam(r, "elementTypeValue") - var body struct { - NeType string `json:"neType" ` - NeName string `json:"neName" ` - RmUID string `json:"rmUID" ` - Timestamp int `json:"timestamp" ` - CDR map[string]any `json:"CDR" ` - } - if err := ctx.ShouldBindJSON(r, &body); err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - neTypeLower := strings.ToLower(body.NeType) - if neType == "" || neType != neTypeLower { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("inconsistent network element types")) - return - } - - // 是否存在网元 - neInfo := neService.NewNeInfo.FindByRmuid(body.RmUID) - if neInfo.NeType != body.NeType || neInfo.RmUID != body.RmUID { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("network element does not exist")) - return - } - - cdrByte, err := json.Marshal(body.CDR) - if err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 执行插入表 - type CDREvent struct { - ID int64 `json:"-" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUid string `json:"rmUid" gorm:"column:rm_uid"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"-" gorm:"column:created_at"` // 记录创建存储毫秒 - } - data := CDREvent{ - NeType: body.NeType, - NeName: body.NeName, - RmUid: body.RmUID, - Timestamp: int64(body.Timestamp) * 1000, - CdrJson: string(cdrByte), - CreatedAt: time.Now().UnixMilli(), - } - tableName := fmt.Sprintf("cdr_event_%s", neTypeLower) - if err := db.DB("").Table(tableName).Create(&data).Error; err != nil { - log.Error("Failed to insert "+tableName, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 推送到ws订阅组 - switch neInfo.NeType { - case "IMS": - if v, ok := body.CDR["recordType"]; ok && (v == "MOC" || v == "MTSM") { - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_IMS_CDR, neInfo.NeId), data) - } - case "SMF": - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMF_CDR, neInfo.NeId), data) - case "SMSC": - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMSC_CDR, neInfo.NeId), data) - case "SGWC": - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SGWC_CDR, neInfo.NeId), data) - } - - services.ResponseStatusOK204NoContent(w) -} diff --git a/features/cm/exec_linux.go b/features/cm/exec_linux.go deleted file mode 100644 index b8b7b36f..00000000 --- a/features/cm/exec_linux.go +++ /dev/null @@ -1,95 +0,0 @@ -//go:build linux -// +build linux - -package cm - -import ( - "bytes" - "context" - "os/exec" - "time" - - "be.ems/lib/log" -) - -func ExecCmd(command string) error { - log.Debug("Exec command:", command) - - cmd := exec.Command("/bin/bash", "-c", command) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - /* - if err := cmd.Start(); err != nil { - log.Error("Start error: ", err) - return err - } - if err := cmd.Wait(); err != nil { - log.Error("Wait error: ", err) - return err - } - */ - return nil -} - -func ExecShell(command string) error { - in := bytes.NewBuffer(nil) - cmd := exec.Command("sh") - cmd.Stdin = in - in.WriteString(command) - in.WriteString("exit\n") - if err := cmd.Start(); err != nil { - return err - } - return nil -} - -func ExecOsCmd(command, os string) error { - log.Debugf("Exec %s command:%s", os, command) - - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - return nil -} - -func StartSSHCmdWithTimeout(duration int, sshHost, cmdStr string) error { - timeout := time.Duration(duration) * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) // 设置超时 - defer cancel() - cmd := exec.CommandContext(ctx, "ssh", sshHost, cmdStr) - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Start() - if err != nil { - return err - } - return nil -} - -func RunSSHCmd(sshHost, cmdStr string) error { - cmd := exec.Command("ssh", sshHost, cmdStr) - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return err - } - return nil -} diff --git a/features/cm/exec_windows.go b/features/cm/exec_windows.go deleted file mode 100644 index 9e151bf7..00000000 --- a/features/cm/exec_windows.go +++ /dev/null @@ -1,83 +0,0 @@ -//go:build windows -// +build windows - -package cm - -import ( - "bytes" - "context" - "os/exec" - "time" - - "be.ems/lib/log" -) - -func ExecCmd(command string) error { - log.Debug("Exec command:", command) - - cmd := exec.Command("cmd", "/C", command) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - /* - if err := cmd.Start(); err != nil { - log.Error("Start error: ", err) - return err - } - if err := cmd.Wait(); err != nil { - log.Error("Wait error: ", err) - return err - } - */ - return nil -} - -func ExecOsCmd(command, os string) error { - log.Debugf("Exec %s command:%s", os, command) - - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - return nil -} - -func StartSSHCmdWithTimeout(duration int, sshHost, cmdStr string) error { - timeout := time.Duration(duration) * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) // 设置超时 - defer cancel() - cmd := exec.CommandContext(ctx, "ssh", sshHost, cmdStr) - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Start() - if err != nil { - return err - } - return nil -} - -func RunSSHCmd(sshHost, cmdStr string) error { - cmd := exec.Command("ssh", sshHost, cmdStr) - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return err - } - return nil -} diff --git a/features/cm/ne.go b/features/cm/ne.go deleted file mode 100644 index f9cc9670..00000000 --- a/features/cm/ne.go +++ /dev/null @@ -1,991 +0,0 @@ -package cm - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "os/exec" - "strings" - "time" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/constants" - "be.ems/src/framework/database/db" - neService "be.ems/src/modules/network_element/service" - - "github.com/go-resty/resty/v2" - "github.com/gorilla/mux" -) - -var ( - // NE CM export/import - NeCmUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm" - // NE info - UriNeInfo = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo" - // NE backup file - UriNeCmFile = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}" - // service action uri, action: start/stop/restart - UriNeService = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/service/{action}" - // nf instance action uri, action: start/stop/restart - UriNeInstance = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/instance/{action}" - - CustomNeCmUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm" - CustomUriNeInfo = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo" - CustomUriNeCmFile = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}" - // service action uri, action: start/stop/restart - CustomUriNeService = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/service/{action}" - // nf instance action uri, action: start/stop/restart - CustomUriNeInstance = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/instance/{action}" -) - -const ( - NEStatusActive = 0 - NEStatusOffline = 1 - NEStatusStandby = 2 - NEStatusMaintain = 3 -) - -var client = resty.New() - -func init() { - /* - client. - SetTimeout(10 * time.Second). - SetRetryCount(1). - SetRetryWaitTime(1 * time.Second). - SetRetryMaxWaitTime(2 * time.Second). - SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) { - return 0, errors.New("quota exceeded") - }) - */ - client. - SetTimeout(time.Duration(1 * time.Second)) -} - -func GetNeInfo(w http.ResponseWriter, r *http.Request) { - log.Debug("GetNeInfo processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neId := services.GetUriParamString(r, "ne_id", ",", false, false) - - // no, _ := strconv.ParseInt(neId, 10, 64) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - var response services.DataResponse - response.Data = neInfo - services.ResponseWithJson(w, http.StatusOK, response) -} - -type OmcNeConfig struct { - NeId string `json:"neId" xorm:"ne_id"` // 网元标识(内部), - RmUID string `json:"rmUID" xorm:"rm_uid"` // rmUID 网元唯一标识 - NeName string `json:"neName" xorm:"ne_name"` // 网元名称(内部)/友好名称(北向资源/性能等使用) - PvFlag string `json:"pvFlag" xorm:"pv_flag"` // 网元虚实性标识 VNF/PNF: 虚拟/物理 - Province string `json:"province" xorm:"province"` // 网元所在省份 - VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称 - // ManagedBy string `json:"managedBy" xorm:"managed_by"` // 管理ManagedElement的ManagementNode对象类的DN值 - Dn string `json:"dn" xorm:"dn"` // 资源里边的ManagedBy,性能的Dn,网络唯一标识 -} - -func PostNeInfo(w http.ResponseWriter, r *http.Request) { - log.Debug("PostNeInfo processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - syncFlag := services.GetUriParamString(r, "sync2ne", ",", false, false) - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Failed to o.ReadAll:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Trace("Body:", string(body)) - - neInfo := new(dborm.NeInfo) - err = json.Unmarshal(body, neInfo) - if err != nil { - log.Error("Failed to json.Unmarshal:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - //neInfo.UpdateTime = time.Now().Format(time.DateTime) - neInfo.UpdateTime = time.Now() - log.Debug("NE info:", neInfo) - - //if !config.GetYamlConfig().OMC.Chk2Ne { - if syncFlag == "false" || neTypeUpper == config.GetYamlConfig().OMC.NeType { - neInfo.Status = NEStatusMaintain - affected, err := dborm.XormInsertNeInfo(neInfo) - if err != nil { - log.Error("Failed to insert Ne info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 刷新缓存,不存在结构体网元Id空字符串 - neService.NewNeInfo.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow["data"] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) - return - } else { - hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port) - //hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig?ne_id=%s", config.DefaultUriPrefix, strings.ToLower(neInfo.NeType), neInfo.NeId) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri) - log.Debug("requestURI2NF:", requestURI2NF) - - omcNeConfig := &OmcNeConfig{ - NeId: neInfo.NeId, - RmUID: neInfo.RmUID, - NeName: neInfo.NeName, - PvFlag: neInfo.PvFlag, - Province: neInfo.Province, - VendorName: neInfo.VendorName, - Dn: neInfo.Dn, - } - body, _ = json.Marshal(omcNeConfig) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Put(requestURI2NF) - if err != nil { - log.Error("Failed to Put:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Info("StatusCode: ", response.StatusCode()) - - respMsg := make(map[string]interface{}) - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - neInfo.Status = NEStatusActive - affected, err := dborm.XormInsertNeInfo(neInfo) - if err != nil { - log.Error("Failed to dborm.XormInsertNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if affected <= 0 { - log.Infof("Not record affected to insert ne_info") - } - - // 刷新缓存,不存在结构体网元Id空字符串 - neService.NewNeInfo.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) - - services.ResponseStatusOK204NoContent(w) - return - default: - log.Info("response body:", string(response.Body())) - body := new(map[string]interface{}) - _ = json.Unmarshal(response.Body(), &body) - respMsg["error"] = body - } - - services.ResponseWithJson(w, response.StatusCode(), respMsg) - return - } -} - -func PutNeInfo(w http.ResponseWriter, r *http.Request) { - log.Debug("PutNeInfo processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeLower := strings.ToLower(neType) - neTypeUpper := strings.ToUpper(neType) - syncFlag := services.GetUriParamString(r, "sync2ne", ",", false, false) - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Failed to io.ReadAll:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo := new(dborm.NeInfo) - _ = json.Unmarshal(body, neInfo) - neInfo.NeType = strings.ToUpper(neType) - neInfo.UpdateTime = time.Now() - log.Debug("NE info:", neInfo) - - //if !config.GetYamlConfig().OMC.Chk2Ne { - if syncFlag == "false" || neTypeUpper == config.GetYamlConfig().OMC.NeType { - neInfo.Status = NEStatusMaintain - affected, err := dborm.XormUpdateNeInfo(neInfo) - if err != nil { - log.Error("Failed to update Ne info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 刷新缓存,不存在结构体网元Id空字符串 - neService.NewNeInfo.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow["data"] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) - return - } else { - hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port) - //hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig?ne_id=%s", config.DefaultUriPrefix, neTypeLower, neInfo.NeId) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri) - log.Debug("requestURI2NF:", requestURI2NF) - - omcNeConfig := &OmcNeConfig{ - NeId: neInfo.NeId, - RmUID: neInfo.RmUID, - NeName: neInfo.NeName, - PvFlag: neInfo.PvFlag, - Province: neInfo.Province, - VendorName: neInfo.VendorName, - Dn: neInfo.Dn, - } - body, _ = json.Marshal(omcNeConfig) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Put(requestURI2NF) - if err != nil { - log.Error("Failed to Put:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Info("StatusCode: ", response.StatusCode()) - - respMsg := make(map[string]interface{}) - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - neInfo.Status = NEStatusActive - affected, err := dborm.XormUpdateNeInfo(neInfo) - if err != nil { - log.Error("Failed to dborm.XormUpdateNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if affected <= 0 { - log.Infof("Not record affected to insert ne_info") - } - - // 刷新缓存,不存在结构体网元Id空字符串 - neService.NewNeInfo.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) - - services.ResponseStatusOK204NoContent(w) - return - default: - log.Info("response body:", string(response.Body())) - body := new(map[string]interface{}) - _ = json.Unmarshal(response.Body(), &body) - respMsg["error"] = body - } - - services.ResponseWithJson(w, response.StatusCode(), respMsg) - return - } -} - -func DeleteNeInfo(w http.ResponseWriter, r *http.Request) { - log.Debug("DeleteNeInfo processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo := new(dborm.NeInfo) - _ = json.Unmarshal(body, neInfo) - neInfo.NeType = strings.ToUpper(neType) - neInfo.NeId = services.GetUriParamString(r, "ne_id", ",", false, false) - neInfo, err = dborm.XormGetNeInfo(neInfo.NeType, neInfo.NeId) - if err != nil || neInfo == nil { - log.Error("Failed to delete Ne info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("NE info:", neInfo) - - // if NE in active status, can't delete NE - if !IsActiveNF(neInfo) { - affected, err := dborm.XormDeleteNeInfo(neInfo) - if err != nil { - log.Error("Failed to delete Ne info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 刷新缓存,不存在结构体网元Id空字符串 - neService.NewNeInfo.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow["data"] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) - return - } - err = global.ErrCMCannotDeleteActiveNE - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) -} - -func IsActiveNF(neInfo *dborm.NeInfo) bool { - log.Debug("IsActiveNF processing... ") - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI := fmt.Sprintf(config.UriPrefix+"/systemManagement/v1/elementType/%s/objectType/systemState", - strings.ToLower(neInfo.NeType)) - - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(hostUri + requestURI) - if err != nil { - log.Error("Failed to Get:", err) - return false - } - - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - return true - } - return false -} - -func ExportCmFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("ExportCmFromNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - neId := services.GetUriParamString(r, "ne_id", ",", false, false) - - // neInfo := new(dborm.NeInfo) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Errorf("Failed to get ne_info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("neInfo:", neInfo) - nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Backup, neTypeLower) - isExist, err := global.PathExists(nePath) - if err != nil { - log.Errorf("Failed to stat:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - if isExist { - err = os.RemoveAll(nePath) - if err != nil { - log.Errorf("Failed to RemoveAll:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - err = os.MkdirAll(nePath, os.ModePerm) - if err != nil { - log.Errorf("Failed to MkdirAll:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - var scpCmd string - ipType := global.ParseIPAddr(neInfo.Ip) - omcNetypeLower := strings.ToLower(config.GetYamlConfig().OMC.NeType) - etcListIMS := "{*.yaml,mmtel,vars.cfg}" - if config.GetYamlConfig().NE.EtcListIMS != "" { - etcListIMS = config.GetYamlConfig().NE.EtcListIMS - } - switch neTypeLower { - case omcNetypeLower: - if ipType == global.IsIPv4 { - scpCmd = fmt.Sprintf("scp -r %s@%s:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower) - } else { - scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower) - } - - case "ims": - if ipType == global.IsIPv4 { - scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/%s %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.EtcDir, neTypeLower, - etcListIMS, config.GetYamlConfig().OMC.Backup, neTypeLower) - } else { - scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/%s %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.EtcDir, neTypeLower, - etcListIMS, config.GetYamlConfig().OMC.Backup, neTypeLower) - } - - case "mme": - if ipType == global.IsIPv4 { - scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.conf %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.EtcDir, - neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower) - } else { - scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.conf %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.EtcDir, - neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower) - } - - default: - if ipType == global.IsIPv4 { - scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.EtcDir, - neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower) - } else { - scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.EtcDir, - neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower) - } - - } - - zipFile := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, strings.ToLower(neInfo.NeId), time.Now().Format(global.DateData)) - zipFilePath := config.GetYamlConfig().OMC.Backup + "/" + zipFile - zipCmd := fmt.Sprintf("cd %s/etc && zip -r %s %s/*", config.GetYamlConfig().OMC.Backup, zipFilePath, neTypeLower) - - command := fmt.Sprintf("%s&&%s", scpCmd, zipCmd) - - log.Debug("command:", command) - err = ExecCmd(command) - if err != nil { - log.Error("Faile to exec command:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - md5Sum, err := global.GetFileMD5Sum(zipFilePath) - if err != nil { - log.Error("Faile to md5sum:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - //log.Debug("md5Str:", md5Sum) - path := config.GetYamlConfig().OMC.Backup - neBackup := dborm.NeBackup{NeType: neTypeUpper, NeId: neId, FileName: zipFile, Path: path, Md5Sum: md5Sum} - _, err = dborm.XormInsertTableOne("ne_backup", neBackup) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - //services.ResponseFileWithNameAndMD5(w, http.StatusOK, zipFile, path, md5Sum) - services.ResponseStatusOK204NoContent(w) -} - -type ImportCMJson struct { - FileName string `json:"fileName"` -} - -func ImportCmToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("ImportCmToNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - neId := services.GetUriParamString(r, "ne_id", ",", false, false) - - var fileName, path string - if services.IsJsonContentType(r) { - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Debug("Body:", string(body)) - - importCMJson := new(ImportCMJson) - _ = json.Unmarshal(body, importCMJson) - fileName = importCMJson.FileName - path = config.GetYamlConfig().OMC.Backup - } else { - path = config.GetYamlConfig().OMC.Upload - fileNamePath, err := services.HandleUploadFile(r, path, "") - if err != nil { - log.Error("Faile to HandleUploadFile:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - fileName = fileNamePath - } - filePath := fmt.Sprintf("%s/%s", path, fileName) - - // neInfo := new(dborm.NeInfo) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Errorf("Failed to get ne_info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("neInfo:", neInfo) - - md5Sum, err := global.GetFileMD5Sum(filePath) - if err != nil { - log.Error("Faile to GetFileMD5Sum:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - //neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum} - //log.Debug("neBackup:", neBackup) - where := fmt.Sprintf("ne_type='%s' and ne_id='%s' and md5_sum='%s'", neTypeUpper, neId, md5Sum) - has, err := dborm.XormExistTableOne("ne_backup", where) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if !has { - err = global.ErrCMInvalidBackupFile - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower) - // isExist, err := global.PathExists(nePath) - // if err != nil { - // log.Errorf("Failed to stat:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // if isExist { - // err = os.RemoveAll(nePath) - // if err != nil { - // log.Errorf("Failed to remove:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // } - // unzipCmd := fmt.Sprintf("unzip -o %s -d %s", filePath, config.GetYamlConfig().OMC.Upload) - - // var scpCmd string - // ipType := global.ParseIPAddr(neInfo.Ip) - // if ipType == global.IsIPv4 { - // scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@%s:%s", config.GetYamlConfig().OMC.Upload, - // neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir) - // } else { - // scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@[%s]:%s", config.GetYamlConfig().OMC.Upload, - // neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir) - // } - - // err = ExecCmd(fmt.Sprintf("%s && %s", unzipCmd, scpCmd)) - // if err != nil { - // log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - - // nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower) - // isExist, err := global.PathExists(nePath) - // if err != nil { - // log.Errorf("Failed to stat:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // if isExist { - // err = os.RemoveAll(nePath) - // if err != nil { - // log.Errorf("Failed to remove:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // } - var scpZipCmd string - ipType := global.ParseIPAddr(neInfo.Ip) - if ipType == global.IsIPv4 { - scpZipCmd = fmt.Sprintf("scp -r %s %s@%s:%s", filePath, - config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - } else { - scpZipCmd = fmt.Sprintf("scp -r %s %s@[%s]:%s", filePath, - config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - } - err = ExecCmd(scpZipCmd) - if err != nil { - log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + fileName - var unzipCmd string - if neTypeLower != "omc" { - unzipCmd = fmt.Sprintf("sudo unzip -o %s -d %s", neFilePath, config.GetYamlConfig().NE.EtcDir) - } else { - unzipCmd = fmt.Sprintf("sudo unzip -oj %s -d %s/etc", neFilePath, config.GetYamlConfig().NE.OmcDir) - } - sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - cmd := exec.Command("ssh", sshHost, unzipCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute command:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} - -func DownloadNeBackupFile(w http.ResponseWriter, r *http.Request) { - log.Debug("DownloadNeBackupFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - //neTypeLower := strings.ToLower(neType) - - fileName := vars["fileName"] - if fileName == "" { - log.Error("fileName is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName) - neBackup, err := db.RawDB("", sql, nil) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(neBackup) == 0 { - err := global.ErrCMNotFoundTargetBackupFile - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - path := fmt.Sprint(neBackup[0]["path"]) - md5Sum := fmt.Sprint(neBackup[0]["md5_sum"]) - - services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum) -} - -func DeleteNeBackupFile(w http.ResponseWriter, r *http.Request) { - log.Debug("DeleteNeBackupFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - //neTypeLower := strings.ToLower(neType) - - fileName := vars["fileName"] - if fileName == "" { - log.Error("fileName is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName) - neBackup, err := db.RawDB("", sql, nil) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(neBackup) == 0 { - err := global.ErrCMNotFoundTargetBackupFile - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - where := fmt.Sprintf("ne_type='%s' and file_name='%s'", neTypeUpper, fileName) - affected, err := dborm.XormDeleteDataByWhere(where, "ne_backup") - if err != nil || affected == 0 { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - path := neBackup[0]["path"] - filePath := fmt.Sprintf("%s/%s", path, fileName) - err = os.Remove(filePath) - if err != nil { - log.Error("Faile to Remove:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} - -func PostNeServiceAction(w http.ResponseWriter, r *http.Request) { - log.Debug("PostNeServiceAction processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - action := vars["action"] - - neId := services.GetUriParamString(r, "neId", ",", false, false) - - // neInfo := new(dborm.NeInfo) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to get ne_info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("neInfo:", neInfo) - - sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - switch neTypeLower { - case "omc": - // send 204 to fe firstly - services.ResponseStatusOK204NoContent(w) - //actionCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh %s", config.GetYamlConfig().NE.OmcDir, action) - actionCmd := fmt.Sprintf("sudo systemctl %s omc", action) - go RunSSHCmd(sshHost, actionCmd) - return - // cmd := exec.Command("ssh", sshHost, actionCmd) - // out, err := cmd.CombinedOutput() - // log.Debugf("Exec output: %v", string(out)) - // if err != nil { - // log.Errorf("Faile to execute ssh %s omc:%v", action, err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - case "ims": - switch action { - case "start", "stop": - actionCmd := fmt.Sprintf("sudo ims-%s", action) - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Errorf("Faile to execute %s command:%v", actionCmd, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - case "restart": - actionCmd := "sudo ims-stop && sudo ims-start" - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Errorf("Faile to execute %s command:%v", actionCmd, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - default: - err = global.ErrCMUnknownServiceAction - log.Errorf("%v, action:%s", err, action) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - default: - actionCmd := fmt.Sprintf("sudo systemctl %s %s.service", action, neTypeLower) - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute command:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - - services.ResponseStatusOK204NoContent(w) -} - -func PostNeInstanceAction(w http.ResponseWriter, r *http.Request) { - log.Debug("PostNeInstanceAction processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeUpper := strings.ToUpper(neType) - //neTypeLower := strings.ToLower(neType) - action := vars["action"] - - neId := services.GetUriParamString(r, "neId", ",", false, false) - - // neInfo := new(dborm.NeInfo) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Errorf("Failed to get ne_info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("neInfo:", neInfo) - - sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - switch action { - case "poweron": - actionCmd := "sudo poweron" - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh %s omc:", action, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - case "poweroff": - actionCmd := "sudo poweroff" - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh sudo poweroff:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - case "reboot": - actionCmd := "sudo reboot" - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh sudo reboot:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - default: - err = global.ErrCMUnknownInstanceAction - log.Errorf("%v, action:%s", err, action) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} diff --git a/features/cm/omc/controller.go b/features/cm/omc/controller.go deleted file mode 100644 index 888f182f..00000000 --- a/features/cm/omc/controller.go +++ /dev/null @@ -1,46 +0,0 @@ -package cm_omc - -import ( - "fmt" - "net/http" - - "be.ems/lib/services" - "github.com/gin-gonic/gin" -) - -func (o *ConfigOMC) Get(c *gin.Context) { - paramName := c.Param("paramName") - results, err := o.Query(paramName) - if err != nil { - c.JSON(http.StatusInternalServerError, services.ErrResp(err.Error())) - return - } - c.JSON(http.StatusOK, services.DataResp(results)) -} - -func (o *ConfigOMC) Post(c *gin.Context) { - err := fmt.Errorf("method not allowed") - c.JSON(http.StatusMethodNotAllowed, services.ErrResp(err.Error())) -} - -func (o *ConfigOMC) Put(c *gin.Context) { - paramName := c.Param("paramName") - var paramData map[string]any - - if err := c.ShouldBindJSON(¶mData); err != nil { - c.JSON(http.StatusBadRequest, services.ErrResp(err.Error())) - return - } - - result, err := o.Modify(paramName, paramData) - if err != nil { - c.JSON(http.StatusInternalServerError, services.ErrResp(err.Error())) - return - } - c.JSON(http.StatusOK, services.DataResp(result)) -} - -func (o *ConfigOMC) Delete(c *gin.Context) { - err := fmt.Errorf("method not allowed") - c.JSON(http.StatusMethodNotAllowed, services.ErrResp(err.Error())) -} diff --git a/features/cm/omc/implement.go b/features/cm/omc/implement.go deleted file mode 100644 index 9d7a4300..00000000 --- a/features/cm/omc/implement.go +++ /dev/null @@ -1,69 +0,0 @@ -package cm_omc - -import ( - "fmt" - - "be.ems/lib/config" -) - -const ( - PASSWORD_MASK = "********" -) - -func (o *ConfigOMC) Query(paramName string) (any, error) { - var results []any - - switch paramName { - case "alarmEmailForward": - result := config.GetYamlConfig().Alarm.EmailForward - result.Password = PASSWORD_MASK - results = append(results, result) - case "alarmSMSForward": - result := config.GetYamlConfig().Alarm.SMSCForward - result.Password = PASSWORD_MASK - results = append(results, result) - default: - return nil, fmt.Errorf("invalid source parameter") - } - - return results, nil -} - -func (o *ConfigOMC) Add() { - -} - -func (o *ConfigOMC) Modify(paramName string, paramData map[string]any) (any, error) { - var results []any - - switch paramName { - case "alarmEmailForward": - param := &(config.GetYamlConfig().Alarm.EmailForward) - config.UpdateStructFromMap(param, paramData) - result := *param - results = append(results, result) - err := config.WriteOrignalConfig(config.YamlConfigInfo.FilePath, paramName, paramData) - if err != nil { - fmt.Println("failed to write config yaml file:", err) - return results, err - } - case "alarmSMSForward": - param := &(config.GetYamlConfig().Alarm.SMSCForward) - config.UpdateStructFromMap(param, paramData) - result := *param - results = append(results, result) - err := config.WriteOrignalConfig(config.YamlConfigInfo.FilePath, paramName, paramData) - if err != nil { - fmt.Println("failed to write config yaml file:", err) - return results, err - } - default: - return nil, fmt.Errorf("invalid source parameter") - } - - return results, nil -} - -func (o *ConfigOMC) Remove() { - -} diff --git a/features/cm/omc/model.go b/features/cm/omc/model.go deleted file mode 100644 index 967c84c6..00000000 --- a/features/cm/omc/model.go +++ /dev/null @@ -1,26 +0,0 @@ -package cm_omc - -type ConfigOMC struct{} - -type SystemConfig struct { - ForwardFlag bool `json:"forwardFlag"` -} - -type AlarmEmailForward struct { - Enable bool `json:"enable"` - EmailList string `json:"emailList"` - SMTP string `json:"smtp"` - Port uint16 `json:"port"` - User string `json:"user"` - Password string `json:"password"` - TLSSkipVerify bool `json:"tlsSkipVerify"` -} - -type AlarmSMSForward struct { - Enable bool `json:"enable"` - MobileList string `json:"mobileList"` - SMSCAddr string `json:"smscAddr"` - SystemID string `json:"systemID"` - Password string `json:"password"` - SystemType string `json:"systemType"` -} diff --git a/features/cm/omc/route.go b/features/cm/omc/route.go deleted file mode 100644 index e97f7b5f..00000000 --- a/features/cm/omc/route.go +++ /dev/null @@ -1,30 +0,0 @@ -package cm_omc - -import ( - "be.ems/src/framework/middleware" - "github.com/gin-gonic/gin" -) - -// Register Routes for file_export -func Register(r *gin.RouterGroup) { - cmOMC := r.Group("/omc") - { - var o *ConfigOMC - cmOMC.GET("/config/:paramName", - middleware.AuthorizeUser(nil), - o.Get, - ) - cmOMC.POST("/config/:paramName", - middleware.AuthorizeUser(nil), - o.Post, - ) - cmOMC.PUT("/config/:paramName", - middleware.AuthorizeUser(nil), - o.Put, - ) - cmOMC.DELETE("/config/:paramName", - middleware.AuthorizeUser(nil), - o.Delete, - ) - } -} diff --git a/features/cm/param.go b/features/cm/param.go deleted file mode 100644 index 1b1266d0..00000000 --- a/features/cm/param.go +++ /dev/null @@ -1,208 +0,0 @@ -package cm - -import ( - "strings" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - - "encoding/json" - "fmt" - "io" - "net/http" - - neService "be.ems/src/modules/network_element/service" - - "github.com/go-resty/resty/v2" - "github.com/gorilla/mux" -) - -var ( - // parameter config management - ParamConfigUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}" - - CustomParamConfigUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}" -) - -func GetParamConfigFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetParamConfigFromNF processing... ") - - neId := ctx.GetQuery(r, "ne_id") - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" || neId == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID(neType, neId) - - var response services.DataResponse - if neInfo.NeId == neId && neInfo.NeId != "" { - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Failed to Get from NF:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - _ = json.Unmarshal(resp.Body(), &response) - } - log.Debug("response:", response) - } - - services.ResponseWithJson(w, http.StatusOK, response) -} - -func PostParamConfigToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostParamConfigToNF processing... ") - - neId := ctx.GetQuery(r, "ne_id") - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" || neId == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID(neType, neId) - - if neInfo.NeId != neId || neInfo.NeId == "" { - log.Error("neId is empty") - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: POST ", requestURI2NF) - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - client := resty.New() - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Post(requestURI2NF) - if err != nil { - log.Error("Failed to POST to NF:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseWithJson(w, http.StatusNoContent, response) -} - -func PutParamConfigToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PutParamConfigToNF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // OMC配置接口 /api/rest/systemManagement/v1/elementType/omc/objectType/config/omcNeConfig - if v, ok := vars["paraName"]; ok && v == "omcNeConfig" && strings.ToLower(neType) == "omc" { - PutOMCNeConfig(w, r) - return - } - - neId := ctx.GetQuery(r, "ne_id") - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID(neType, neId) - - if neInfo.NeId != neId || neInfo.NeId == "" { - log.Error("neId is empty") - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: PUT ", requestURI2NF) - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - client := resty.New() - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Put(requestURI2NF) - if err != nil { - log.Error("Failed to Put to NF:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseWithJson(w, http.StatusNoContent, response) -} - -// PutOMCNeConfig 网元OMC配置 -// -// 目前没配置,返回204 -func PutOMCNeConfig(w http.ResponseWriter, r *http.Request) { - services.ResponseStatusOK204NoContent(w) -} - -func DeleteParamConfigToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("DeleteParamConfigToNF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neId := ctx.GetQuery(r, "ne_id") - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID(neType, neId) - - if neInfo.NeId != neId || neInfo.NeId == "" { - log.Error("neId is empty") - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: DELETE ", requestURI2NF) - - client := resty.New() - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Delete(requestURI2NF) - if err != nil { - log.Error("Failed to delete parameter:", err) - services.ResponseInternalServerError500NFConnectRefused(w) - return - } - - services.ResponseWithJson(w, http.StatusNoContent, response) -} diff --git a/features/cm/service.go b/features/cm/service.go deleted file mode 100644 index f5d8b692..00000000 --- a/features/cm/service.go +++ /dev/null @@ -1,17 +0,0 @@ -package cm - -import ( - cm_omc "be.ems/features/cm/omc" - "be.ems/lib/log" - "github.com/gin-gonic/gin" -) - -func InitSubServiceRoute(r *gin.Engine) { - log.Info("======init PM group gin.Engine") - - cmGroup := r.Group("/cm") - // register sub modules routes - cm_omc.Register(cmGroup) - - // return featuresGroup -} diff --git a/features/cm/software.go b/features/cm/software.go deleted file mode 100644 index fd873702..00000000 --- a/features/cm/software.go +++ /dev/null @@ -1,1052 +0,0 @@ -package cm - -import ( - "bytes" - "fmt" - "io" - "net/http" - "os" - "os/exec" - "strconv" - "strings" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - - "github.com/gorilla/mux" -) - -const ( - SoftwareStatusUploaded = "3" - SoftwareStatusInactive = "3" - SoftwareStatusActive = "1" - DigestsSignOkString = "digests signatures OK" - SoftwareVerifiedOk = "Verified OK" -) - -var ( - UriSoftware = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}" - UriSoftwareNE = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}" - - CustomUriSoftware = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}" - CustomUriSoftwareNE = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}" -) - -// 验证签名 -func verify_signature(public_key_name string, source_cms_file string, source_file string) bytes.Buffer { - cmd := exec.Command("/usr/local/omc/run/iv", "verify_signature", public_key_name, source_cms_file, source_file) - var out bytes.Buffer - cmd.Stdout = &out - cmd.Env = append(os.Environ(), - "FOO=duplicate_value", // 重复被忽略 - "FOO=actual_value", // 实际被使用 - ) - err := cmd.Run() - if err != nil { - log.Error(err) - } - - return out -} - -func UploadSoftwareFile(w http.ResponseWriter, r *http.Request) { - log.Debug("UploadSoftwareFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false) - - // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - // if err != nil { - // log.Error("io.ReadAll is failed:", err) - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - // neSWBody := new(dborm.NeSoftware) - // _ = json.Unmarshal(body, neSWBody) - // log.Trace("neSoftware:", neSWBody) - - softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower) - fileName, err := services.HandleUploadFile(r, softwarePath, "") - if err != nil { - log.Error("Faile to HandleUploadFile:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - filePrefix := fileName[:strings.Index(fileName, ".zip")] - filePath := fmt.Sprintf("%s/%s", softwarePath, fileName) - log.Debugf("filePath:%s filePrefix:%s softwarePath:%s", filePath, filePrefix, softwarePath) - cmd := exec.Command("unzip", "-o", filePath) - cmd.Dir = softwarePath - out, err := cmd.CombinedOutput() - log.Debugf("Exec outpout:%s", string(out)) - if err != nil { - log.Error("Failed to unzip:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - md5File, err := global.GetFileMD5Sum(filePath) - if err != nil { - log.Error("Faile to GetFileMD5Sum:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - if md5File != md5Param { - err = global.ErrCMNotMatchMD5File - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - rpmFileName := filePrefix + ".rpm" - if config.GetYamlConfig().OMC.CheckSign { - rpmFilePath := softwarePath + "/" + rpmFileName - cmsFileName := rpmFileName + ".cms" - cmsFilePath := softwarePath + "/" + cmsFileName - log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey) - result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath) - log.Debug("result:", result.String()) - if !strings.Contains(result.String(), SoftwareVerifiedOk) { - err = global.ErrCMNotMatchSignFile - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - // cmd := exec.Command("rpm", "-K", filePath) - // out, err := cmd.CombinedOutput() - // log.Debugf("Exec outpout:%s", string(out)) - // if err != nil { - // log.Error("Failed to execute rpm:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // if !strings.Contains(string(out), DigestsSignOkString) { - // err = global.ErrCMNotMatchSignFile - // log.Error(err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - } - - //neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum} - //log.Debug("neBackup:", neBackup) - where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version) - has, err := dborm.XormExistTableOne("ne_software", where) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if has { - err = global.ErrCMExistSoftwareFile - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - neSoftware := dborm.NeSoftware{ - NeType: neTypeUpper, - FileName: rpmFileName, - Path: softwarePath, - Version: version, - Md5Sum: md5Param, - Comment: neType + " 5GC " + version, - //Comment: neSWBody.Comment, - } - - _, err = dborm.XormInsertTableOne("ne_software", neSoftware) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} - -func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) { - log.Info("UploadSoftwareMultiFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version) - neSoftwareInfo, _ := dborm.XormGetDataBySQL(sql) - if len(*neSoftwareInfo) >= 1 { - services.ResponseWithJson(w, 200, map[string]any{ - "code": 0, - "msg": "Software version already exists", - }) - return - } - - md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false) - - softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower) - err := os.MkdirAll(softwarePath, os.ModePerm) - if err != nil { - log.Error("Failed to Mkdir:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - //fileName, err := services.HandleUploadFile(r, softwarePath, "") - - // 解析multipart/form-data请求 - err = r.ParseMultipartForm(1000 << 20) // 1000MB - if err != nil { - log.Error("Faile to ParseMultipartForm:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 获取文件和数据 - swFile := r.MultipartForm.File["file"] - cmsFile := r.MultipartForm.File["cms"] - data := r.MultipartForm.Value["comment"] - - var softwareFileName, cmsFileName, comment string - - // 处理软件rpm/deb文件 - if len(swFile) > 0 { - file := swFile[0] - // 打开文件 - f, err := file.Open() - if err != nil { - log.Error("Faile to Open:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - defer f.Close() - - // 创建本地文件 - dst, err := os.Create(softwarePath + "/" + file.Filename) - if err != nil { - log.Error("Faile to Create:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - defer dst.Close() - - softwareFileName = file.Filename - // 将文件内容拷贝到本地文件 - _, err = io.Copy(dst, f) - if err != nil { - log.Error("Faile to Copy:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - - // 处理cms文件 - if len(cmsFile) > 0 { - file := cmsFile[0] - // 打开文件 - f, err := file.Open() - if err != nil { - log.Error("Faile to Open:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - defer f.Close() - - // 创建本地文件 - dst, err := os.Create(softwarePath + "/" + file.Filename) - if err != nil { - log.Error("Faile to Create:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - defer dst.Close() - - cmsFileName = file.Filename - // 将文件内容拷贝到本地文件 - _, err = io.Copy(dst, f) - if err != nil { - log.Error("Faile to Copy:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - - // 处理数据 - if len(data) > 0 { - comment = data[0] - } - - if config.GetYamlConfig().OMC.CheckSign && cmsFileName != "" { - rpmFilePath := softwarePath + "/" + softwareFileName - cmsFileName := cmsFileName - cmsFilePath := softwarePath + "/" + cmsFileName - log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey) - result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath) - log.Debug("result:", result.String()) - if !strings.Contains(result.String(), SoftwareVerifiedOk) { - err = global.ErrCMNotMatchSignFile - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - // cmd := exec.Command("rpm", "-K", filePath) - // out, err := cmd.CombinedOutput() - // log.Debugf("Exec outpout:%s", string(out)) - // if err != nil { - // log.Error("Failed to execute rpm:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // if !strings.Contains(string(out), DigestsSignOkString) { - // err = global.ErrCMNotMatchSignFile - // log.Error(err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - } - - // //neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum} - // //log.Debug("neBackup:", neBackup) - // where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version) - // has, err := dborm.XormExistTableOne("ne_software", where) - // if err != nil { - // log.Error("Faile to XormInsertTableOne:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } else if has == true { - // err = global.ErrCMExistSoftwareFile - // log.Error(err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - - neSoftware := dborm.NeSoftware{ - NeType: neTypeUpper, - FileName: softwareFileName, - Path: softwarePath, - Version: version, - Md5Sum: md5Param, - Comment: comment, - } - - _, err = dborm.XormInsertTableOne("ne_software", neSoftware) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} - -func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) { - log.Debug("DownloadSoftwareFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - //neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version) - neSoftware, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(*neSoftware) == 0 { - err := global.ErrCMNotFoundTargetSoftware - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - fileName := (*neSoftware)[0]["name"] - path := (*neSoftware)[0]["path"] - md5Sum := (*neSoftware)[0]["md5_sum"] - - services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum) -} - -func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) { - log.Debug("DeleteSoftwareFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - //neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version) - neSoftware, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(*neSoftware) == 0 { - err := global.ErrCMNotFoundTargetSoftware - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version) - affected, err := dborm.XormDeleteDataByWhere(where, "ne_software") - if err != nil || affected == 0 { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - fileName := (*neSoftware)[0]["name"] - path := (*neSoftware)[0]["path"] - filePath := fmt.Sprintf("%s/%s", path, fileName) - err = os.Remove(filePath) - if err != nil { - log.Error("Faile to Remove:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} - -func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("DistributeSoftwareFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neId := vars["neId"] - if version == "" { - log.Error("neId is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version) - neSoftware, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(*neSoftware) == 0 { - err := global.ErrCMNotFoundTargetSoftware - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neSoftware:", neSoftware) - - sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId) - neVersion, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neVersion:", neVersion) - - sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - mkdirCmd := fmt.Sprintf("sudo mkdir -p %s/software/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower) - cmd := exec.Command("ssh", sshHost, mkdirCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to mkdir:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - fileName := (*neSoftware)[0]["name"] - path := (*neSoftware)[0]["path"] - srcFile := fmt.Sprintf("%s/%s", path, fileName) - - scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - cmd = exec.Command("scp", "-r", srcFile, scpDir) - out, err = cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + fileName - cpCmd := fmt.Sprintf("sudo mv -f %s %s/software/%s", neFilePath, - config.GetYamlConfig().NE.OmcDir, neTypeLower) - cmd = exec.Command("ssh", sshHost, cpCmd) - out, err = cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute cp command:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - if len(*neVersion) == 0 { - neVersionData := dborm.NeVersion{ - NeType: neTypeUpper, - NeId: neInfo.NeId, - Version: (*neSoftware)[0]["version"], - FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName), - PreVersion: "", - PreFile: "", - Status: SoftwareStatusInactive, - } - - _, err = dborm.XormInsertTableOne("ne_version", neVersionData) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } else { - idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) - neVersionData := dborm.NeVersion{ - NeType: neTypeUpper, - NeId: neInfo.NeId, - Version: (*neSoftware)[0]["version"], - FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName), - PreVersion: (*neVersion)[0]["version"], - PreFile: (*neVersion)[0]["path"], - Status: SoftwareStatusInactive, - } - - _, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData) - if err != nil { - log.Error("Faile to UpdateTableById:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - - services.ResponseStatusOK204NoContent(w) -} - -func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("ActiveSoftwareToNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neId := vars["neId"] - if version == "" { - log.Error("neId is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version) - neSoftware, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(*neSoftware) == 0 { - err := global.ErrCMNotFoundTargetSoftware - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neSoftware:", neSoftware) - - sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s' and version='%s'", neTypeUpper, neId, version) - neVersion, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(*neVersion) == 0 { - err := global.ErrCMNotFoundTargetNeVersion - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neVersion:", neVersion) - - if !config.GetYamlConfig().OMC.TestMode { - filePath := (*neVersion)[0]["path"] - sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - - runCmd := fmt.Sprintf("sudo rm -f %s/actpkg.sh", config.GetYamlConfig().NE.ScpDir) - err = RunSSHCmd(sshHost, runCmd) - if err != nil { - log.Errorf("Failed to run cmd: %s", runCmd) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - srcFile := fmt.Sprintf("%s/actpkg.sh", config.GetYamlConfig().OMC.BinDir) - scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - cmd := exec.Command("scp", "-r", srcFile, scpDir) - _, err := cmd.CombinedOutput() - if err != nil { - log.Errorf("Failed to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - runCmd = fmt.Sprintf("sudo %s/actpkg.sh '%s' %s", - config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper) - if neTypeLower == "omc" { - idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) - neVersionData := dborm.NeVersion{ - Status: SoftwareStatusActive, - } - - _, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData) - if err != nil { - log.Error("Faile to UpdateTableById:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) - go RunSSHCmd(sshHost, runCmd) - return - } - err = RunSSHCmd(sshHost, runCmd) - if err != nil { - log.Errorf("Faile to execute command: %s, error: %v", runCmd, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // fileType := global.IsRpmOrDebPackage(filePath) - // if fileType == 1 { - // srcFile := fmt.Sprintf("%s/spawnrpm.sh", config.GetYamlConfig().OMC.BinDir) - - // scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, - // neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - // cmd := exec.Command("scp", "-r", srcFile, scpDir) - // _, err := cmd.CombinedOutput() - // if err != nil { - // log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - - // dpkgCmd := fmt.Sprintf("sudo %s/spawnrpm.sh '%s'", - // config.GetYamlConfig().NE.ScpDir, filePath) - // err = RunSSHCmd(sshHost, dpkgCmd) - // if err != nil { - // log.Errorf("Faile to execute dpkg command: %s, error: %v", dpkgCmd, err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // } else if fileType == 2 { - // srcFile := fmt.Sprintf("%s/spawndpkg.sh", config.GetYamlConfig().OMC.BinDir) - - // scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, - // neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - // cmd := exec.Command("scp", "-r", srcFile, scpDir) - // _, err := cmd.CombinedOutput() - // if err != nil { - // log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - - // dpkgCmd := fmt.Sprintf("sudo %s/spawndpkg.sh '%s'", - // config.GetYamlConfig().NE.ScpDir, filePath) - // err = RunSSHCmd(sshHost, dpkgCmd) - // if err != nil { - // log.Errorf("Faile to execute dpkg command: %s, error: %v", dpkgCmd, err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // } else { - // err := global.ErrCMUnknownSoftwareFormat - // log.Error(err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - switch neTypeLower { - case "omc": - restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir) - cmd := exec.Command("ssh", sshHost, restartCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh restart omc:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - case "ims": - restartCmd := "sudo ims-stop && sudo ims-start" - cmd := exec.Command("ssh", sshHost, restartCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh command: %s, error: %v", restartCmd, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - default: - restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower) - cmd := exec.Command("ssh", sshHost, restartCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh sudo systemctl command:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - } - - idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) - neVersionData := dborm.NeVersion{ - Status: SoftwareStatusActive, - } - - _, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData) - if err != nil { - log.Error("Faile to UpdateTableById:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} - -func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("ActiveSoftwareToNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - neTypeUpper := strings.ToUpper(neType) - neTypeLower := strings.ToLower(neType) - - version := vars["version"] - if version == "" { - log.Error("version is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neId := vars["neId"] - if version == "" { - log.Error("neId is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - sql := fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId) - neVersion, err := dborm.XormGetDataBySQL(sql) - if err != nil { - log.Error("Faile to XormGetDataBySQL:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if len(*neVersion) == 0 { - err := global.ErrCMNotFoundTargetNeVersion - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("neVersion:", neVersion) - - filePath := (*neVersion)[0]["pre_file"] - if filePath == "" { - err := global.ErrCMNotFoundRollbackNeVersion - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - if !config.GetYamlConfig().OMC.TestMode { - sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - runCmd := fmt.Sprintf("sudo rm -f %s/rbkpkg.sh", config.GetYamlConfig().NE.ScpDir) - err = RunSSHCmd(sshHost, runCmd) - if err != nil { - log.Errorf("Failed to run cmd: %s", runCmd) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - srcFile := fmt.Sprintf("%s/rbkpkg.sh", config.GetYamlConfig().OMC.BinDir) - - scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, - neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - cmd := exec.Command("scp", "-r", srcFile, scpDir) - _, err := cmd.CombinedOutput() - if err != nil { - log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - runCmd = fmt.Sprintf("sudo %s/rbkpkg.sh '%s' %s", - config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper) - if neTypeLower == "omc" { - idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) - neVersionData := dborm.NeVersion{ - Version: (*neVersion)[0]["pre_version"], - FilePath: (*neVersion)[0]["pre_file"], - PreVersion: "-", - PreFile: "-", - NewVersion: (*neVersion)[0]["version"], - NewFile: (*neVersion)[0]["path"], - Status: SoftwareStatusActive, - } - - _, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData) - if err != nil { - log.Error("Faile to UpdateTableById:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - services.ResponseStatusOK204NoContent(w) - go RunSSHCmd(sshHost, runCmd) - return - } - err = RunSSHCmd(sshHost, runCmd) - if err != nil { - log.Errorf("Faile to execute command: %s, error: %v", runCmd, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - // fileType := global.IsRpmOrDebPackage(filePath) - // if fileType == 1 { - // rpmCmd := fmt.Sprintf("sudo rpm -Uvh --oldpackage '%s'", filePath) - // cmd := exec.Command("ssh", sshHost, rpmCmd) - // _, err := cmd.CombinedOutput() - // if err != nil { - // log.Error("Faile to execute rpm command:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // } else if fileType == 2 { - // srcFile := fmt.Sprintf("%s/spawndpkg.sh", config.GetYamlConfig().OMC.BinDir) - - // scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, - // neInfo.Ip, config.GetYamlConfig().NE.ScpDir) - // cmd := exec.Command("scp", "-r", srcFile, scpDir) - // _, err := cmd.CombinedOutput() - // if err != nil { - // log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // var inputStr string = "n" - // if config.GetYamlConfig().NE.DpkgOverwrite { - // inputStr = "y" - // } - // dpkgCmd := fmt.Sprintf("sudo %s/spawndpkg.sh %s '%s'", - // config.GetYamlConfig().NE.ScpDir, inputStr, filePath) - // err = RunSSHCmd(sshHost, dpkgCmd) - // if err != nil { - // log.Errorf("Faile to execute dpkg command: %s, error: %v", dpkgCmd, err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // } else { - // err := global.ErrCMUnknownSoftwareFormat - // log.Error(err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - switch neTypeLower { - case "omc": - restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir) - cmd := exec.Command("ssh", sshHost, restartCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh restart omc:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - case "ims": - restartCmd := "sudo ims-stop && sudo ims-start" - cmd := exec.Command("ssh", sshHost, restartCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh command: %s, error: %v", restartCmd, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - default: - restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower) - cmd := exec.Command("ssh", sshHost, restartCmd) - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to execute ssh sudo systemctl command:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - } - } - - idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) - neVersionData := dborm.NeVersion{ - Version: (*neVersion)[0]["pre_version"], - FilePath: (*neVersion)[0]["pre_file"], - PreVersion: "-", - PreFile: "-", - NewVersion: (*neVersion)[0]["version"], - NewFile: (*neVersion)[0]["path"], - Status: SoftwareStatusActive, - } - - _, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData) - if err != nil { - log.Error("Faile to UpdateTableById:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - services.ResponseStatusOK204NoContent(w) -} diff --git a/features/dbrest/dbrest.go b/features/dbrest/dbrest.go deleted file mode 100644 index d11f981a..00000000 --- a/features/dbrest/dbrest.go +++ /dev/null @@ -1,859 +0,0 @@ -package dbrest - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "regexp" - "strings" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/database/db" - - "github.com/gorilla/mux" -) - -type XormResponse struct { - Data interface{} `json:"data"` -} - -type XormInsertResponse struct { - Data interface{} `json:"data"` -} - -var ( - // database management rest pattern, discard - XormGetDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}" - XormSelectDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/select/{elementTypeValue}/{objectTypeValue}" - XormInsertDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/insert/{elementTypeValue}/{objectTypeValue}" - XormUpdateDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/update/{elementTypeValue}/{objectTypeValue}" - XormDeleteDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/delete/{elementTypeValue}/{objectTypeValue}" - - CustomXormGetDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}" - CustomXormSelectDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/select/{elementTypeValue}/{objectTypeValue}" - CustomXormInsertDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/insert/{elementTypeValue}/{objectTypeValue}" - CustomXormUpdateDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/update/{elementTypeValue}/{objectTypeValue}" - CustomXormDeleteDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/delete/{elementTypeValue}/{objectTypeValue}" - - XormCommonUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for internal - XormDatabaseUri = config.DefaultUriPrefix + "/database/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for crontask - XormDataRestUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}" - XormExtDataUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external - XormDataSQLUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external - - CustomXormCommonUri = config.UriPrefix + "/databaseManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for internal - CustomXormExtDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external - CustomXormDataSQLUri = config.UriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external - - // 查询数据库连接情况 - UriDbConnection = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbConnection" - CustomUriDbConnection = config.UriPrefix + "/dataManagement/{apiVersion}/dbConnection" // for external - - // 终结非法的数据库连接 - UriDbStop = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbStop" - CustomUriDbStop = config.UriPrefix + "/dataManagement/{apiVersion}/dbStop" // for external - -) - -func GetUriSQLArray(r *http.Request) []string { - var sa []string - vars := r.URL.Query() - - // 默认SQL - if s, ok := vars["SQL"]; ok { - for _, r := range s { - if r != "" { - sa = append(sa, r) - } - } - } - - // 查询总数 - if totalSQL, ok := vars["totalSQL"]; ok { - if totalSQL[0] != "" { - sa = append(sa, totalSQL[0]) - } - } - // 查询列表 - if rowsSQL, ok := vars["rowsSQL"]; ok { - if rowsSQL[0] != "" { - sa = append(sa, rowsSQL[0]) - } - } - - if len(sa) == 0 { - log.Info("SQL is not exist") - return nil - } - - log.Debug("SQL array:", sa) - return sa -} - -// Get table name from SQL -func GetTableNameFromSQL(s string) string { - ls := strings.ToLower(s) - i1 := strings.Index(ls, "from") - i2 := strings.Index(ls, "where") - - var ts string - if i1 > 0 { - if i2 > 0 && i2 > i1 { - ts = ls[i1+4 : i2] - } - if i2 < 0 { - ts = ls[i1+4:] - } - } - - tn := strings.Trim(ts, " ") - log.Debug("i1:", i1, "i2:", i2, "tn:", tn) - return tn -} - -func GetTableName(sql string) string { - ls := strings.ToLower(sql) - - re := regexp.MustCompile(`from\s+(\S+)`) - matches := re.FindStringSubmatch(ls) - if len(matches) < 2 { - return "" - } - return matches[1] -} - -func IsQuerySQL(s string) bool { - ts := strings.Trim(strings.ToLower(s), " ") - return strings.Index(ts, "select") == 0 -} - -// xorm Get data from database -func ExtDatabaseExecSQL(w http.ResponseWriter, r *http.Request) { - log.Debug("ExtDatabaseExecSQL processing... ") - - // var err error - - // _, err = services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - //vars := mux.Vars(r) - //tblName := vars["objectTypeValue"] - var sql = GetUriSQLArray(r) - // select as must, todo ... - - ls := services.ExtGetUriPageLimitString(r) - - // data := make([]map[string]interface{}, 0) - // xormResponse := make([]map[string]interface{}, len(sql)) - var xormResponse XormResponse - data := make([]map[string]interface{}, 0) - for i, s := range sql { - log.Tracef("SQL[%d]: %s", i, sql[i]) - - //rows := make([]map[string]interface{}, 0) - mapRows := make(map[string]interface{}) - - if s != "" { - // err = XEngine.SQL(s).Find(&rows) - // if IsQuerySQL(s) == false { - // services.ResponseNotAcceptable406QuerySQLError(w) - // return - // } - - querySQL := s - if i == (len(sql) - 1) { - querySQL = querySQL + " " + ls - } - log.Debug("querySQL:", querySQL) - rows, err := db.RawDB("", querySQL, nil) - if err != nil { - log.Error("SQL failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - tableName := GetTableName(s) - log.Debugf("s:%s tableName:%s", s, tableName) - mapRows[tableName] = rows - data = append(data, mapRows) - log.Trace("data:", data) - } - i++ - } - xormResponse.Data = data - - services.ResponseWithJson(w, http.StatusOK, xormResponse) -} - -// xorm Get data from database -func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) { - log.Debug("ExtDatabaseGetData processing... ") - - var sql []string - // token, err := services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - pack := "dbrest" - vars := mux.Vars(r) - module := "" - dbname := vars["elementTypeValue"] - tbname := vars["objectTypeValue"] - - log.Debugf("method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", r.Method, module, dbname, tbname, pack) - - // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) - // if err != nil { - // log.Error("Failed to get permission:", err) - // services.ResponseForbidden403NotPermission(w) - // return - // } - // if !exist { - // log.Error("Not permission!") - // services.ResponseForbidden403NotPermission(w) - // return - // } - - sql = GetUriSQLArray(r) - // select as must, todo ... - if sql == nil { - wc := services.GetUriLocString(r) - if wc == "" { - sql = append(sql, fmt.Sprintf("select * from %s", tbname)) - } else { - sql = append(sql, fmt.Sprintf("select * from %s where %s", tbname, wc)) - } - } - - ls := services.ExtGetUriPageLimitString(r) - - // data := make([]map[string]interface{}, 0) - // xormResponse := make([]map[string]interface{}, len(sql)) - var xormResponse XormResponse - data := make([]map[string]interface{}, 0) - for i, s := range sql { - log.Tracef("SQL[%d]: %s", i, sql[i]) - - mapRows := make(map[string]interface{}) - - if s != "" { - // err = XEngine.SQL(s).Find(&rows) - if !IsQuerySQL(s) { - services.ResponseNotAcceptable406QuerySQLError(w) - return - } - - querySQL := s - if i == (len(sql) - 1) { - querySQL = querySQL + " " + ls - } - log.Debug("querySQL:", querySQL) - rows, err := db.RawDB("", querySQL, nil) - if err != nil { - log.Error("SQL failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - tableName := GetTableName(s) - log.Debugf("s:%s tableName:%s", s, tableName) - mapRows[tableName] = rows - data = append(data, mapRows) - log.Trace("data:", data) - } - i++ - } - xormResponse.Data = data - - services.ResponseWithJson(w, http.StatusOK, xormResponse) -} - -func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) { - log.Debug("ExtDatabaseInsertData processing... ") - - // token, err := services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - vars := mux.Vars(r) - module := "" - dbname := vars["elementTypeValue"] - tbname := vars["objectTypeValue"] - pack := "dbrest" - - log.Debugf("method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", r.Method, module, dbname, tbname, pack) - - // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) - // if err != nil { - // log.Error("Failed to get permission:", err) - // services.ResponseForbidden403NotPermission(w) - // return - // } - // if !exist { - // log.Error("permission deny!") - // services.ResponseForbidden403NotPermission(w) - // return - // } - - log.Debug("Request body:", string(body), "dataObject:", tbname) - insertData := make(map[string]interface{}) - _ = json.Unmarshal(body, &insertData) - - tn, sql := dborm.ConstructInsertSQL(tbname, insertData) - log.Tracef("tn: %s sql :%s", tn, sql) - - var affected int64 - for _, s := range sql { - n, err := db.ExecDB("", s, nil) - if err != nil { - log.Error("Insert failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - affected = affected + n - } - - // affected, err := InsertDataWithJson(insertData) - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tn] = row - // xormResponse.Data = mapRow - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) { - log.Debug("ExtDatabaseUpdateData processing... ") - - // token, err := services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - module := "" - dbname := vars["elementTypeValue"] - tbname := vars["objectTypeValue"] - pack := "dbrest" - - log.Debugf("method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", r.Method, module, dbname, tbname, pack) - - // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) - // if err != nil { - // log.Error("Failed to get permission:", err) - // services.ResponseForbidden403NotPermission(w) - // return - // } - // if !exist { - // log.Error("Not permission!") - // services.ResponseForbidden403NotPermission(w) - // return - // } - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - wc := services.GetUriLocString(r) - - log.Debug("Request body:", string(body), "Tablename:", tbname, "wc:", wc) - updateData := make(map[string]interface{}) - _ = json.Unmarshal(body, &updateData) - - tn, sql := dborm.ConstructUpdateSQL(tbname, updateData, wc) - log.Tracef("tn: %s sql :%s", tn, sql) - - var affected int64 - for _, s := range sql { - n, err := db.ExecDB("", s, nil) - if err != nil { - log.Error("Update failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - affected = affected + n - } - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tn] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -func ExtDatabaseDeleteData(w http.ResponseWriter, r *http.Request) { - log.Debug("ExtDatabaseDeleteData processing... ") - - // token, err := services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - module := "" - dbname := vars["elementTypeValue"] - tbname := vars["objectTypeValue"] - pack := "dbreset" - - log.Debugf("method:%s, module:%, dbname:%s, tbname:%s pack:%s", r.Method, module, dbname, tbname, pack) - - // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) - // if err != nil { - // log.Error("Failed to get permission:", err) - // services.ResponseForbidden403NotPermission(w) - // return - // } - // if !exist { - // log.Error("Not permission!") - // services.ResponseForbidden403NotPermission(w) - // return - // } - - wc := services.GetUriLocString(r) - - log.Debug("Table name:", tbname, "wc:", wc) - - sql := dborm.ConstructDeleteSQL(tbname, wc) - - affected, err := db.ExecDB("", sql, nil) - if err != nil { - log.Error("Update failed, err:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow["data"] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -// xorm Get data from database -func DatabaseGetData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseGetData processing... ") - - var sql []string - - // _, err = services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - tblName := vars["objectTypeValue"] - sql = GetUriSQLArray(r) - // select as must, todo ... - - if sql == nil { - wc := services.GetUriWhereString(r) - if wc == "" { - sql = append(sql, fmt.Sprintf("select * from %s", tblName)) - } else { - sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc)) - } - } - - ls := services.GetUriPageLimitString(r) - - // data := make([]map[string]interface{}, 0) - // xormResponse := make([]map[string]interface{}, len(sql)) - var xormResponse XormResponse - data := make([]map[string]interface{}, 0) - for i, s := range sql { - log.Tracef("SQL[%d]: %s", i, sql[i]) - - mapRows := make(map[string]interface{}) - - if s != "" { - // err = XEngine.SQL(s).Find(&rows) - if !IsQuerySQL(s) { - services.ResponseNotAcceptable406QuerySQLError(w) - return - } - - querySQL := s - if i == (len(sql) - 1) { - querySQL = querySQL + " " + ls - } - log.Debug("querySQL:", querySQL) - rows, err := db.RawDB("", querySQL, nil) - if err != nil { - log.Error("QueryInterface failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - tableName := GetTableName(s) - log.Debugf("s:%s tableName:%s", s, tableName) - mapRows[tableName] = rows - data = append(data, mapRows) - log.Trace("data:", data) - } - i++ - } - xormResponse.Data = data - - services.ResponseWithJson(w, http.StatusOK, xormResponse) -} - -func DatabaseInsertData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseInsertData processing... ") - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - vars := mux.Vars(r) - tableName := vars["objectTypeValue"] - log.Debug("Request body:", string(body), "tableName:", tableName) - insertData := make(map[string]interface{}) - _ = json.Unmarshal(body, &insertData) - - // 操作日志的IP - if tableName == "operation_log" || tableName == "security_log" { - ipAddr := strings.Split(r.RemoteAddr, ":")[0] - s := insertData["data"].([]any) - a := s[0].(map[string]any) - a["op_ip"] = ipAddr - } else if tableName == "mml_log" { - ipAddr := strings.Split(r.RemoteAddr, ":")[0] - s := insertData["data"].([]any) - a := s[0].(map[string]any) - a["ip"] = ipAddr - } - - tn, sql := dborm.ConstructInsertSQL(tableName, insertData) - log.Tracef("tn: %s sql :%s", tn, sql) - - var affected int64 - for _, s := range sql { - n, err := db.ExecDB("", s, nil) - if err != nil { - log.Error("Insert failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - affected = affected + n - } - - // affected, err := InsertDataWithJson(insertData) - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tn] = row - // xormResponse.Data = mapRow - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -func DatabaseUpdateData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseUpdateData processing... ") - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - vars := mux.Vars(r) - tblName := vars["objectTypeValue"] - wc := services.GetUriWhereString(r) - - log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc) - updateData := make(map[string]interface{}) - _ = json.Unmarshal(body, &updateData) - - tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc) - log.Tracef("tn: %s sql :%s", tn, sql) - - var affected int64 - for _, s := range sql { - n, err := db.ExecDB("", s, nil) - if err != nil { - log.Error("Update failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - affected = affected + n - } - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tn] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -func DatabaseDeleteData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseDeleteData processing... ") - - vars := mux.Vars(r) - tblName := vars["objectTypeValue"] - wc := services.GetUriWhereString(r) - - log.Debug("Table name:", tblName, "wc:", wc) - - sql := dborm.ConstructDeleteSQL(tblName, wc) - - affected, err := db.ExecDB("", sql, nil) - if err != nil { - log.Error("Update failed, err:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow["data"] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -// 连接用户实例 -func DbConnection(w http.ResponseWriter, r *http.Request) { - // 获取底层 SQL 数据库连接 - sqlDB, err := db.DB("").DB() - if err != nil { - services.ResponseErrorWithJson(w, 400, "无连接") - return - } - // 测试数据库连接 - err = sqlDB.Ping() - if err != nil { - services.ResponseErrorWithJson(w, 400, "无连接") - return - } - - // 查询实例 - result, err := db.RawDB("", "SHOW PROCESSLIST;", nil) - if err != nil { - services.ResponseErrorWithJson(w, 500, err.Error()) - } - filterData := []map[string]any{} - for _, r := range result { - if r["User"] != "system user" { - filterData = append(filterData, r) - } - } - // Sleep:连接处于空闲状态,没有执行任何操作。 - // Query:连接正在执行一个查询语句。 - // Execute:连接正在执行一个准备好的 SQL 语句。 - // Connect:连接正在建立但尚未完成。 - services.ResponseWithJson(w, 200, filterData) -} - -// 关闭数据库连接 -func DbStop(w http.ResponseWriter, r *http.Request) { - // 获取底层 SQL 数据库连接 - sqlDB, err := db.DB("").DB() - if err != nil { - services.ResponseErrorWithJson(w, 400, "无连接") - return - } - // 测试数据库连接 - err = sqlDB.Ping() - if err != nil { - services.ResponseErrorWithJson(w, 400, "无连接") - return - } - - // json 請求參數獲取 - var bodyArgs struct { - ID string `json:"ID" validate:"required"` - } - err = ctx.ShouldBindJSON(r, &bodyArgs) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - // 关闭 - rse, err := db.ExecDB("", "KILL ?;", []any{bodyArgs.ID}) - if err != nil { - services.ResponseErrorWithJson(w, 500, err.Error()) - return - } - services.ResponseWithJson(w, 200, rse) -} - -// xorm Get data from database -func TaskDatabaseGetData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseGetData processing... ") - - vars := mux.Vars(r) - tblName := vars["objectTypeValue"] - var sql = GetUriSQLArray(r) - // select as must, todo ... - - if sql == nil { - wc := services.GetUriWhereString(r) - if wc == "" { - sql = append(sql, fmt.Sprintf("select * from %s", tblName)) - } else { - sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc)) - } - } - - ls := services.GetUriPageLimitString(r) - - // data := make([]map[string]interface{}, 0) - // xormResponse := make([]map[string]interface{}, len(sql)) - var xormResponse XormResponse - data := make([]map[string]interface{}, 0) - for i, s := range sql { - log.Tracef("SQL[%d]: %s", i, sql[i]) - - mapRows := make(map[string]interface{}) - - if s != "" { - // err = XEngine.SQL(s).Find(&rows) - if !IsQuerySQL(s) { - services.ResponseNotAcceptable406QuerySQLError(w) - return - } - - querySQL := s - if i == (len(sql) - 1) { - querySQL = querySQL + " " + ls - } - log.Debug("querySQL:", querySQL) - rows, err := db.RawDB("", querySQL, nil) - if err != nil { - log.Error("SQL failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - tableName := GetTableName(s) - log.Debugf("s:%s tableName:%s", s, tableName) - mapRows[tableName] = rows - data = append(data, mapRows) - log.Trace("data:", data) - } - i++ - } - xormResponse.Data = data - - services.ResponseWithJson(w, http.StatusOK, xormResponse) -} - -func TaskDatabaseInsertData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseInsertData processing... ") - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - vars := mux.Vars(r) - tableName := vars["objectTypeValue"] - log.Debug("Request body:", string(body), "tableName:", tableName) - insertData := make(map[string]interface{}) - _ = json.Unmarshal(body, &insertData) - - tn, sql := dborm.ConstructInsertSQL(tableName, insertData) - log.Tracef("tn: %s sql :%s", tn, sql) - - var affected int64 - for _, s := range sql { - n, err := db.ExecDB("", s, nil) - if err != nil { - log.Error("Insert failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - affected = affected + n - } - - // affected, err := InsertDataWithJson(insertData) - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tn] = row - // xormResponse.Data = mapRow - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -func TaskDatabaseUpdateData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseUpdateData processing... ") - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - vars := mux.Vars(r) - tblName := vars["objectTypeValue"] - wc := services.GetUriWhereString(r) - - log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc) - updateData := make(map[string]interface{}) - _ = json.Unmarshal(body, &updateData) - - tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc) - log.Tracef("tn: %s sql :%s", tn, sql) - - var affected int64 - for _, s := range sql { - n, err := db.ExecDB("", s, nil) - if err != nil { - log.Error("Update failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - affected = affected + n - } - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tn] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} - -func TaskDatabaseDeleteData(w http.ResponseWriter, r *http.Request) { - log.Debug("DatabaseDeleteData processing... ") - - vars := mux.Vars(r) - tblName := vars["objectTypeValue"] - wc := services.GetUriWhereString(r) - - log.Debug("Table name:", tblName, "wc:", wc) - - sql := dborm.ConstructDeleteSQL(tblName, wc) - - affected, err := db.ExecDB("", sql, nil) - if err != nil { - log.Error("Update failed, err:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow["data"] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} diff --git a/features/event/event.go b/features/event/event.go deleted file mode 100644 index 5e3853f1..00000000 --- a/features/event/event.go +++ /dev/null @@ -1,248 +0,0 @@ -package event - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - "time" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/log" - "be.ems/lib/services" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/parse" - neService "be.ems/src/modules/network_element/service" - wsService "be.ems/src/modules/ws/service" - - "github.com/gin-gonic/gin" -) - -var ( - // 走Gin - UriUEEventAMF = "/upload-ue/v1/:eventType" - // 走Mux - UriUEEvent = config.DefaultUriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent" - CustomUriUEEvent = config.UriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent" -) - -// 旧AMF上报处理 -func PostUEEventFromAMF(c *gin.Context) { - log.Info("PostUEEventFromAMF processing... ") - eventType := c.Param("eventType") - if eventType == "" { - log.Error("eventType is empty") - services.ResponseNotFound404UriNotExist(c.Writer, c.Request) - return - } - var body map[string]any - if err := c.ShouldBindBodyWithJSON(&body); err != nil { - log.Error("Failed to Unmarshal ueEvent:", err) - services.ResponseInternalServerError500ProcessError(c.Writer, err) - return - } - - // 执行插入表 - type UEEvent struct { - ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state - EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 - } - timestamp := time.Now().UnixMilli() - data := UEEvent{ - NeType: "AMF", - NeName: "", - RmUID: "", - Timestamp: timestamp, - EventType: eventType, - EventJSONStr: "", - CreatedAt: timestamp, - } - - // 从eventJson中获取rmUID - if v, ok := body["rmUID"]; ok { - data.RmUID = fmt.Sprint(v) - } else { - data.RmUID = "4400HXAMF001" - } - if v, ok := body["neName"]; ok { - data.NeName = fmt.Sprint(v) - } else { - data.NeName = "AMF_001" - } - - // 是否存在网元 - neInfo := neService.NewNeInfo.FindByRmuid(data.RmUID) - if neInfo.NeType != "AMF" || neInfo.RmUID != data.RmUID { - services.ResponseInternalServerError500ProcessError(c.Writer, fmt.Errorf("network element does not exist")) - return - } - - // 统一格式 - eventJson := map[string]any{"cellID": 0, "gNBID": "", "imsi": "", "onlineNumber": 0, "result": "", "tacID": 0, "timestamp": 0, "time": 0, "type": eventType} - switch eventType { - case "auth-result": - // {"authCode":"200","authMessage":"成功","authTime":"2024-12-07 16:48:37","cellID":"3","gNBID":"1","imsi":"460002082100000","onlineNumber":1,"tacID":"81"} - if v, ok := body["imsi"]; ok { - eventJson["imsi"] = fmt.Sprint(v) - } - if v, ok := body["cellID"]; ok { - eventJson["cellID"] = fmt.Sprint(v) - } - if v, ok := body["gNBID"]; ok { - eventJson["gNBID"] = fmt.Sprint(v) - } - if v, ok := body["tacID"]; ok { - eventJson["tacID"] = fmt.Sprint(v) - } - if v, ok := body["onlineNumber"]; ok { - eventJson["onlineNumber"] = parse.Number(v) - } - if v, ok := body["authCode"]; ok { - eventJson["result"] = fmt.Sprint(v) - } - if v, ok := body["authTime"]; ok { - authTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) - eventJson["timestamp"] = authTime.Unix() - eventJson["time"] = fmt.Sprint(v) - } - case "detach": - // {"detachResult":0,"detachTime":"2024-12-07 18:00:47","imsi":"460002082100000"} - if v, ok := body["imsi"]; ok { - eventJson["imsi"] = fmt.Sprint(v) - } - if v, ok := body["detachResult"]; ok { - if fmt.Sprint(v) == "0" { - eventJson["result"] = "200" - } else { - eventJson["result"] = "500" - } - } - if v, ok := body["detachTime"]; ok { - detachTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) - eventJson["timestamp"] = detachTime.Unix() - eventJson["time"] = fmt.Sprint(v) - } - case "cm-state": - // {"changeTime":"2024-12-07 17:07:52","imsi":"460002082100000","onlineNumber":1,"status":2} - if v, ok := body["imsi"]; ok { - eventJson["imsi"] = fmt.Sprint(v) - } - if v, ok := body["onlineNumber"]; ok { - eventJson["onlineNumber"] = parse.Number(v) - } - if v, ok := body["status"]; ok { - eventJson["result"] = fmt.Sprint(v) - } - if v, ok := body["changeTime"]; ok { - changeTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) - eventJson["timestamp"] = changeTime.Unix() - eventJson["time"] = fmt.Sprint(v) - } - } - - ueByte, err := json.Marshal(eventJson) - if err != nil { - services.ResponseInternalServerError500ProcessError(c.Writer, err) - return - } - data.EventJSONStr = string(ueByte) - - if err := db.DB("").Table("ue_event_amf").Create(&data).Error; err != nil { - log.Error("Failed to insert ue_event_amf", err) - services.ResponseInternalServerError500ProcessError(c.Writer, err) - return - } - - // 推送到ws订阅组 - if data.NeType == "AMF" { - wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, data) - wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE+"_"+neInfo.NeId, data) - } - - services.ResponseStatusOK204NoContent(c.Writer) -} - -// UE上报处理 -func PostUEEvent(w http.ResponseWriter, r *http.Request) { - log.Info("PostUEEvent processing... ") - neType := ctx.GetParam(r, "elementTypeValue") - var body struct { - NeType string `json:"neType" ` - NeName string `json:"neName" ` - RmUID string `json:"rmUID" ` - Timestamp int64 `json:"timestamp" ` - EventType string `json:"eventType" ` - EventJson map[string]any `json:"eventJSON" ` - } - if err := ctx.ShouldBindJSON(r, &body); err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - neTypeLower := strings.ToLower(body.NeType) - if neType == "" || neType != neTypeLower { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("inconsistent network element types")) - return - } - - // 是否存在网元 - neInfo := neService.NewNeInfo.FindByRmuid(body.RmUID) - if neInfo.NeType != body.NeType || neInfo.RmUID != body.RmUID { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("network element does not exist")) - return - } - - ueByte, err := json.Marshal(body.EventJson) - if err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 执行插入表 - type UEEvent struct { - ID string `json:"-" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state - EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String - CreatedAt int64 `json:"-" gorm:"column:created_at"` // 记录创建存储毫秒 - } - data := UEEvent{ - NeType: body.NeType, - NeName: body.NeName, - RmUID: body.RmUID, - Timestamp: int64(body.Timestamp) * 1000, - EventType: body.EventType, - EventJSONStr: string(ueByte), - CreatedAt: time.Now().UnixMilli(), - } - tableName := fmt.Sprintf("ue_event_%s", neTypeLower) - if err := db.DB("").Table(tableName).Create(&data).Error; err != nil { - log.Error("Failed to insert "+tableName, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - // 推送到ws订阅组 - if body.NeType == "MME" { - wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE, data) - wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE+"_"+neInfo.NeId, data) - } - if body.NeType == "AMF" { - wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, data) - wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE+"_"+neInfo.NeId, data) - } - - services.ResponseStatusOK204NoContent(w) -} diff --git a/features/features.go b/features/features.go deleted file mode 100644 index e4f68c75..00000000 --- a/features/features.go +++ /dev/null @@ -1,22 +0,0 @@ -package features - -import ( - "be.ems/features/cm" - "be.ems/features/lm" - "be.ems/features/nbi" - "be.ems/features/pm" - "be.ems/lib/log" - "github.com/gin-gonic/gin" -) - -func InitServiceEngine(r *gin.Engine) { - log.Info("======init feature group gin.Engine") - - // featuresGroup := r.Group("/") - // register features routers - pm.InitSubServiceRoute(r) - lm.InitSubServiceRoute(r) - cm.InitSubServiceRoute(r) - nbi.InitSubServiceRoute(r) - // return featuresGroup -} diff --git a/features/file/file.go b/features/file/file.go deleted file mode 100644 index bdd971f8..00000000 --- a/features/file/file.go +++ /dev/null @@ -1,141 +0,0 @@ -package file - -import ( - "net/http" - "path/filepath" - - "be.ems/lib/config" - "be.ems/lib/log" - "be.ems/lib/services" - "github.com/gorilla/mux" -) - -var ( - // parameter config management - UriFile = config.DefaultUriPrefix + "/fileManagement/{apiVersion}/{location}/file" - CustomUriFile = config.UriPrefix + "/fileManagement/{apiVersion}/{location}/file" -) - -// func init() { -// routes.Register("POST", UriFile, UploadFile, nil) -// routes.Register("GET", UriFile, DownloadFile, nil) -// routes.Register("DELETE", UriFile, DeleteFile, nil) -// } - -func UploadFile(w http.ResponseWriter, r *http.Request) { - log.Debug("UploadFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - vars := mux.Vars(r) - location := vars["location"] - if location == "" { - log.Error("location is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - params := r.URL.Query() - rename, ok := params["rename"] - if !ok { - log.Info("rename parameter is not exist") - } - log.Debug("rename:", rename) - - var path, fileName string - if len(rename) > 0 { - fileName = rename[0] - } - if location == "upload" { - path = config.GetYamlConfig().OMC.Upload - fileNamePath, err := services.HandleUploadFile(r, path, fileName) - if err != nil { - log.Error("Faile to HandleUploadFile:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - fileName = fileNamePath - } else { - path = config.GetYamlConfig().OMC.FrontUpload - fileNamePath, err := services.HandleUploadFile(r, path, fileName) - if err != nil { - log.Error("Faile to HandleUploadFile:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - fileName = fileNamePath - } - log.Debugf("upload file=%s to path=%s", fileName, path) - - services.ResponseStatusOK204NoContent(w) - return -} - -func DownloadFile(w http.ResponseWriter, r *http.Request) { - log.Debug("DownloadFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - location := vars["location"] - if location == "" { - log.Error("location is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // 全路径文件下载 - filePath := r.URL.Query().Get("path") - if location == "path" && filePath != "" { - // 截取文件路径 - dir := filepath.Dir(filePath) - // 截取文件名 - fileName := filepath.Base(filePath) - services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, dir, "") - return - } - - params := r.URL.Query() - fileNames, ok := params["loc"] - if !ok { - log.Info("loc parameter is not exist") - } - var path string - if location == "upload" { - path = config.GetYamlConfig().OMC.Upload - } else { - path = config.GetYamlConfig().OMC.FrontUpload - } - for _, fileName := range fileNames { - services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, "") - } - return -} - -func DeleteFile(w http.ResponseWriter, r *http.Request) { - log.Debug("DeleteFile processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["neType"] - if neType == "" { - log.Error("neType is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - services.ResponseStatusOK204NoContent(w) - return -} diff --git a/features/fm/alarm.go b/features/fm/alarm.go deleted file mode 100644 index e5f624fe..00000000 --- a/features/fm/alarm.go +++ /dev/null @@ -1,567 +0,0 @@ -package fm - -import ( - "database/sql" - "encoding/json" - "fmt" - "net/http" - "strings" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - - "be.ems/src/framework/constants" - "be.ems/src/framework/resp" - "be.ems/src/framework/utils/date" - neDataModel "be.ems/src/modules/network_data/model" - neDataService "be.ems/src/modules/network_data/service" - neFetchlink "be.ems/src/modules/network_element/fetch_link" - neModel "be.ems/src/modules/network_element/model" - neService "be.ems/src/modules/network_element/service" - traceService "be.ems/src/modules/trace/service" - wsService "be.ems/src/modules/ws/service" -) - -const ( - AlarmStatusClear = 0 - AlarmStatusActive = 1 - AlarmStatusClearString = "0" - AlarmStatusActiveString = "1" -) - -const ( - ClearTypeUnclear = 0 - ClearTypeAutoClear = 1 - ClearTypeManualClear = 2 -) - -const ( - AckStateUnacked = 0 - AckStateAcked = 1 -) - -const ( - AlarmTypeCommunicationAlarm = 1 - AlarmTypeEquipmentAlarm = 2 - AlarmTypeProcessingFailure = 3 - AlarmTypeEnvironmentalAlarm = 4 - AlarmTypeQualityOfServiceAlarm = 5 -) - -const ( - AlarmPerceivedSeverityCritical = 1 - AlarmPerceivedSeverityMajor = 2 - AlarmPerceivedSeverityMinor = 3 - AlarmPerceivedSeverityWarning = 4 - AlarmPerceivedSeverityEvent = 5 -) - -const ( - AlarmSeqBeginNumber = 1 -) - -type Alarm struct { - AlarmSeq int `json:"alarmSeq"` - AlarmId string `json:"alarmId" xorm:"alarm_id"` - NeId string `json:"neId"` // 收到实际是rmUID - AlarmCode int `json:"alarmCode"` - AlarmTitle string `json:"alarmTitle"` - EventTime string `json:"eventTime"` - AlarmType string `json:"alarmType"` - OrigSeverity string `json:"origSeverity"` - PerceivedSeverity string `json:"perceivedSeverity"` - PVFlag string `json:"pvFlag" xorm:"pv_flag"` - NeName string `json:"neName"` - NeType string `json:"neType"` - ObjectUid string `json:"objectUid" xorm:"object_uid"` - ObjectName string `json:"objectName" xorm:"object_name"` - ObjectType string `json:"objectType" xorm:"object_type"` - LocationInfo string `json:"locationInfo"` - Province string `json:"province"` - AlarmStatus int `json:"alarmStatus"` - SpecificProblem string `json:"specificProblem"` - SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"` - AddInfo string `json:"addInfo"` - - AckState int `json:"ackState"` - AckTime sql.NullTime `json:"ackTime"` - AckUser string `json:"ackUser"` - ClearType int `json:"clearType"` // 0: Unclear, 1: Auto clear, 2: Manual clear - ClearTime sql.NullTime `json:"clearTime"` -} - -var ( - // alarm management - UriAlarms = config.DefaultUriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms" - UriAlarmsFmt = config.DefaultUriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms" - - CustomUriAlarms = config.UriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms" - CustomUriAlarmsFmt = config.UriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms" -) - -// PostAlarmFromNF 网元告警数据上报接收 -func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostAlarmFromNF processing... ") - apiVer := ctx.GetParam(r, "apiVersion") - if apiVer != global.ApiVersionV1 { - log.Error("Uri api version is invalid. apiVersion:", apiVer) - services.ResponseWithJson(w, 422, resp.CodeMsg(40422, "api version is invalid")) - return - } - - var body []Alarm - if err := ctx.ShouldBindJSON(r, &body); err != nil { - services.ResponseWithJson(w, 422, resp.ErrMsg(err.Error())) - return - } - - // service object - neService := neService.NewNeInfo - - for _, v := range body { - log.Debug("alarmData:", v) - - // 是否存在网元 neId实际是rmUID - neInfo := neService.FindByRmuid(v.NeId) - if neInfo.NeType != v.NeType { - msg := fmt.Sprintf("network element does not exist %s", v.NeId) - services.ResponseWithJson(w, 400, resp.ErrMsg(msg)) - return - } - - // 记录日志 - alarmSaveLog(neInfo, v) - - // 补充默认信息 - if v.LocationInfo == "" { - v.LocationInfo = fmt.Sprintf("Remote Host:%s", r.RemoteAddr) - } - if v.AddInfo == "" { - v.AddInfo = fmt.Sprintf("NeInfo:%s", v.NeType) - } - if v.ObjectUid == "" { - v.ObjectUid = neInfo.RmUID - } - if v.ObjectName == "" { - v.ObjectName = neInfo.NeName - } - if v.ObjectType == "" { - v.ObjectType = neInfo.NeType - } - - // 告警事件 - if v.OrigSeverity == "Event" || v.OrigSeverity == "5" { - if v.AlarmStatus == AlarmStatusClear { - // 进行清除 - clearAlarmEvent, err := alarmEventClear(neInfo, v) - if err != nil { - services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) - return - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM_EVENT, neInfo.NeType, neInfo.NeId) - wsService.NewWSSend.ByGroupID(groupID, clearAlarmEvent) - } - if v.AlarmStatus == AlarmStatusActive { - // 进行新增 - newAlarmEvent, err := alarmEventNew(neInfo, v) - if err != nil { - services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) - return - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM_EVENT, neInfo.NeType, neInfo.NeId) - wsService.NewWSSend.ByGroupID(groupID, newAlarmEvent) - } - continue - } - - if v.AlarmStatus == AlarmStatusClear { - // 进行清除 - clearAlarm, err := alarmClear(neInfo, v) - if err != nil { - services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) - return - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - wsService.NewWSSend.ByGroupID(groupID, clearAlarm) - } - if v.AlarmStatus == AlarmStatusActive { - // 进行新增 - newAlarm, err := alarmNew(neInfo, v) - if err != nil { - services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) - return - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - wsService.NewWSSend.ByGroupID(groupID, newAlarm) - } - - // for alarm forward 告警转发 - alarmForward(v) - } - - services.ResponseStatusOK204NoContent(w) -} - -// alarmTypeValue 映射值 -func alarmTypeValue(str string) string { - arr := []string{"CommunicationAlarm", "EquipmentAlarm", "ProcessingFailure", "EnvironmentalAlarm", "QualityOfServiceAlarm"} - for k, v := range arr { - if v == str { - return fmt.Sprint(k + 1) - } - } - return str -} - -// origSeverityValue 映射值 -func origSeverityValue(str string) string { - arr := []string{"Critical", "Major", "Minor", "Warning", "Event"} - for k, v := range arr { - if v == str { - return fmt.Sprint(k + 1) - } - } - return str -} - -// alarmClear 清除告警 -func alarmClear(neInfo neModel.NeInfo, v Alarm) (neDataModel.Alarm, error) { - alarmService := neDataService.NewAlarm - // 检查网元告警ID是否唯一 - alarmIdArr := alarmService.Find(neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: v.AlarmId, - }) - if len(alarmIdArr) != 1 { - return neDataModel.Alarm{}, fmt.Errorf("[%s %s] clear alarm not exists alarmId:%s", neInfo.NeType, neInfo.NeId, v.AlarmId) - } - - // 产生时间 - eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) - - alarm := neDataModel.Alarm{ - ID: alarmIdArr[0].ID, - NeType: neInfo.NeType, - NeId: neInfo.NeId, - NeName: neInfo.NeName, - Province: neInfo.Province, - PvFlag: neInfo.PvFlag, - AlarmSeq: alarmIdArr[0].AlarmSeq, // seq 告警序号 - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: int64(v.AlarmCode), - EventTime: eventTime.UnixMilli(), - AlarmType: alarmTypeValue(v.AlarmType), - OrigSeverity: origSeverityValue(v.OrigSeverity), - PerceivedSeverity: origSeverityValue(v.PerceivedSeverity), - ObjectUid: v.ObjectUid, - ObjectName: v.ObjectName, - ObjectType: v.ObjectType, - LocationInfo: v.LocationInfo, - AlarmStatus: fmt.Sprint(v.AlarmStatus), - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - - // 告警清除 - alarm.ClearType = ClearTypeAutoClear - alarm.ClearTime = eventTime.UnixMilli() - alarm.ClearUser = neInfo.NeName - rows := alarmService.Update(alarm) - if rows > 0 { - return alarm, nil - } - return neDataModel.Alarm{}, fmt.Errorf("[%s %s] clear alarm fail", neInfo.NeType, neInfo.NeId) -} - -// alarmNew 新增告警 -func alarmNew(neInfo neModel.NeInfo, v Alarm) (neDataModel.Alarm, error) { - alarmService := neDataService.NewAlarm - // 检查网元告警ID是否唯一 - alarmIdArr := alarmService.Find(neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: v.AlarmId, - }) - if len(alarmIdArr) > 0 { - return neDataModel.Alarm{}, fmt.Errorf("[%s %s] new alarm already exists alarmId:%s", neInfo.NeType, neInfo.NeId, v.AlarmId) - } - // seq 告警序号 - lastSeq := alarmService.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) - // 产生时间 - eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) - - alarm := neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - NeName: neInfo.NeName, - Province: neInfo.Province, - PvFlag: neInfo.PvFlag, - AlarmSeq: lastSeq + 1, - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: int64(v.AlarmCode), - EventTime: eventTime.UnixMilli(), - AlarmType: alarmTypeValue(v.AlarmType), - OrigSeverity: origSeverityValue(v.OrigSeverity), - PerceivedSeverity: origSeverityValue(v.PerceivedSeverity), - ObjectUid: v.ObjectUid, - ObjectName: v.ObjectName, - ObjectType: v.ObjectType, - LocationInfo: v.LocationInfo, - AlarmStatus: fmt.Sprint(v.AlarmStatus), - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - insertId := alarmService.Insert(alarm) - if insertId > 0 { - alarm.ID = insertId - return alarm, nil - } - return neDataModel.Alarm{}, fmt.Errorf("[%s %s] new alarm fail", neInfo.NeType, neInfo.NeId) -} - -// alarmSaveLog 保存告警日志 -func alarmSaveLog(neInfo neModel.NeInfo, v Alarm) int64 { - alarmLogService := neDataService.NewAlarmLog - eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) - alarmLog := neDataModel.AlarmLog{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmSeq: int64(v.AlarmSeq), - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: int64(v.AlarmCode), - AlarmStatus: fmt.Sprint(v.AlarmStatus), - AlarmType: alarmTypeValue(v.AlarmType), - OrigSeverity: origSeverityValue(v.OrigSeverity), - EventTime: eventTime.UnixMilli(), - } - return alarmLogService.Insert(alarmLog) -} - -// alarmForward 告警转发 -func alarmForward(v Alarm) { - if config.GetYamlConfig().Alarm.EmailForward.Enable { - if err := AlarmEmailForward(&v); err != nil { - log.Error("Failed to AlarmEmailForward:", err) - } - } - if config.GetYamlConfig().Alarm.SMSCForward.Enable { - if err := AlarmSMSForward(&v); err != nil { - log.Error("Failed to AlarmSMSForward:", err) - } - } -} - -// alarmEventClear 清除告警事件 -func alarmEventClear(neInfo neModel.NeInfo, v Alarm) (neDataModel.AlarmEvent, error) { - alarmEventService := neDataService.NewAlarmEvent - // 检查网元告警ID是否唯一 - alarmIdArr := alarmEventService.Find(neDataModel.AlarmEvent{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: v.AlarmId, - }) - if len(alarmIdArr) != 1 { - return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] clear alarm event not exists alarmId:%s", neInfo.NeType, neInfo.NeId, v.AlarmId) - } - - // 产生时间 - eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) - - alarmEvent := neDataModel.AlarmEvent{ - ID: alarmIdArr[0].ID, - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmSeq: alarmIdArr[0].AlarmSeq, // seq 告警序号 - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: int64(v.AlarmCode), - EventTime: eventTime.UnixMilli(), - ObjectUid: v.ObjectUid, - ObjectName: v.ObjectName, - ObjectType: v.ObjectType, - LocationInfo: v.LocationInfo, - AlarmStatus: fmt.Sprint(v.AlarmStatus), - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - - // 告警清除 - alarmEvent.ClearType = ClearTypeAutoClear - alarmEvent.ClearTime = eventTime.UnixMilli() - alarmEvent.ClearUser = neInfo.NeName - rows := alarmEventService.Update(alarmEvent) - if rows > 0 { - return alarmEvent, nil - } - return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] clear alarm event fail", neInfo.NeType, neInfo.NeId) -} - -// alarmEventNew 新增告警事件 -func alarmEventNew(neInfo neModel.NeInfo, v Alarm) (neDataModel.AlarmEvent, error) { - alarmEventService := neDataService.NewAlarmEvent - // 检查网元告警ID是否唯一 - alarmIdArr := alarmEventService.Find(neDataModel.AlarmEvent{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: v.AlarmId, - }) - if len(alarmIdArr) > 0 { - return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] new alarm event already exists alarmId:%s", neInfo.NeType, neInfo.NeId, v.AlarmId) - } - // seq 告警序号 - lastSeq := alarmEventService.FindAlarmEventSeqLast(neInfo.NeType, neInfo.NeId) - // 产生时间 - eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) - - alarmEvent := neDataModel.AlarmEvent{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmSeq: lastSeq + 1, - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: int64(v.AlarmCode), - EventTime: eventTime.UnixMilli(), - ObjectUid: v.ObjectUid, - ObjectName: v.ObjectName, - ObjectType: v.ObjectType, - LocationInfo: v.LocationInfo, - AlarmStatus: fmt.Sprint(v.AlarmStatus), - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - insertId := alarmEventService.Insert(alarmEvent) - if insertId > 0 { - alarmEvent.ID = insertId - // 网元重启后,清除活动告警 - if v.AlarmCode == constants.ALARM_EVENT_REBOOT { - alarmService := neDataService.NewAlarm - rows := alarmService.Find(neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmStatus: "1", - }) - for _, v := range rows { - alarmService.AlarmClearByIds([]int64{v.ID}, "system") - } - } - // 网元重启后,有跟踪任务的需要重新补发启动任务 - if v.AlarmCode == constants.ALARM_EVENT_REBOOT { - traceService.NewTraceTask.RunUnstopped(neInfo.NeType, neInfo.NeId) - } - return alarmEvent, nil - } - return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] new alarm event fail", neInfo.NeType, neInfo.NeId) -} - -// mapToAlarm 将 []map[string]any 转换为 []Alarm -func mapToAlarm(data []map[string]any) []Alarm { - var result []Alarm - - // 将 []map[string]any 序列化为 JSON 字符串 - jsonData, err := json.Marshal(data) - if err != nil { - log.Error("Error marshaling data:", err) - return result - } - - // 反序列化到结构体 - err = json.Unmarshal(jsonData, &result) - if err != nil { - log.Error("Error unmarshaling data:", err) - return result - } - return result -} - -// GetAlarmFromNF 告警历史数据,从网元获取 -func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetAlarmFromNF processing... ") - neType := ctx.GetParam(r, "elementTypeValue") - neTypeLower := strings.ToLower(neType) - - // Get alarms from OMC return 204 - if neTypeLower == strings.ToLower(config.GetYamlConfig().OMC.NeType) { - log.Infof("Return no content alarms from %s", neType) - services.ResponseWithJson(w, 200, resp.ErrMsg("omc alarms no content")) - return - } - - neInfos := neService.NewNeInfo.Find(neModel.NeInfo{}, false, false) - for _, neInfo := range neInfos { - data, err := neFetchlink.AlarmHistory(neInfo) - if err != nil { - log.Error("Failed to fetch alarm history:", err) - continue - } - if len(data) == 0 { - log.Infof("Not found sync alarms, neType=%s, neId=%s", neInfo.NeType, neInfo.NeId) - continue - } - - alarms := mapToAlarm(data) - for _, v := range alarms { - // 补充默认信息 - if v.LocationInfo == "" { - v.LocationInfo = fmt.Sprintf("Remote Host:%s", r.RemoteAddr) - } - if v.AddInfo == "" { - v.AddInfo = fmt.Sprintf("NeInfo:%s", v.NeType) - } - if v.ObjectUid == "" { - v.ObjectUid = neInfo.RmUID - } - if v.ObjectName == "" { - v.ObjectName = neInfo.NeName - } - if v.ObjectType == "" { - v.ObjectType = neInfo.NeType - } - - // 告警事件 - if v.OrigSeverity == "Event" || v.OrigSeverity == "5" { - if v.AlarmStatus == AlarmStatusClear { - // 进行清除 - if _, err := alarmEventClear(neInfo, v); err != nil { - log.Error("Failed to alarmEventClear:", err) - continue - } - } - if v.AlarmStatus == AlarmStatusActive { - // 进行新增 - if _, err := alarmEventNew(neInfo, v); err != nil { - log.Error("Failed to alarmEventNew:", err) - continue - } - } - continue - } - - if v.AlarmStatus == AlarmStatusClear { - // 进行清除 - if _, err := alarmClear(neInfo, v); err != nil { - log.Error("Failed to alarmClear:", err) - continue - } - } - if v.AlarmStatus == AlarmStatusActive { - // 进行新增 - if _, err := alarmNew(neInfo, v); err != nil { - log.Error("Failed to alarmNew:", err) - continue - } - } - } - } - services.ResponseWithJson(w, 200, resp.OkMsg("sync alarms success")) -} diff --git a/features/fm/email.go b/features/fm/email.go deleted file mode 100644 index eacca7d1..00000000 --- a/features/fm/email.go +++ /dev/null @@ -1,129 +0,0 @@ -package fm - -import ( - "crypto/tls" - "fmt" - "strings" - - "be.ems/lib/config" - neService "be.ems/src/modules/network_element/service" - systemService "be.ems/src/modules/system/service" - - "gopkg.in/gomail.v2" -) - -func AlarmEmailForward(alarmData *Alarm) error { - neInfo := neService.NewNeInfo.FindByRmuid(alarmData.NeId) - - alarmStatus := "Clear" - if alarmData.AlarmStatus == 1 { - alarmStatus = "Active" - } - severity := origSeverityValue(alarmData.OrigSeverity) - dictAlarmSeverity := systemService.NewSysDictData.FindByType("active_alarm_severity") - for _, v := range dictAlarmSeverity { - if v.DataValue == severity { - severity = v.DataLabel - } - } - subjectTitle := config.GetYamlConfig().Alarm.EmailForward.Title - if subjectTitle == "" { - subjectTitle = fmt.Sprintf("%s-%s-%s", alarmData.OrigSeverity, alarmData.NeName, alarmData.AlarmTitle) - } - message := fmt.Sprintf(` -

Alarm information

-

Sequence: %d

-

NE Name: %s

-

NE IP: %s

-

Title: %s

-

Severity: %s

-

Event Time: %s

-

Alarm Status: %s

-

Automatic sent by OMC, please do not reply!

- `, - alarmData.AlarmSeq, - alarmData.NeName, - neInfo.IP, - alarmData.AlarmTitle, - severity, - alarmData.EventTime, - alarmStatus, - ) - - // message := fmt.Sprintf(` - // Alarm information - - // Sequence: %d - // NE name: %s - // Title: %s - // Severity: %s - // Event Time: %s - - // Automatic send by OMC, don't reply! - // `, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime) - - // QQ 邮箱: - // SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25) - // 163 邮箱: - // SMTP 服务器地址:smtp.163.com(端口:25) - // host := "mail.agrandtech.com" - // port := 25 - // userName := "smtpext@agrandtech.com" - // password := "1000smtp@omc!" - - host := config.GetYamlConfig().Alarm.EmailForward.SMTP - port := int(config.GetYamlConfig().Alarm.EmailForward.Port) - userName := config.GetYamlConfig().Alarm.EmailForward.User - password := config.GetYamlConfig().Alarm.EmailForward.Password - - m := gomail.NewMessage() - m.SetHeader("From", userName) // 发件人 - //m.SetHeader("From", "alias"+"<"+"aliastest"+">") // 增加发件人别名 - - // emails, err := dborm.XormGetAlarmForward("Email") - // if err != nil { - // log.Error("Failed to XormGetAlarmForward:", err) - // return err - // } else if emails == nil || len(*emails) == 0 { - // err := errors.New("not found forward email list") - // log.Error(err) - // return err - // } - emails := strings.Split(config.GetYamlConfig().Alarm.EmailForward.EmailList, ",") - if len(emails) == 0 { - return fmt.Errorf("not found forward email list") - } - m.SetHeader("To", emails...) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 - //m.SetHeader("To", strings.Join(*emails, " ")) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 - //m.SetHeader("To", "zhangshuzhong@agrandtech.com", "simonzhangsz@outlook.com") // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 - //m.SetHeader("Cc", "******@qq.com") // 抄送,可以多个 - //m.SetHeader("Bcc", "******@qq.com") // 暗送,可以多个 - m.SetHeader("Subject", subjectTitle) // 邮件主题 - - // text/html 的意思是将文件的 content-type 设置为 text/html 的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。 - // 可以通过 text/html 处理文本格式进行特殊处理,如换行、缩进、加粗等等 - //m.SetBody("text/html", fmt.Sprintf(message, *alarm)) - m.SetBody("text/html", message) - - // text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理 - //m.SetBody("text/plain", message) - // m.Attach("test.sh") // 附件文件,可以是文件,照片,视频等等 - // m.Attach("lolcatVideo.mp4") // 视频 - // m.Attach("lolcat.jpg") // 照片 - - d := gomail.NewDialer( - host, - port, - userName, - password, - ) - // 关闭SSL协议认证 - d.TLSConfig = &tls.Config{InsecureSkipVerify: true} - if !config.GetYamlConfig().Alarm.EmailForward.TLSSkipVerify { - // 打开SSL协议认证 - d.TLSConfig = &tls.Config{InsecureSkipVerify: false} - } - - err := d.DialAndSend(m) - return writeLog(alarmData, config.GetYamlConfig().Alarm.EmailForward.EmailList, "EMAIL", err) -} diff --git a/features/fm/smsforward.go b/features/fm/smsforward.go deleted file mode 100644 index 642e0ed3..00000000 --- a/features/fm/smsforward.go +++ /dev/null @@ -1,271 +0,0 @@ -package fm - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "strings" - "time" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/log" - "be.ems/src/framework/utils/date" - neDataModel "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/linxGnu/gosmpp" - "github.com/linxGnu/gosmpp/data" - "github.com/linxGnu/gosmpp/pdu" -) - -func AlarmSMSForward(alarmData *Alarm) error { - switch config.GetYamlConfig().Alarm.SMProxy { - case "sms": - users, err := AlarmForwardBySMS(alarmData) - writeLog(alarmData, users, "SMS", err) - return err - case "smsc": - users, err := AlarmForwardBySMPP(alarmData) - writeLog(alarmData, users, "SMS", err) - return err - default: - users, err := AlarmForwardBySMPP(alarmData) - writeLog(alarmData, users, "SMS", err) - return err - } -} - -func AlarmForwardBySMS(alarmData *Alarm) (string, error) { - log.Info("AlarmForwardBySMS processing... ") - - SMSFforwardconfig := config.GetYamlConfig().Alarm.SMS - // 阿里云短信API的请求地址 - apiURL := SMSFforwardconfig.ApiURL - - // 阿里云短信API的AccessKey ID和AccessKey Secret - //accessKeyID := SMSFforwardconfig.AccessKeyID - accessKeySecret := SMSFforwardconfig.AccessKeySecret - - toUsers, err := dborm.XormGetAlarmForward("SMS") - if err != nil { - log.Error("Failed to XormGetAlarmForward:", err) - return "", err - } - if toUsers == nil { - err := errors.New("not found forward phone number") - log.Error(err) - return "", err - } - userList := strings.Join(*toUsers, ",") - if len(userList) == 0 { - err := errors.New("not found forward phone number") - log.Error(err) - return "", err - } - // 短信相关参数 - params := url.Values{} - params.Set("PhoneNumbers", userList) - params.Set("SignName", SMSFforwardconfig.SignName) - params.Set("TemplateCode", SMSFforwardconfig.TemplateCode) - params.Set("TemplateParam", `{"message":"alarm"}`) - - // 构建请求URL - reqURL := apiURL + "?Action=SendSms&" + params.Encode() - - // 创建HTTP请求 - req, err := http.NewRequest("GET", reqURL, nil) - if err != nil { - log.Error("Failed to create request:", err) - return userList, err - } - - // 添加请求头部 - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("Authorization", "APPCODE "+accessKeySecret) - - // 发送请求 - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - log.Error("Failed to send request:%v", err) - return userList, err - } - defer resp.Body.Close() - - // 解析响应 - switch resp.StatusCode { - case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated: - return userList, nil - default: - log.Error(fmt.Errorf("failed to send SMS: %s(Code=%d)", resp.Status, resp.StatusCode)) - return userList, err - } -} - -var smsForward = &(config.GetYamlConfig().Alarm.SMSCForward) - -func AlarmForwardBySMPP(alarmData *Alarm) (string, error) { - log.Info("AlarmForwardBySMPP processing... ") - - if smsForward == nil { - err := errors.New("smsForward configuration is nil") - log.Error(err) - return "", err - } - userList := smsForward.MobileList - if len(userList) == 0 { - err := errors.New("not found forward phone number") - log.Error(err) - return "", err - } - auth := gosmpp.Auth{ - SMSC: smsForward.SMSCAddr, - SystemID: smsForward.SystemID, - Password: smsForward.Password, - SystemType: smsForward.SystemType, - } - - trans, err := gosmpp.NewSession( - gosmpp.TXConnector(gosmpp.NonTLSDialer, auth), - gosmpp.Settings{ - ReadTimeout: 2 * time.Second, - - OnPDU: func(p pdu.PDU, _ bool) { - log.Debug("%+v", p) - }, - - OnSubmitError: func(_ pdu.PDU, err error) { - log.Error(err) - }, - - OnRebindingError: func(err error) { - log.Error(err) - }, - - OnClosed: func(state gosmpp.State) { - log.Error(state) - }, - }, -1) - if err != nil { - log.Error("Failed to create SMPP new session:", err) - return "", err - } - defer func() { - if err := trans.Close(); err != nil { - log.Error(err) - } - }() - - message := "Alarm Notification: " + alarmData.AlarmTitle + - " from " + alarmData.NeType + "_" + alarmData.NeId + - " at " + alarmData.EventTime - users := strings.Split(userList, ",") - for _, user := range users { - if user == "" { - continue - } - sm, err := newSubmitSM(user, message) - if err != nil { - log.Errorf("Failed to newSubmitSM %s short message: %v", user, err) - writeLog(alarmData, user, "SMS", err) - continue - } - if err = trans.Transceiver().Submit(sm); err != nil { - log.Errorf("Failed to Submit %s short message: %v", user, err) - writeLog(alarmData, user, "SMS", err) - continue - } - writeLog(alarmData, user, "SMS", nil) - } - - return userList, nil -} - -func writeLog(alarmData *Alarm, toUser, forwardBy string, err error) error { - var result string = fmt.Sprintf("%s Sent Successfully!", forwardBy) - if err != nil { - result = err.Error() - } - neInfo := neService.NewNeInfo.FindByRmuid(alarmData.NeId) - eventTime := date.ParseStrToDate(alarmData.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) - alarmForwardLog := neDataModel.AlarmForwardLog{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmSeq: int64(alarmData.AlarmSeq), - AlarmId: alarmData.AlarmId, - AlarmTitle: alarmData.AlarmTitle, - AlarmCode: int64(alarmData.AlarmCode), - AlarmStatus: fmt.Sprint(alarmData.AlarmStatus), - AlarmType: alarmTypeValue(alarmData.AlarmType), - OrigSeverity: origSeverityValue(alarmData.OrigSeverity), - EventTime: eventTime.UnixMilli(), - Type: forwardBy, - Target: toUser, - Result: result, - } - - // 记录日志 - insertId := neDataService.NewAlarmForwardLog.Insert(alarmForwardLog) - if insertId <= 0 { - return fmt.Errorf("failed to insert data") - } - return nil -} - -func newSubmitSM(phoneNumber string, message string) (*pdu.SubmitSM, error) { - // build up submitSM - srcAddr := pdu.NewAddress() - srcAddr.SetTon(5) - srcAddr.SetNpi(0) - err := srcAddr.SetAddress(smsForward.ServiceNumber) - if err != nil { - return nil, err - } - destAddr := pdu.NewAddress() - destAddr.SetTon(1) - destAddr.SetNpi(1) - err = destAddr.SetAddress(phoneNumber) - if err != nil { - return nil, err - } - submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM) - submitSM.SourceAddr = srcAddr - submitSM.DestAddr = destAddr - dataCoding := data.FromDataCoding(smsForward.DataCoding) - err = submitSM.Message.SetMessageWithEncoding(message, dataCoding) - if err != nil { - return nil, err - } - submitSM.ProtocolID = 0 - submitSM.RegisteredDelivery = 1 - submitSM.ReplaceIfPresentFlag = 0 - submitSM.EsmClass = 0 - - return submitSM, nil -} - -// const ( -// // Short message data coding type -// SMS_CODING_GSM7BIT byte = iota -// SMS_CODING_ASCII -// SMS_CODING_BINARY8BIT1 -// SMS_CODING_LATIN1 -// SMS_CODING_BINARY8BIT2 -// SMS_CODING_NODEF -// SMS_CODING_CYRILLIC -// SMS_CODING_HEBREW -// SMS_CODING_UCS2 -// ) - -// var codingMap = map[byte]data.Encoding{ -// SMS_CODING_GSM7BIT: data.GSM7BIT, -// SMS_CODING_ASCII: data.ASCII, -// SMS_CODING_BINARY8BIT1: data.BINARY8BIT1, -// SMS_CODING_LATIN1: data.LATIN1, -// SMS_CODING_BINARY8BIT2: data.BINARY8BIT2, -// SMS_CODING_CYRILLIC: data.CYRILLIC, -// SMS_CODING_HEBREW: data.HEBREW, -// SMS_CODING_UCS2: data.UCS2, -// } diff --git a/features/handle/handle.go b/features/handle/handle.go deleted file mode 100644 index daeaf726..00000000 --- a/features/handle/handle.go +++ /dev/null @@ -1,565 +0,0 @@ -package handle - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "strconv" - "strings" - - "github.com/gorilla/mux" - g "github.com/gosnmp/gosnmp" - - "be.ems/lib/config" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/oauth" - "be.ems/lib/services" - "be.ems/lib/session" -) - -var TodoList []stTodo - -type stTodo struct { - No string - Item string - Value string -} - -type ErrorOAuthResponse struct { - Error map[string]interface{} -} - -type FailOAuthResponse struct { - Error struct { - ErrorCode string - ErrorInfo string - } -} - -type ApiResponse struct { - ResultCode string - ResultMessage interface{} -} - -var globalSession = session.NewSessManager("restagent") - -func init() { - conf := config.GetYamlConfig() - // Default is a pointer to a GoSNMP struct that contains sensible defaults - // eg port 161, community public, etc - g.Default.Target = conf.NE.Addr - g.Default.Port = conf.NE.Port - err := g.Default.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - //defer g.Default.Conn.Close() -} - -/* -func IsValidOAuthInfo(oAuthBody OAuthBody) bool { - log.Debug("IsValidOAuthInfo processing... ") - - conf := config.GetYamlConfig() - for _, o := range conf.Auth { - if oAuthBody.GrantType == o.Type && oAuthBody.UserName == o.User && oAuthBody.Value == o.Password { - return true - } - } - - return false -} - -func IsWrongOAuthInfo(oAuthBody OAuthBody) bool { - log.Debug("IsWrongOAuthInfo processing... ") - - if oAuthBody.GrantType == "" || strings.ToLower(oAuthBody.GrantType) != "password" || oAuthBody.UserName == "" || oAuthBody.Value == "" { - return true - } - - return false -} -*/ - -func IsValidOAuthUri(r *http.Request) bool { - vars := mux.Vars(r) - Uri := vars["apiCategory"] + "/" + vars["apiVersion"] // 获取Uri - return Uri == "securityManagement/v1" -} - -func IsVallidContentType(r *http.Request) bool { - log.Debug("IsVallidContentType processing ...") - - ctype := r.Header["Content-Type"] - if len(ctype) != 0 && !strings.Contains(ctype[0], "application/json") { - return false - } - - return true -} - -func LoginFromOMC(w http.ResponseWriter, r *http.Request) { - log.Debug("LoginFromOMC processing... ") - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Debug(err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // check media type(content type) only support "application/json" - /* if !IsVallidContentType(r) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // check extend uri, response 404 - if !IsValidOAuthUri(r) { - log.Debug("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - */ - // Error process .... - // response 400-7 - if !json.Valid([]byte(body)) { - log.Debug("Invalid Json Format") - services.ResponseBadRequest400InvalidJson(w) - return - } - - var oAuthBody oauth.OAuthBody - _ = json.Unmarshal(body, &oAuthBody) //转为json - log.Debug("body:", string(body), "oAuthBody:", oAuthBody) - - defer r.Body.Close() - // response 400-5 - if oauth.IsWrongOAuthInfo(oAuthBody) { - log.Debug("Wrong parameter value") - services.ResponseBadRequest400WrongParamValue(w) - return - } - /* - if oauth.IsValidOAuthInfo(oAuthBody) { - plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType) - log.Debug("Permission list:", plist) - - token := globalSession.NewSession(w, r, plist) - services.ResponseStatusOK200Login(w, token) - } else { - // response 400-4 - log.Debug("Authentication failed, mismatch user or password") - - services.ResponseBadRequest400IncorrectLogin(w) - } - */ - // response 400-4 - log.Error("Authentication failed, mismatch user or password") - - services.ResponseBadRequest400IncorrectLogin(w) -} - -func LogoutFromOMC(w http.ResponseWriter, r *http.Request) { - - // check media type(content type) only support "application/json" - if !IsVallidContentType(r) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // check extend uri, response 404 - if !IsValidOAuthUri(r) { - log.Debug("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // error processing ... - // 401-1 response - token, ret := globalSession.IsCarriedToken(r) - if ret { - log.Debug("AccessToken is not carried") - services.ResponseUnauthorized401AccessTokenNotCarried(w) - return - } - - // 401-2 response - if globalSession.IsValidToken(token) { - log.Debug("AccessToken fails or does not exist") - services.ResponseUnauthorized401AccessTokenNotExist(w) - return - } - - globalSession.EndSession(w, r) - services.ResponseStatusOK200Null(w) -} - -func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) { - log.Debug("HandshakeFromOMC processing... ") - - // check media type(content type) only support "application/json" - if !IsVallidContentType(r) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // check extend uri, response 404 - if !IsValidOAuthUri(r) { - log.Debug("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // error processing ... - // 401-1 response - token, ret := globalSession.IsCarriedToken(r) - if !ret { - log.Debug("AccessToken is not carried") - services.ResponseUnauthorized401AccessTokenNotCarried(w) - return - } - - if !globalSession.ShakeSession(token) { - // 401-2 response - log.Debug("AccessToken fails or does not exist") - services.ResponseUnauthorized401AccessTokenNotExist(w) - return - } - - // 200 response - services.ResponseStatusOK200Null(w) -} - -var ( - MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig() - MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig() - MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig() - MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig() - MAX_URI_LEN = config.GetUriMaxLenFromConfig() - RMUID_REGEXP = config.GetRmUIDRegexpFromConfig() -) - -func CheckParameterName(r *http.Request) []string { - var errorParams []string - vars := r.URL.Query() - for k, v := range vars { - log.Debug("vars:", k, v) - if k != "rmUIDs" && k != "fields" { - errorParams = append(errorParams, k) - } - } - - return errorParams -} - -func GetRmUIDArr(r *http.Request) []string { - vars := r.URL.Query() - rmUIDs, ok := vars["rmUIDs"] - if !ok { - log.Debug("rmUIDs is not exist") - return nil - } - - var rmUIDValues []string - for _, r := range rmUIDs { - if r != "" { - rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`)) - } - } - - return rmUIDValues -} - -func GetAttrNameArr(r *http.Request) []string { - vars := r.URL.Query() - fields, ok := vars["fields"] - if !ok { - log.Debug("attributeNames does not exist") - return nil - } - var attrNames []string - for _, a := range fields { - if a != "" { - attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`)) - } - } - - return attrNames -} - -func CheckValidRmUID(rmUIDs []string) []string { - log.Debug("GetLocalRmUID processing... ") - - var invalidRmUIDs []string - for _, r := range rmUIDs { - if !global.MatchRmUID(RMUID_REGEXP, r) { - invalidRmUIDs = append(invalidRmUIDs, r) - } - } - - return invalidRmUIDs -} - -func CheckLocalRmUID(rmUIDs []string) string { - log.Debug("GetLocalRmUID processing... ") - - rmUID := config.GetRmUIDFromConfig() - for _, r := range rmUIDs { - if r == rmUID { - return rmUID - } - } - - return "" -} - -func GetNRMByUri(w http.ResponseWriter, r *http.Request) { - log.Debug("GetNRMByUri processing... ") - - // response 414-4 uri too long ? (optional) - // todo ... ? - if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN { - log.Debug("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil)) - services.ResponseRequestURITooLong414UriTooLong(w) - return - } - - // check media type(content type) only support "application/json" - // response 415-1 - if !IsVallidContentType(r) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // error processing ... - // 401-1 response - token, ret := globalSession.IsCarriedToken(r) - if !ret { - log.Debug("AccessToken is not carried") - services.ResponseUnauthorized401AccessTokenNotCarried(w) - return - } - - // 401-2 response - if globalSession.IsValidToken(token) { - log.Debug("AccessToken fails or does not exist") - services.ResponseUnauthorized401AccessTokenNotExist(w) - return - } - // response 403 Forbidden, permissions deny - // todo... - plist := globalSession.GetPermissionFromSession(token) - log.Debug("permission list:", plist) - if len(plist) == 0 || !plist[0] { - log.Debug("User permission deny") - services.ResponseForbidden403NotPermission(w) - return - } - - vars := mux.Vars(r) - qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"] - log.Debug("Get by Uri: ", qeuryUri) - - apiVer := vars["apiVersion"] - if apiVer != "v1" { - log.Debug("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // response 406-1 - rmUIDValues := GetRmUIDArr(r) - if rmUIDValues == nil { - log.Debug("missing parameter: rmUIDs") - services.ResponseNotAcceptable406MissingParam(w) - return - } - - // response 406-2 - errorParams := CheckParameterName(r) - if errorParams != nil { - log.Debug("parameter name error: ", errorParams) - services.ResponseNotAcceptable406ParamError(w, errorParams) - return - } - - // response 400-5 - if len(rmUIDValues) == 0 { - log.Debug("rmUIDs is wrong or NULL") - services.ResponseBadRequest400WrongParamValue(w) - return - } - - // response 414-1 - if len(rmUIDValues) > MAX_RMUID_NUM { - log.Debug("rmUID greater than", MAX_RMUID_NUM) - services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM) - return - } - - // response 400-1 - // check rmUID is valid - // todo ... - invalidRmUIDs := CheckValidRmUID(rmUIDValues) - if len(invalidRmUIDs) != 0 { - log.Debug("rmUID is invalid") - services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs) - return - } - - // response 404-2 - rmUID := CheckLocalRmUID(rmUIDValues) - if rmUID == "" { - log.Debug("rmUID does not exist") - services.ResponseNotFound404NRMNotExist(w, rmUIDValues) - return - } - - // response 404-1, uri is not exist in map - attrNames := GetAttrNameArr(r) - var Oids []string - Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids) - if len(Oids) == 0 { - log.Debug("Nothing of config map") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // response 404-1, uri is not exist in map - var nameOids []config.NameOid - nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids) - if len(nameOids) == 0 { - log.Debug("Nothing of config map") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS - if err2 != nil { - log.Fatalf("Get() err: %v", err2) - - } - - // var nameValues []config.NameValue - var nameValue config.NameValue - - nameValues := make(map[string]interface{}) - nameValues["rmUID"] = rmUID - for i, variable := range result.Variables { - nameValue.Name = nameOids[i].Name - log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name) - // if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) { - if nameOids[i].Oid == variable.Name { - // the Value of each variable returned by Get() implements - // interface{}. You could do a type switch... - switch variable.Type { - case g.OctetString: - bytes := variable.Value.([]byte) - log.Debugf("string: %s\n", string(bytes)) - nameValue.Value = string(bytes) - nameValues[nameValue.Name] = nameValue.Value - case g.Integer: - value := variable.Value.(int) - log.Debugf("integer: %d\n", value) - nameValue.Value = strconv.Itoa(value) - nameValues[nameValue.Name] = nameValue.Value - case g.IPAddress: - value := variable.Value.(string) - log.Debugf("IPAddress: %s\n", variable.Value) - nameValue.Value = value - nameValues[nameValue.Name] = nameValue.Value - default: - // ... or often you're just interested in numeric values. - // ToBigInt() will return the Value as a BigInt, for plugging - // into your calculations. - log.Debugf("number: %d\n", g.ToBigInt(variable.Value)) - } - } - } - - getResponse := services.DataResponse{Data: nameValues} - services.ResponseWithJson(w, http.StatusOK, getResponse) -} - -func RestfulPut(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - queryNo := vars["no"] - var targetTodo stTodo - for _, Todo := range TodoList { - if Todo.No == queryNo { - targetTodo = Todo - } - } - response := ApiResponse{"200", targetTodo} - services.ResponseWithJson(w, http.StatusOK, response) -} - -func RestfulHead(w http.ResponseWriter, r *http.Request) { - var targetTodo stTodo - - response := ApiResponse{"200", targetTodo} - services.ResponseWithJson(w, http.StatusOK, response) - -} - -func RemoveElement(TodoList []stTodo, No string) stTodo { - // var targetTodo stTodo - j := 0 - if len(TodoList) == 0 { - return TodoList[j] - } - - for i := 0; i < len(TodoList); i++ { - if TodoList[i].No != No { - if i != j { - TodoList[i], TodoList[j] = TodoList[j], TodoList[i] - } - j++ - } - } - log.Debug(TodoList[j].No, TodoList[j].Item) - return TodoList[j] -} - -func RestfulDelete(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - queryNo := vars["no"] //获取No - - log.Debug("RestfulDelete processing... ") - - targetTodo := RemoveElement(TodoList, queryNo) - response := ApiResponse{"200", targetTodo} - services.ResponseWithJson(w, http.StatusOK, response) -} - -func RestfulOptions(w http.ResponseWriter, r *http.Request) { - var targetTodo stTodo - - response := ApiResponse{"200", targetTodo} - services.ResponseWithJson(w, http.StatusOK, response) - -} - -func RestfulTrace(w http.ResponseWriter, r *http.Request) { - var targetTodo stTodo - - response := ApiResponse{"200", targetTodo} - services.ResponseWithJson(w, http.StatusOK, response) - -} - -func RestfulPatch(w http.ResponseWriter, r *http.Request) { - var targetTodo stTodo - - response := ApiResponse{"200", targetTodo} - services.ResponseWithJson(w, http.StatusOK, response) - -} diff --git a/features/lm/file_export/controller.go b/features/lm/file_export/controller.go deleted file mode 100644 index 54eeed7c..00000000 --- a/features/lm/file_export/controller.go +++ /dev/null @@ -1,138 +0,0 @@ -package file_export - -import ( - "encoding/json" - "net/http" - "os" - "path/filepath" - - "be.ems/lib/file" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/database/db" - "be.ems/src/framework/i18n" - "be.ems/src/framework/reqctx" - "github.com/gin-gonic/gin" -) - -type SysJobResponse struct { - SysJob - TableName string `json:"tableName"` - TableDisplay string `json:"tableDisplay"` - FilePath string `json:"filePath"` -} - -type TargetParams struct { - Hour int `json:"hour"` // hour - TableName string `json:"tableName"` - Columns []string `json:"columns"` - FilePath string `json:"filePath"` // file path -} - -func (m *SysJob) GetFileExportTable(c *gin.Context) { - var results []SysJob - - tx := db.DB("").Table("sys_job").Where("invoke_target=?", INVOKE_FILE_EXPORT) - if err := tx.Find(&results).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - language := reqctx.AcceptLanguage(c) - var response []SysJobResponse - for _, job := range results { - var params TargetParams - if err := json.Unmarshal([]byte(job.TargetParams), ¶ms); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - TableDisplay := i18n.TKey(language, "table."+params.TableName) - if TableDisplay == "" { - TableDisplay = params.TableName - } - response = append(response, SysJobResponse{ - SysJob: job, - TableName: params.TableName, - TableDisplay: TableDisplay, - FilePath: params.FilePath, - }) - } - c.JSON(http.StatusOK, services.DataResp(response)) -} - -func (m *FileExport) GetFileList(c *gin.Context) { - var querys FileExportQuery - - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - files, err := file.GetFileInfo(querys.Path, querys.Suffix) - if err != nil { - log.Error("failed to GetFileInfo:", err) - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // split files list - lenNum := int64(len(files)) - start := (querys.PageNum - 1) * querys.PageSize - end := start + querys.PageSize - var splitList []file.FileInfo - if start >= lenNum { - splitList = []file.FileInfo{} - } else if end >= lenNum { - splitList = files[start:] - } else { - splitList = files[start:end] - } - total := len(files) - c.JSON(http.StatusOK, services.TotalDataResp(splitList, total)) -} - -func (m *FileExport) Total(c *gin.Context) { - dir := c.Query("path") - - fileCount, dirCount, err := file.GetFileAndDirCount(dir) - if err != nil { - log.Error("failed to GetFileAndDirCount:", err) - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - total := fileCount + dirCount - c.JSON(http.StatusOK, services.TotalResp(int64(total))) -} - -func (m *FileExport) DownloadHandler(c *gin.Context) { - dir := c.Query("path") - fileName := c.Param("fileName") - filePath := filepath.Join(dir, fileName) - - file, err := os.Open(filePath) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - defer file.Close() - - if _, err := os.Stat(filePath); os.IsNotExist(err) { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - c.Header("Content-Disposition", "attachment; filename="+fileName) - c.Header("Content-Type", "application/octet-stream") - c.File(filePath) -} - -func (m *FileExport) Delete(c *gin.Context) { - fileName := c.Param("fileName") - dir := c.Query("path") - filePath := filepath.Join(dir, fileName) - - if err := os.Remove(filePath); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - c.JSON(http.StatusNoContent, nil) // 204 No Content -} diff --git a/features/lm/file_export/model.go b/features/lm/file_export/model.go deleted file mode 100644 index 33a611f9..00000000 --- a/features/lm/file_export/model.go +++ /dev/null @@ -1,30 +0,0 @@ -package file_export - -import ( - "be.ems/lib/file" -) - -const ( - INVOKE_FILE_EXPORT = "exportTable" -) - -type SysJob struct { - JobID int64 `gorm:"column:job_id;primary_key;auto_increment" json:"job_id"` //任务ID - InvokeTarget string `gorm:"column:invoke_target" json:"invoke_target"` //调用目标字符串 - TargetParams string `gorm:"column:target_params;type:json" json:"target_params,omitempty"` //调用目标传入参数 -} - -func (m *SysJob) TableName() string { - return "sys_job" -} - -type FileExport struct { - file.FileInfo -} - -type FileExportQuery struct { - Path string `form:"path" binding:"required"` - Suffix string `form:"suffix"` - PageNum int64 `form:"pageNum" binding:"required"` - PageSize int64 `form:"pageSize" binding:"required"` -} diff --git a/features/lm/file_export/route.go b/features/lm/file_export/route.go deleted file mode 100644 index de9a05e6..00000000 --- a/features/lm/file_export/route.go +++ /dev/null @@ -1,39 +0,0 @@ -package file_export - -import ( - "be.ems/src/framework/middleware" - "github.com/gin-gonic/gin" -) - -// Register Routes for file_export -func Register(r *gin.RouterGroup) { - - lmTable := r.Group("/table") - { - var m *SysJob - lmTable.GET("/list", - middleware.AuthorizeUser(nil), - m.GetFileExportTable, - ) - } - lmFile := r.Group("/file") - { - var f *FileExport - lmFile.GET("/list", - middleware.AuthorizeUser(nil), - f.GetFileList, - ) - lmFile.GET("/total", - middleware.AuthorizeUser(nil), - f.Total, - ) - lmFile.GET("/:fileName", - middleware.AuthorizeUser(nil), - f.DownloadHandler, - ) - lmFile.DELETE("/:fileName", - middleware.AuthorizeUser(nil), - f.Delete, - ) - } -} diff --git a/features/lm/logbak.go b/features/lm/logbak.go deleted file mode 100644 index 99a36ae6..00000000 --- a/features/lm/logbak.go +++ /dev/null @@ -1,103 +0,0 @@ -package lm - -import ( - "fmt" - "net/http" - "os/exec" - "time" - - "be.ems/lib/config" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/database/db" - - "github.com/gorilla/mux" -) - -type XormResponse struct { - Data interface{} `json:"data"` -} - -type XormInsertResponse struct { - Data interface{} `json:"data"` -} - -var ( - ExtBackupDataUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}/backup" // for external - - CustomExtBackupDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}/backup" // for external -) - -// func init() { -// conf := config.GetYamlConfig() -// InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, -// conf.Database.Host, conf.Database.Port, conf.Database.Name) -// } - -func ExtDatabaseBackupData(w http.ResponseWriter, r *http.Request) { - log.Debug("ExtDatabaseBackupData processing... ") - - // token, err := services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - module := vars["managementModule"] - dbname := vars["dataStorage"] - tbname := vars["dataObject"] - pack := "lm" - log.Debugf("method:%s, module:%s dbname:%s, tbname:%s pack:%s", r.Method, module, dbname, tbname, pack) - // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) - // if err != nil { - // log.Error("Failed to get permission:", err) - // services.ResponseForbidden403NotPermission(w) - // return - // } - // if !exist { - // log.Error("permission deny!") - // services.ResponseForbidden403NotPermission(w) - // return - // } - - var sql string - var filePath string - switch tbname { - case "operation_log": - filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData)) - sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'op_id','account_name','op_ip','subsys_tag','op_type','op_content','op_result','begin_time','end_time','vnf_flag','log_time' union select op_id,account_name,op_ip,subsys_tag,op_type,op_content,op_result,begin_time,end_time,vnf_flag,log_time from operation_log) b", filePath) - case "security_log": - filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData)) - sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'id','account_name','account_type','op_ip','op_type','op_content','op_result','op_time' union select id,account_name,account_type,op_ip,op_type,op_content,op_result,op_time from security_log) b", filePath) - case "alarm_log": - filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData)) - sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'id','ne_type','ne_id','alarm_seq','alarm_id','alarm_code','alarm_status','event_time','log_time' union select id,ne_type,ne_id,alarm_seq,alarm_id,alarm_code,alarm_status,event_time,log_time from alarm_log) b", filePath) - default: - log.Error("error target table") - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - affected, err := db.ExecDB("", sql, nil) - if err != nil { - log.Error("Failed to exec SQL:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - log.Debugf("filePath:%s backup dir:%s", filePath, config.GetYamlConfig().OMC.Backup) - cmd := exec.Command("cp", "-rf", filePath, config.GetYamlConfig().OMC.Backup) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Error("Faile to exec:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - mapRow := make(map[string]interface{}) - row := map[string]interface{}{"affectedRows": affected} - mapRow[tbname] = row - services.ResponseWithJson(w, http.StatusOK, mapRow) -} diff --git a/features/lm/service.go b/features/lm/service.go deleted file mode 100644 index 5cdaa943..00000000 --- a/features/lm/service.go +++ /dev/null @@ -1,17 +0,0 @@ -// log management package - -package lm - -import ( - "be.ems/features/lm/file_export" - "be.ems/lib/log" - "github.com/gin-gonic/gin" -) - -func InitSubServiceRoute(r *gin.Engine) { - log.Info("======init Log management group gin.Engine") - - lmGroup := r.Group("/lm") - // register sub modules routes - file_export.Register(lmGroup) -} diff --git a/features/mml/mml.go b/features/mml/mml.go deleted file mode 100644 index 867c41e6..00000000 --- a/features/mml/mml.go +++ /dev/null @@ -1,705 +0,0 @@ -package mml - -import ( - "encoding/json" - "fmt" - "io" - "net" - "net/http" - "regexp" - "strings" - "time" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/mmlp" - "be.ems/lib/services" - "be.ems/src/framework/constants" - neModel "be.ems/src/modules/network_element/model" - neService "be.ems/src/modules/network_element/service" -) - -// const ( -// //经过测试,linux下,延时需要大于100ms -// TIME_DELAY_AFTER_WRITE = 200 -// TIME_DEAD_LINE = 10 -// ) - -type Response struct { - Data []string `json:"data"` -} - -type MMLRequest struct { - MML []string `json:"mml"` -} - -var ( - // MML interface - UriMML = config.DefaultUriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml" - UriMML2 = config.DefaultUriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml2" - UriMMLDiscard = config.DefaultUriPrefix + "/opeartionManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml" - UriNeOmMml = config.DefaultUriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}" - UriOmMmlExt = config.DefaultUriPrefix + "/{managedType}/{apiVersion}/elementType/OMC/objectType/mml" - UriOmMmlInt = config.DefaultUriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}" - - CustomUriMML = config.UriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml" - CustomUriMML2 = config.UriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml2" - CustomUriNeOmMml = config.UriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}" - CustomUriOmMmlExt = config.UriPrefix + "/opeartionManagement/{apiVersion}/elementType/OMC/objectType/mml" - CustomUriOmMmlInt = config.UriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}" -) - -var ( - TIME_DELAY_AFTER_WRITE time.Duration = 200 - TIME_DEAD_LINE time.Duration = 10 - WIN_ROW_SIZE int16 = 200 - WIN_COL_SIZE int16 = 120 - BUFFER_SIZE int = 65535 -) - -func InitMML() { - if config.GetYamlConfig().MML.Sleep != 0 { - TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep) - } - if config.GetYamlConfig().MML.DeadLine != 0 { - TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine) - } - WIN_ROW_SIZE = config.GetYamlConfig().MML.SizeRow - WIN_COL_SIZE = config.GetYamlConfig().MML.SizeCol - BUFFER_SIZE = config.GetYamlConfig().MML.BufferSize -} - -func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { - log.Info("PostMML2ToNF processing... ") - - neType := ctx.GetParam(r, "elementTypeValue") - neId := ctx.GetQuery(r, "ne_id") - if neId == "" { - log.Error("NOT FOUND ne_id") - services.ResponseBadRequest400WrongParamValue(w) - return - } - log.Debug("neType:", neType, "neId", neId) - - neInfoArr := neService.NewNeInfo.Find(neModel.NeInfo{NeType: neType, NeId: neId}, false, true) - if len(neInfoArr) < 1 { - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - neInfo := neInfoArr[0] - if neInfo.NeId != neId || neInfo.IP == "" || len(neInfo.Hosts) < 2 { - services.ResponseWithJson(w, 200, map[string]any{ - "code": 0, - "msg": "neInfo not found", - }) - return - } - telnetHost := neInfo.Hosts[1] - - buf := make([]byte, BUFFER_SIZE) - var n int - var mmlResult []string - hostMML := net.JoinHostPort(telnetHost.Addr, fmt.Sprintf("%d", telnetHost.Port)) - conn, err := net.Dial("tcp", hostMML) - if err != nil { - errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) - log.Error(errMsg) - mmlResult = append(mmlResult, errMsg) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - defer conn.Close() - - // localAddr := conn.LocalAddr() - // remoteAddr := conn.RemoteAddr() - // if localAddr == nil || remoteAddr == nil { - // errMsg := fmt.Sprintf("connect invalid: localAddr=%v, remoteAddr=%v", localAddr, remoteAddr) - // log.Error(errMsg) - // mmlResult = append(mmlResult, errMsg) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - - // 发送窗口大小设置命令 - conn.Write([]byte{255, 251, 31}) // 发送WILL WINDOW SIZE - conn.Write([]byte{ - 255, 250, 31, - byte(WIN_COL_SIZE >> 8), byte(WIN_COL_SIZE & 0xFF), - byte(WIN_ROW_SIZE >> 8), byte(WIN_ROW_SIZE & 0xFF), - 255, 240, - }) // 发送设置 WINDOW SIZE - - conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) - loginStr := fmt.Sprintf("%s\n%s\n", telnetHost.User, telnetHost.Password) - _, err = conn.Write([]byte(loginStr)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - log.Trace(string(buf[0:n])) - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Failed to ReadAll:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Trace("Body:", string(body)) - - mmlRequest := new(MMLRequest) - _ = json.Unmarshal(body, mmlRequest) - - for _, mml := range mmlRequest.MML { - mmlCommand := fmt.Sprintf("%s\n", mml) - _, err = conn.Write([]byte(mmlCommand)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - continue - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - continue - } - log.Trace(string(buf[0 : n-len(neType)-2])) - re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 - //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 - re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 - //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) - result := re1.ReplaceAllString(string(buf[0:n]), "") - result = re2.ReplaceAllString(result, "") - mmlResult = append(mmlResult, result) - } - - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) -} - -func PostMMLToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostMMLToNF processing... ") - - // token, err := services.CheckExtValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // 经过测试,linux下,延时需要大于100ms - // var TIME_DELAY_AFTER_WRITE time.Duration = 200 - // var TIME_DEAD_LINE time.Duration = 10 - // if config.GetYamlConfig().MML.Sleep != 0 { - // TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep) - // } - // if config.GetYamlConfig().MML.DeadLine != 0 { - // TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine) - // } - - neType := ctx.GetParam(r, "elementTypeValue") - neId := ctx.GetQuery(r, "ne_id") - if neId == "" { - log.Error("NOT FOUND ne_id") - services.ResponseBadRequest400WrongParamValue(w) - return - } - log.Debug("neType:", neType, "neId", neId) - - if strings.ToLower(neType) == "omc" { - PostMMLToOMC(w, r) - return - } - - neInfoArr := neService.NewNeInfo.Find(neModel.NeInfo{NeType: neType, NeId: neId}, false, true) - if len(neInfoArr) < 1 { - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - neInfo := neInfoArr[0] - if neInfo.NeId != neId || neInfo.IP == "" || len(neInfo.Hosts) < 2 { - services.ResponseWithJson(w, 200, map[string]any{ - "code": 0, - "msg": "neInfo not found", - }) - return - } - telnetHost := neInfo.Hosts[1] - - var buf [20 * 1024]byte - //buf := make([]byte, 0) - var n int - var mmlResult []string - switch strings.ToLower(neType) { - case "xxx": - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Trace("Body:", string(body)) - - mmlRequest := new(MMLRequest) - _ = json.Unmarshal(body, mmlRequest) - - // n, err = conn.Read(buf[0:]) - // if err != nil { - // log.Error("Failed to read:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // log.Debug(string(buf[0:n])) - - // hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port) - // conn, err := net.Dial("tcp", hostMML) - // if err != nil { - // errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) - // log.Error(errMsg) - // mmlResult = append(mmlResult, errMsg) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // defer conn.Close() - - // conn.SetDeadline(time.Now().Add(10 * time.Second)) - // loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) - // _, err = conn.Write([]byte(loginStr)) - // if err != nil { - // log.Error("Failed to write:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - // n, err = conn.Write([]byte(config.GetYamlConfig().MML.User + "\n")) - // if err != nil { - // log.Error("Failed to write:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // log.Debug(string(buf[0:n])) - // time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - // n, err = conn.Read(buf[0:]) - // if err != nil { - // log.Error("Failed to read:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // log.Debug(string(buf[0:n])) - - // n, err = conn.Write([]byte(config.GetYamlConfig().MML.Password + "\n")) - // if err != nil { - // log.Error("Failed to write:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // log.Debug(string(buf[0:n])) - - // time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - // n, err = conn.Read(buf[0:]) - // if err != nil { - // log.Error("Failed to read:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // log.Debug(string(buf[0:n])) - - for _, mml := range mmlRequest.MML { - hostMML := net.JoinHostPort(telnetHost.Addr, fmt.Sprintf("%d", telnetHost.Port)) - conn, err := net.Dial("tcp", hostMML) - if err != nil { - errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) - log.Error(errMsg) - mmlResult = append(mmlResult, errMsg) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - defer conn.Close() - - conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) - - loginStr := fmt.Sprintf("%s\n%s\n", telnetHost.User, telnetHost.Password) - _, err = conn.Write([]byte(loginStr)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - //response := Response{mmlResult} - //services.ResponseWithJson(w, http.StatusOK, response) - //return - continue - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - mmlCommand := fmt.Sprintf("%s\n", mml) - log.Debug("mml command:", mmlCommand) - _, err = conn.Write([]byte(mmlCommand)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - //response := Response{mmlResult} - //services.ResponseWithJson(w, http.StatusOK, response) - //return - continue - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - //response := Response{mmlResult} - //services.ResponseWithJson(w, http.StatusOK, response) - //return - continue - } - log.Trace(string(buf[0 : n-len(neType)-2])) - - re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 - //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 - re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 - //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) - // upf telnet buffer只能读取一次,需要去掉前面的多余字符 - //result := re1.ReplaceAllString(string(buf[config.GetYamlConfig().MML.UpfHeaderLength:n-len(neType)-2]), "") - result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") - result = re2.ReplaceAllString(result, "") - mmlResult = append(mmlResult, result) - conn.Close() - //mmlResult = append(mmlResult, string(buf[0:n-len(neType)-2])) - - // can't read buffer from upf telnet server, so return ok always - // mmlResult = append(mmlResult, "COMMAND OK\n") - } - case "ims": - hostMML := net.JoinHostPort(telnetHost.Addr, fmt.Sprintf("%d", telnetHost.Port)) - conn, err := net.Dial("tcp", hostMML) - if err != nil { - errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) - log.Error(errMsg) - mmlResult = append(mmlResult, errMsg) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - defer conn.Close() - - // localAddr := conn.LocalAddr() - // remoteAddr := conn.RemoteAddr() - // if localAddr == nil || remoteAddr == nil { - // errMsg := fmt.Sprintf("connect invalid: localAddr=%v, remoteAddr=%v", localAddr, remoteAddr) - // log.Error(errMsg) - // mmlResult = append(mmlResult, errMsg) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) - - _, err = conn.Write([]byte(telnetHost.User + "\r\n")) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - log.Trace(string(buf[0:n])) - - _, err = conn.Write([]byte(telnetHost.Password + "\r\n")) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - // loginStr := fmt.Sprintf("%s\r\n%s\r\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) - // _, err = conn.Write([]byte(loginStr)) - // if err != nil { - // log.Error("Failed to write:", err) - // mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - // time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - log.Trace(string(buf[0 : n-len(neType)-2])) - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Trace("Body:", string(body)) - - mmlRequest := new(MMLRequest) - _ = json.Unmarshal(body, mmlRequest) - - for _, mml := range mmlRequest.MML { - mmlCommand := fmt.Sprintf("%s\r\n", mml) - log.Debug("mml command:", mmlCommand) - _, err = conn.Write([]byte(mmlCommand)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - continue - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - continue - } - log.Trace(string(buf[0 : n-len(neType)-2])) - - re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 - //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 - re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 - //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) - result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") - result = re2.ReplaceAllString(result, "") - mmlResult = append(mmlResult, result) - } - default: - hostMML := net.JoinHostPort(telnetHost.Addr, fmt.Sprintf("%d", telnetHost.Port)) - conn, err := net.Dial("tcp", hostMML) - if err != nil { - errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) - log.Error(errMsg) - mmlResult = append(mmlResult, errMsg) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - defer conn.Close() - - // localAddr := conn.LocalAddr() - // remoteAddr := conn.RemoteAddr() - // if localAddr == nil || remoteAddr == nil { - // errMsg := fmt.Sprintf("connect invalid: localAddr=%v, remoteAddr=%v", localAddr, remoteAddr) - // log.Error(errMsg) - // mmlResult = append(mmlResult, errMsg) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - // } - - conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) - loginStr := fmt.Sprintf("%s\n%s\n", telnetHost.User, telnetHost.Password) - _, err = conn.Write([]byte(loginStr)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - log.Trace(string(buf[0:n])) - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Failed to ReadAll:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Trace("Body:", string(body)) - - mmlRequest := new(MMLRequest) - _ = json.Unmarshal(body, mmlRequest) - - for _, mml := range mmlRequest.MML { - mmlCommand := fmt.Sprintf("%s\n", mml) - _, err = conn.Write([]byte(mmlCommand)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - continue - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) - - n, err = conn.Read(buf[0:]) - if err != nil { - log.Error("Failed to read:", err) - mmlResult = append(mmlResult, err.Error()) - // response := Response{mmlResult} - // services.ResponseWithJson(w, http.StatusOK, response) - // return - continue - } - log.Trace(string(buf[0 : n-len(neType)-2])) - re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 - //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 - re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 - //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) - result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") - result = re2.ReplaceAllString(result, "") - mmlResult = append(mmlResult, result) - - // UDM 特殊命令处理 - if neType == "UDM" && mml == "dec key" { - output, err := neService.NewNeInfo.NeRunSSHCmd(neInfo.NeType, neInfo.NeId, "cat /usr/local/etc/udm/ueKeyProfile.tmp") - if err != nil { - mmlResult = append(mmlResult, err.Error()) - } else { - mmlResult = append(mmlResult, output) - } - } - } - } - - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) -} - -func PostMMLToOMC(w http.ResponseWriter, r *http.Request) { - log.Debug("PostMMLToOMC processing... ") - - neType := "OMC" //ctx.GetParam(r, "elementTypeValue") - neId := ctx.GetQuery(r, "ne_id") - if neId == "" { - log.Error("NOT FOUND ne_id") - services.ResponseBadRequest400WrongParamValue(w) - return - } - log.Debug("neType:", neType, "neId", neId) - - neInfoArr := neService.NewNeInfo.Find(neModel.NeInfo{NeType: neType, NeId: neId}, false, false) - if len(neInfoArr) < 1 { - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - neInfo := neInfoArr[0] - if neInfo.NeId != neId || neInfo.IP == "" { - services.ResponseWithJson(w, 200, map[string]any{ - "code": 0, - "msg": "neInfo not found", - }) - return - } - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Trace("Body:", string(body)) - - hostUri := fmt.Sprintf("http://%s:%d", neInfo.IP, neInfo.Port) - omcMmlVar := &mmlp.MmlVar{ - Version: global.Version, - Output: mmlp.DefaultFormatType, - MmlHome: config.GetYamlConfig().MML.MmlHome, - Limit: 50, - User: "", - SessionToken: "", // 旧token - Authorization: r.Header.Get(constants.HEADER_KEY), // 请求Token - HttpUri: hostUri, - UserAgent: config.GetDefaultUserAgent(), - } - mmlRequest := new(MMLRequest) - _ = json.Unmarshal(body, mmlRequest) - - var mmlResult []string - mmlLine := strings.Join(mmlRequest.MML, ";") - - var mmlCmds []mmlp.MmlCommand - if err = mmlp.ParseMMLCommand(mmlLine, &mmlCmds); err != nil { - response := fmt.Sprintf("parse command error: %v\n", err) - mmlResult = append(mmlResult, response) - } - - for _, mmlCmd := range mmlCmds { - output, err := mmlp.TransMml2HttpReq(omcMmlVar, &mmlCmd) - if err != nil { - response := fmt.Sprintf("translate MML command error: %v]\n", err) - mmlResult = append(mmlResult, response) - } - mmlResult = append(mmlResult, string(*output)) - } - - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) -} diff --git a/features/nbi/file/controller.go b/features/nbi/file/controller.go deleted file mode 100644 index cc5edc88..00000000 --- a/features/nbi/file/controller.go +++ /dev/null @@ -1,257 +0,0 @@ -package nbi_file - -import ( - "archive/zip" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "time" - - "be.ems/lib/dborm" - "be.ems/lib/file" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - "github.com/gin-gonic/gin" -) - -type SysJobResponse struct { - SysJob - TableName string `json:"tableName"` - TableDisplay string `json:"tableDisplay"` - FilePath string `json:"filePath"` -} - -type TargetParams struct { - Duration int `json:"duration"` - TableName string `json:"tableName"` - Columns string `json:"columns"` // exported column name of time string - TimeCol string `json:"timeCol"` // time stamp of column name - TimeUnit string `json:"timeUnit"` // timestamp unit: second/micro/milli - Extras string `json:"extras"` // extras condition for where - FilePath string `json:"filePath"` // file path -} - -func (m *FileNBI) GetFileList(c *gin.Context) { - var querys FileNBIQuery - - querys.Category = c.Param("category") - querys.Type = c.Param("type") - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - if querys.Path == "" { - tableName := "" - ok := false - switch querys.Category { - case "cdr": - tableName, ok = CDRTableMapper[querys.Type] - if tableName == "" || !ok { - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid CDR file type: %s", querys.Type))) - return - } - case "log": - tableName, ok = LogTableMapper[querys.Type] - if tableName == "" || !ok { - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid log file type: %s", querys.Type))) - return - } - default: - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid log file category: %s", querys.Category))) - return - } - - s := SysJob{} - where := fmt.Sprintf("invoke_target='%s' and status=1 and JSON_UNQUOTE(JSON_EXTRACT(target_params,'$.tableName'))='%s'", INVOKE_FILE_EXPORT, tableName) - _, err := dborm.XEngDB().Table(s.TableName()). - Select("JSON_UNQUOTE(JSON_EXTRACT(target_params, '$.filePath')) as file_path"). - Where(where). - Get(&querys.Path) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - } - - files, err := file.GetFileInfo(querys.Path, querys.Suffix) - if err != nil { - log.Error("failed to GetFileInfo:", err) - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // split files list - lenNum := int64(len(files)) - start := (querys.PageNum - 1) * querys.PageSize - end := start + querys.PageSize - var splitList []file.FileInfo - if start >= lenNum { - splitList = []file.FileInfo{} - } else if end >= lenNum { - splitList = files[start:] - } else { - splitList = files[start:end] - } - total := len(files) - c.JSON(http.StatusOK, services.TotalDataResp(splitList, total)) -} - -func (m *FileNBI) Total(c *gin.Context) { - dir := c.Query("path") - - fileCount, dirCount, err := file.GetFileAndDirCount(dir) - if err != nil { - log.Error("failed to GetFileAndDirCount:", err) - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - total := fileCount + dirCount - c.JSON(http.StatusOK, services.TotalResp(int64(total))) -} - -func (m *FileNBI) GetSingleFileHandler(c *gin.Context) { - var querys FileNBIQuery - - querys.Category = c.Param("category") - querys.Type = c.Param("type") - querys.DateIndex = c.Param("dateIndex") - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - tableName := "" - if querys.Path == "" { - ok := false - switch querys.Category { - case "cdr": - tableName, ok = CDRTableMapper[querys.Type] - if tableName == "" || !ok { - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid CDR file type: %s", querys.Type))) - return - } - case "log": - tableName, ok = LogTableMapper[querys.Type] - if tableName == "" || !ok { - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid log file type: %s", querys.Type))) - return - } - default: - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid log file category: %s", querys.Category))) - return - } - - s := SysJob{} - where := fmt.Sprintf("invoke_target='%s' and status=1 and JSON_UNQUOTE(JSON_EXTRACT(target_params,'$.tableName'))='%s'", INVOKE_FILE_EXPORT, tableName) - _, err := dborm.XEngDB().Table(s.TableName()). - Select("JSON_UNQUOTE(JSON_EXTRACT(target_params, '$.filePath')) as file_path"). - Where(where). - Get(&querys.Path) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - } - - fileName := tableName + "_export_" + querys.DateIndex + "0000" + ".csv" - filePath := filepath.Join(querys.Path, fileName) - - file, err := os.Open(filePath) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - defer file.Close() - - if _, err := os.Stat(filePath); os.IsNotExist(err) { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - c.Header("Content-Disposition", "attachment; filename="+fileName) - c.Header("Content-Type", "application/octet-stream") - c.File(filePath) -} - -func (m *FileNBI) GetMultiFileHandler(c *gin.Context) { - var querys FileNBIQuery - - querys.Category = c.Param("category") - querys.Type = c.Param("type") - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - tableName := "" - if querys.Path == "" { - ok := false - switch querys.Category { - case "cdr": - tableName, ok = CDRTableMapper[querys.Type] - if tableName == "" || !ok { - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid CDR file type: %s", querys.Type))) - return - } - case "log": - tableName, ok = LogTableMapper[querys.Type] - if tableName == "" || !ok { - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid log file type: %s", querys.Type))) - return - } - default: - c.JSON(http.StatusOK, services.ErrResp(fmt.Sprintf("invalid log file category: %s", querys.Category))) - return - } - - s := SysJob{} - where := fmt.Sprintf("invoke_target='%s' and status=1 and JSON_UNQUOTE(JSON_EXTRACT(target_params,'$.tableName'))='%s'", INVOKE_FILE_EXPORT, tableName) - _, err := dborm.XEngDB().Table(s.TableName()). - Select("JSON_UNQUOTE(JSON_EXTRACT(target_params, '$.filePath')) as file_path"). - Where(where). - Get(&querys.Path) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - } - - zipWriter := zip.NewWriter(c.Writer) - defer zipWriter.Close() - - for _, fileName := range querys.FileNames { - filePath := filepath.Join(querys.Path, fileName) - - file, err := os.Open(filePath) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - defer file.Close() - - if _, err := os.Stat(filePath); os.IsNotExist(err) { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - writer, err := zipWriter.Create(filepath.Base(fileName)) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - if _, err := io.Copy(writer, file); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - } - zipFile := tableName + "_export_" + time.Now().Local().Format(global.DateData) + ".zip" - c.Header("Content-Disposition", "attachment; filename="+zipFile) - c.Header("Content-Type", "application/zip") - //c.File(filePath) -} diff --git a/features/nbi/file/model.go b/features/nbi/file/model.go deleted file mode 100644 index 5dcdd9fa..00000000 --- a/features/nbi/file/model.go +++ /dev/null @@ -1,47 +0,0 @@ -package nbi_file - -import ( - "be.ems/lib/file" -) - -const ( - INVOKE_FILE_EXPORT = "exportTable" -) - -var CDRTableMapper map[string]string = map[string]string{ - "ims": "cdr_event_ims", - "smf": "cdr_event_smf", - "smsc": "cdr_event_smsc", - "sms": "cdr_event_smsc", -} - -var LogTableMapper map[string]string = map[string]string{ - "operate": "sys_log_operate", - "security": "sys_log_login", - "alarm": "alarm_log", -} - -type SysJob struct { - JobID int64 `gorm:"column:job_id;primary_key;auto_increment" json:"job_id"` //任务ID - InvokeTarget string `gorm:"column:invoke_target" json:"invoke_target"` //调用目标字符串 - TargetParams string `gorm:"column:target_params;type:json" json:"target_params,omitempty"` //调用目标传入参数 -} - -func (s *SysJob) TableName() string { - return "sys_job" -} - -type FileNBI struct { - file.FileInfo -} - -type FileNBIQuery struct { - Category string `form:"category" binding:"required"` - Type string `form:"type" binding:"required"` - DateIndex string `form:"dateIndex"` - Path string `json:"path" form:"path"` - FileNames []string `json:"fileName" form:"fileName"` - Suffix string `form:"suffix"` - PageNum int64 `form:"pageNum"` - PageSize int64 `form:"pageSize"` -} diff --git a/features/nbi/file/route.go b/features/nbi/file/route.go deleted file mode 100644 index 45c87e62..00000000 --- a/features/nbi/file/route.go +++ /dev/null @@ -1,26 +0,0 @@ -package nbi_file - -import ( - "be.ems/src/framework/middleware" - "github.com/gin-gonic/gin" -) - -// Register Routes for file_export -func Register(r *gin.RouterGroup) { - fileNBI := r.Group("/file") - { - var f *FileNBI - fileNBI.GET("/:category/:type/list", - middleware.AuthorizeUser(nil), - f.GetFileList, - ) - fileNBI.GET("/:category/:type/:dateIndex", - middleware.AuthorizeUser(nil), - f.GetSingleFileHandler, - ) - fileNBI.GET("/:category/:type", - middleware.AuthorizeUser(nil), - f.GetMultiFileHandler, - ) - } -} diff --git a/features/nbi/nbi.go b/features/nbi/nbi.go deleted file mode 100644 index 44ce90dd..00000000 --- a/features/nbi/nbi.go +++ /dev/null @@ -1,258 +0,0 @@ -package nbi - -import ( - "bytes" - "fmt" - "net/http" - "strings" - - "be.ems/lib/dborm" - "github.com/go-resty/resty/v2" - - "github.com/gorilla/mux" - - "be.ems/lib/config" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/oauth" - "be.ems/lib/services" -) - -type ErrorOAuthResponse struct { - Error map[string]interface{} -} - -type FailOAuthResponse struct { - Error struct { - ErrorCode string - ErrorInfo string - } -} - -type ApiResponse struct { - ResultCode string - ResultMessage interface{} -} - -//var globalSession = session.NewSessManager("restagent") - -var ( - MAX_RMUID_NUM int - MAX_ALARMID_NUM int - MAX_PMUID_NUM int - MAX_SUBID_NUM int - MAX_URI_LEN int - RMUID_REGEXP string -) - -var ( - // Northbound interface - GetNRMUri = config.DefaultUriPrefix + "/resourceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}" - NorthboundGetAlarmUri = config.DefaultUriPrefix + "/faultManagement/{apiVersion}/alarms" // ?alarmIds={alarmIdValues} - - CustomGetNRMUri = config.UriPrefix + "/resourceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}" -) - -func CheckParameterName(r *http.Request) []string { - var errorParams []string - vars := r.URL.Query() - for k, v := range vars { - log.Debug("vars:", k, v) - if k != "rmUIDs" && k != "fields" { - errorParams = append(errorParams, k) - } - } - - return errorParams -} - -func GetRmUIDArr(r *http.Request) []string { - vars := r.URL.Query() - rmUIDs, ok := vars["rmUIDs"] - if !ok { - log.Debug("rmUIDs is not exist") - return nil - } - - var rmUIDValues []string - for _, r := range rmUIDs { - if r != "" { - rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`)) - } - } - - return rmUIDValues -} - -func GetAttrNameArr(r *http.Request) []string { - vars := r.URL.Query() - fields, ok := vars["fields"] - if !ok { - log.Debug("attributeNames does not exist") - return nil - } - var attrNames []string - for _, a := range fields { - if a != "" { - attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`)) - } - } - - return attrNames -} - -func CheckValidRmUID(rmUIDs []string) []string { - log.Debug("CheckValidRmUID processing... ") - - var invalidRmUIDs []string - for _, r := range rmUIDs { - if !global.MatchRmUID(RMUID_REGEXP, r) { - invalidRmUIDs = append(invalidRmUIDs, r) - } - } - - return invalidRmUIDs -} - -func CheckLocalRmUID(rmUIDs []string) string { - log.Debug("GetLocalRmUID processing... ") - - rmUID := config.GetRmUIDFromConfig() - for _, r := range rmUIDs { - if r == rmUID { - return rmUID - } - } - - return "" -} - -func NBIGetNRMFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("NBIGetNRMFromNF processing... ") - - // response 414-4 uri too long ? (optional) - // todo ... ? - if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() { - log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig()) - services.ResponseRequestURITooLong414UriTooLong(w) - return - } - - // check media type(content type) only support "application/json" - // response 415-1 - if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // error processing ... - // 401-1 response - token, ret := oauth.IsCarriedToken(r) - if ret == false { - log.Error("AccessToken is not carried") - services.ResponseUnauthorized401AccessTokenNotCarried(w) - return - } - - // 401-2 response - if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false { - log.Error("AccessToken fails or does not exist") - services.ResponseUnauthorized401AccessTokenNotExist(w) - return - } - - _, err := dborm.XormUpdateSessionShakeTime(token) - if err != nil { - log.Error("Failed to update session table:", err) - services.ResponseUnauthorized401AccessTokenNotExist(w) - return - } - - /* - // response 403 Forbidden, permissions deny - // todo... - plist := globalSession.GetPermissionFromSession(token) - log.Debug("permission list:", plist) - if len(plist) == 0 || plist[0] == false { - log.Debug("User permission deny") - services.ResponseForbidden403NotPermission(w) - return - } - */ - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - - apiVer := vars["apiVersion"] - if apiVer != "v1" { - log.Error("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // response 406-1 - rmUIDValues := GetRmUIDArr(r) - if rmUIDValues == nil { - log.Error("missing parameter: rmUIDs") - services.ResponseNotAcceptable406MissingParam(w) - return - } - - // response 406-2 - errorParams := CheckParameterName(r) - if errorParams != nil { - log.Error("parameter name error: ", errorParams) - services.ResponseNotAcceptable406ParamError(w, errorParams) - return - } - - // response 400-5 - if len(rmUIDValues) == 0 { - log.Error("rmUIDs is wrong or NULL") - services.ResponseBadRequest400WrongParamValue(w) - return - } - - // response 414-1 - if len(rmUIDValues) > config.GetYamlConfig().Params.RmUIDMaxNum { - log.Error("rmUID greater than", config.GetYamlConfig().Params.RmUIDMaxNum) - services.ResponseRequestURITooLong414NRMNumExceed(w, config.GetYamlConfig().Params.RmUIDMaxNum) - return - } - - var response *resty.Response - respMsg := make(map[string]interface{}) - for _, rmUID := range rmUIDValues { - neInfo, err := dborm.XormGetNeInfoByRmUID(neType, rmUID) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: GET ", requestURI2NF) - - client := resty.New() - response, err = client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Failed to Get from NF:", err) - services.ResponseInternalServerError500NFConnectRefused(w) - return - } - switch response.StatusCode() { - case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated: - respMsg["data"] = response - default: - if response != nil { - services.TransportResponse(w, response.StatusCode(), response.Body()) - } - } - } - - services.TransportResponse(w, response.StatusCode(), response.Body()) -} diff --git a/features/nbi/service.go b/features/nbi/service.go deleted file mode 100644 index 7b913d5c..00000000 --- a/features/nbi/service.go +++ /dev/null @@ -1,16 +0,0 @@ -// log management package - -package nbi - -import ( - nbi_file "be.ems/features/nbi/file" - "be.ems/lib/log" - "github.com/gin-gonic/gin" -) - -func InitSubServiceRoute(r *gin.Engine) { - log.Info("======init North-Bound Interface group gin.Engine") - - nbiGroup := r.Group("/nbi") - nbi_file.Register(nbiGroup) -} diff --git a/features/nbi/snmp.go b/features/nbi/snmp.go deleted file mode 100644 index 9e5e727b..00000000 --- a/features/nbi/snmp.go +++ /dev/null @@ -1,203 +0,0 @@ -package nbi - -import ( - "bytes" - "fmt" - "net/http" - "strconv" - - "github.com/gorilla/mux" - g "github.com/gosnmp/gosnmp" - - "be.ems/lib/config" - "be.ems/lib/log" - "be.ems/lib/services" -) - -func init() { - conf := config.GetYamlConfig() - // Default is a pointer to a GoSNMP struct that contains sensible defaults - // eg port 161, community public, etc - g.Default.Target = conf.NE.Addr - g.Default.Port = conf.NE.Port - err := g.Default.Connect() - if err != nil { - fmt.Printf("Connect() err: %v", err) - } - //defer g.Default.Conn.Close() - MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig() - MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig() - MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig() - MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig() - MAX_URI_LEN = config.GetUriMaxLenFromConfig() - RMUID_REGEXP = config.GetRmUIDRegexpFromConfig() -} - -func GetNRMByUri(w http.ResponseWriter, r *http.Request) { - log.Debug("GetNRMByUri processing... ") - - // response 414-4 uri too long ? (optional) - // todo ... ? - if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN { - log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil)) - services.ResponseRequestURITooLong414UriTooLong(w) - return - } - - // check media type(content type) only support "application/json" - // response 415-1 - if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // error processing ... - // 401-1 response - // token, ret := globalSession.IsCarriedToken(r) - // if ret == false { - // log.Error("AccessToken is not carried") - // services.ResponseUnauthorized401AccessTokenNotCarried(w) - // return - // } - - // 401-2 response - // if globalSession.IsValidToken(token) == false { - // log.Error("AccessToken fails or does not exist") - // services.ResponseUnauthorized401AccessTokenNotExist(w) - // return - // } - // response 403 Forbidden, permissions deny - // todo... - // plist := globalSession.GetPermissionFromSession(token) - // log.Debug("permission list:", plist) - // if len(plist) == 0 || plist[0] == false { - // log.Error("User permission deny") - // services.ResponseForbidden403NotPermission(w) - // return - // } - - vars := mux.Vars(r) - qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"] - log.Debug("Get by Uri: ", qeuryUri) - - apiVer := vars["apiVersion"] - if apiVer != "v1" { - log.Error("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // response 406-1 - rmUIDValues := GetRmUIDArr(r) - if rmUIDValues == nil { - log.Error("missing parameter: rmUIDs") - services.ResponseNotAcceptable406MissingParam(w) - return - } - - // response 406-2 - errorParams := CheckParameterName(r) - if errorParams != nil { - log.Error("parameter name error: ", errorParams) - services.ResponseNotAcceptable406ParamError(w, errorParams) - return - } - - // response 400-5 - if len(rmUIDValues) == 0 { - log.Error("rmUIDs is wrong or NULL") - services.ResponseBadRequest400WrongParamValue(w) - return - } - - // response 414-1 - if len(rmUIDValues) > MAX_RMUID_NUM { - log.Error("rmUID greater than", MAX_RMUID_NUM) - services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM) - return - } - - // response 400-1 - // check rmUID is valid - // todo ... - invalidRmUIDs := CheckValidRmUID(rmUIDValues) - if len(invalidRmUIDs) != 0 { - log.Error("rmUID is invalid") - services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs) - return - } - - // response 404-2 - rmUID := CheckLocalRmUID(rmUIDValues) - if rmUID == "" { - log.Error("rmUID does not exist") - services.ResponseNotFound404NRMNotExist(w, rmUIDValues) - return - } - - // response 404-1, uri is not exist in map - attrNames := GetAttrNameArr(r) - var Oids []string - Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids) - if len(Oids) == 0 { - log.Error("Nothing of config map") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // response 404-1, uri is not exist in map - var nameOids []config.NameOid - nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids) - if len(nameOids) == 0 { - log.Error("Nothing of config map") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS - if err2 != nil { - log.Fatalf("Get() err: %v", err2) - - } - - // var nameValues []config.NameValue - var nameValue config.NameValue - - nameValues := make(map[string]interface{}) - nameValues["rmUID"] = rmUID - for i, variable := range result.Variables { - nameValue.Name = nameOids[i].Name - log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name) - // if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) { - if nameOids[i].Oid == variable.Name { - // the Value of each variable returned by Get() implements - // interface{}. You could do a type switch... - switch variable.Type { - case g.OctetString: - bytes := variable.Value.([]byte) - log.Debugf("string: %s\n", string(bytes)) - nameValue.Value = string(bytes) - nameValues[nameValue.Name] = nameValue.Value - case g.Integer: - value := variable.Value.(int) - log.Debugf("integer: %d\n", value) - nameValue.Value = strconv.Itoa(value) - nameValues[nameValue.Name] = nameValue.Value - case g.IPAddress: - value := variable.Value.(string) - log.Debugf("IPAddress: %s\n", variable.Value) - nameValue.Value = value - nameValues[nameValue.Name] = nameValue.Value - default: - // ... or often you're just interested in numeric values. - // ToBigInt() will return the Value as a BigInt, for plugging - // into your calculations. - log.Debugf("number: %d\n", g.ToBigInt(variable.Value)) - } - } - } - - getResponse := services.DataResponse{nameValues} - services.ResponseWithJson(w, http.StatusOK, getResponse) -} diff --git a/features/pm/kpi_c_report/controller.go b/features/pm/kpi_c_report/controller.go deleted file mode 100644 index 63350aa9..00000000 --- a/features/pm/kpi_c_report/controller.go +++ /dev/null @@ -1,349 +0,0 @@ -package kpi_c_report - -import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - "strings" - - "be.ems/lib/services" - "be.ems/src/framework/database/db" - "be.ems/src/framework/utils/parse" - "github.com/gin-gonic/gin" -) - -func (k *KpiCReport) Get(c *gin.Context) { - var reports []KpiCReport - var conditions []string - var params []any - - var querys KpiCReportQuery - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusBadRequest, services.ErrResp(err.Error())) - return - } - - // construct condition to get - if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(querys.NeType)) - } else { - c.JSON(http.StatusBadRequest, services.ErrResp("Not found NE type")) - return - } - tableName := TableName() + "_" + strings.ToLower(querys.NeType) - dbg := db.DB("").Model(&KpiCReport{}).Table(tableName) - - if querys.NeID != "" { - conditions = append(conditions, "rm_uid = (select n.rm_uid from ne_info n where n.ne_type=? and n.ne_id=?)") - params = append(params, strings.ToUpper(querys.NeType), querys.NeID) - } else { - c.JSON(http.StatusBadRequest, services.ErrResp("Not found required parameter NE ID")) - return - } - if querys.StartTime != "" { - conditions = append(conditions, "(UNIX_TIMESTAMP(created_at) * 1000) >= ?") - params = append(params, querys.StartTime) - } - if querys.EndTime != "" { - conditions = append(conditions, "(UNIX_TIMESTAMP(created_at) * 1000) <= ?") - params = append(params, querys.EndTime) - } - conditions = append(conditions, "kpi_values != 'null'") - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - dbg = dbg.Where(whereSql, params...) - } - // page number and size - if pageSize := querys.PageSize; pageSize > 0 { - dbg = dbg.Limit(pageSize) - if pageNum := querys.PageNum; pageNum > 0 { - dbg = dbg.Offset((pageNum - 1) * pageSize) - } - } - - // order by - if sortField, sortOrder := querys.SortField, querys.SortOrder; sortField != "" && sortOrder != "" { - orderBy := fmt.Sprintf("%s %s", sortField, sortOrder) - dbg = dbg.Order(orderBy) - } - - //err := db.DB("").Table(tableName).Where(whereSql, params...).Find(&reports).Error - err := dbg.Find(&reports).Error - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - c.JSON(http.StatusOK, services.DataResp(reports)) -} - -func (k *KpiCReport) GetReport2FE(c *gin.Context) { - var results []KpiCReport - var conditions []string - var params []any - - var querys KpiCReportQuery - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // construct condition to get - if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(querys.NeType)) - } else { - c.JSON(http.StatusOK, services.ErrResp("Not found required parameter NE type")) - return - } - tableName := TableName() + "_" + strings.ToLower(querys.NeType) - dbg := db.DB("").Model(&KpiCReport{}).Table(tableName) - - if querys.NeID != "" { - conditions = append(conditions, "rm_uid = (select n.rm_uid from ne_info n where n.ne_type=? and n.ne_id=?)") - params = append(params, querys.NeType, querys.NeID) - } else { - c.JSON(http.StatusBadRequest, services.ErrResp("Not found required parameter NE ID")) - return - } - if querys.StartTime != "" { - conditions = append(conditions, "created_at >= ?") - params = append(params, querys.StartTime) - } - if querys.EndTime != "" { - conditions = append(conditions, "created_at <= ?") - params = append(params, querys.EndTime) - } - conditions = append(conditions, "kpi_values != 'null'") - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - dbg = dbg.Where(whereSql, params...) - } - // page number and size - if pageSize := querys.PageSize; pageSize > 0 { - dbg = dbg.Limit(pageSize) - if pageNum := querys.PageNum; pageNum > 0 { - dbg = dbg.Offset((pageNum - 1) * pageSize) - } - } - - // order by - if sortField, sortOrder := querys.SortField, querys.SortOrder; sortField != "" && sortOrder != "" { - orderBy := fmt.Sprintf("%s %s", sortField, sortOrder) - dbg = dbg.Order(orderBy) - } - - //err := db.DB("").Table(tableName).Where(whereSql, params...).Find(&reports).Error - err := dbg.Find(&results).Error - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - reports := []map[string]any{} - for _, r := range results { - report := map[string]any{ - // kip_id ... - "neType": *r.NeType, - "neId": querys.NeID, - "neName": *r.NeName, - "rmUID": *r.RmUID, - "startIndex": r.Index, - "timeGroup": r.Date[:10] + " " + *r.EndTime, - "createdAt": r.CreatedAt, - "granularity": r.Granularity, - } - // 解析 JSON 字符串为 map - var kpiValues []map[string]any - err := json.Unmarshal([]byte(r.KpiValues), &kpiValues) - if err != nil { - continue - } - - // 遍历 kpiValues 数组 - for _, k := range kpiValues { - kpiId := fmt.Sprint(k["kpiId"]) - value := parse.Number(k["value"]) - - formatted := fmt.Sprintf("%.3d", value) - formattedFloat, err := strconv.ParseFloat(formatted, 64) - if err != nil { - formattedFloat = 0 - } - report[kpiId] = formattedFloat - } - reports = append(reports, report) - } - c.JSON(http.StatusOK, services.DataResp(reports)) -} - -func (k *KpiCReport) GetTotalList(c *gin.Context) { - var reports []KpiCReport - var conditions []string - var params []any - - var querys KpiCReportQuery - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // construct condition to get - if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(querys.NeType)) - } else { - c.JSON(http.StatusOK, services.ErrResp("Not found NE type")) - return - } - tableName := TableName() + "_" + strings.ToLower(querys.NeType) - dbg := db.DB("").Model(&KpiCReport{}).Table(tableName) - - if querys.StartTime != "" { - conditions = append(conditions, "created_at >= ?") - params = append(params, querys.StartTime) - } - if querys.EndTime != "" { - conditions = append(conditions, "created_at <= ?") - params = append(params, querys.EndTime) - } - conditions = append(conditions, "kpi_values != 'null'") - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - dbg = dbg.Where(whereSql, params...) - } - - // get total number - var total int64 = 0 - err := dbg.Count(&total).Error - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // page number and size - if pageSize := querys.PageSize; pageSize > 0 { - dbg = dbg.Limit(pageSize) - if pageNum := querys.PageNum; pageNum > 0 { - dbg = dbg.Offset((pageNum - 1) * pageSize) - } - } - - // order by - if sortField, sortOrder := querys.SortField, querys.SortOrder; sortField != "" && sortOrder != "" { - orderBy := fmt.Sprintf("%s %s", sortField, sortOrder) - dbg = dbg.Order(orderBy) - } - - //err := db.DB("").Table(tableName).Where(whereSql, params...).Find(&reports).Error - err = dbg.Find(&reports).Error - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - c.JSON(http.StatusOK, services.TotalDataResp(reports, total)) -} - -func (k *KpiCReport) Total(c *gin.Context) { - var conditions []string - var params []any - - var querys KpiCReportQuery - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // construct condition to get - if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(querys.NeType)) - } else { - c.JSON(http.StatusOK, services.ErrResp("Not found NE type")) - return - } - tableName := TableName() + "_" + strings.ToLower(querys.NeType) - dbg := db.DB("").Model(&KpiCReport{}).Table(tableName) - if querys.StartTime != "" { - conditions = append(conditions, "(UNIX_TIMESTAMP(created_at) * 1000) >= ?") - params = append(params, querys.StartTime) - } - if querys.EndTime != "" { - conditions = append(conditions, "(UNIX_TIMESTAMP(created_at) * 1000) <= ?") - params = append(params, querys.EndTime) - } - conditions = append(conditions, "kpi_values != 'null'") - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - dbg = dbg.Where(whereSql, params...) - } - var total int64 = 0 - err := dbg.Count(&total).Error - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - c.JSON(http.StatusOK, services.TotalResp(total)) -} - -func (k *KpiCReport) Post(c *gin.Context) { - var report KpiCReport - - if err := c.ShouldBindJSON(&report); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - dbg := db.DB("").Model(&KpiCReport{}) - if err := dbg.Create(&report).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - c.JSON(http.StatusCreated, services.DataResp(report)) -} - -func (k *KpiCReport) Put(c *gin.Context) { - var report KpiCReport - id := c.Param("id") - dbg := db.DB("").Model(&KpiCReport{}) - if err := dbg.First(&report, id).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp("custom indicator report not found")) - return - } - - if err := c.ShouldBindJSON(&report); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - db.DB("").Model(&KpiCReport{}).Save(&report) - c.JSON(http.StatusOK, services.DataResp(report)) -} - -func (k *KpiCReport) Delete(c *gin.Context) { - id := c.Param("id") - - if err := db.DB("").Delete(&KpiCReport{}, id).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp("custom indicator report not found")) - return - } - - c.JSON(http.StatusNoContent, nil) // 204 No Content -} - -func InsertKpiCReport(neType string, report KpiCReport) { - tableName := TableName() + "_" + strings.ToLower(neType) - dbg := db.DB("").Model(&KpiCReport{}) - if err := dbg.Table(tableName).Create(&report).Error; err != nil { - return - } -} diff --git a/features/pm/kpi_c_report/model.go b/features/pm/kpi_c_report/model.go deleted file mode 100644 index 82a3c505..00000000 --- a/features/pm/kpi_c_report/model.go +++ /dev/null @@ -1,42 +0,0 @@ -package kpi_c_report - -type KpiCReport struct { - ID int `gorm:"column:id;primary_key;auto_increment" json:"id"` - NeType *string `gorm:"column:ne_type;default:NULL" json:"neType,omitempty"` - NeName *string `gorm:"column:ne_name;default:" json:"neName,omitempty"` - RmUID *string `gorm:"column:rm_uid;" json:"rmUid,omitempty"` - Date string `gorm:"column:date" json:"date"` // time.Time `gorm:"column:date" json:"date"` - StartTime *string `gorm:"column:start_time" json:"startTime,omitempty"` - EndTime *string `gorm:"column:end_time" json:"endTime,omitempty"` - Index int64 `gorm:"column:index" json:"index"` - Granularity *int64 `gorm:"column:granularity" json:"granularity,omitempty"` //Time granualarity: 5/10/.../60/300 (second) - KpiValues string `gorm:"column:kpi_values" json:"kpiValues,omitempty"` - CreatedAt *int64 `gorm:"column:created_at" json:"createdAt,omitempty"` -} - -type KpiCReportQuery struct { - NeType string `json:"neType" form:"neType" binding:"required"` - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - StartTime string `json:"startTime" form:"startTime"` - EndTime string `json:"endTime" form:"endTime"` - UserName string `json:"userName" form:"userName"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=created_at"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int `json:"pageNum" form:"pageNum"` - PageSize int `json:"pageSize" form:"pageSize"` -} - -type KpiCReport2FE struct { - NeType string `json:"neType" gorm:"column:ne_type"` - NeId string `json:"neId"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUid" gorm:"column:rm_uid"` - TimeGroup string `json:"timeGroup"` - StartIndex int16 `json:"startIndex" gorm:"column:index"` - Granularity int8 `json:"granularity" gorm:"column:granularity"` -} - -func TableName() string { - return "kpi_c_report" -} diff --git a/features/pm/kpi_c_report/route.go b/features/pm/kpi_c_report/route.go deleted file mode 100644 index 037d936c..00000000 --- a/features/pm/kpi_c_report/route.go +++ /dev/null @@ -1,43 +0,0 @@ -package kpi_c_report - -import ( - "be.ems/src/framework/middleware" - "github.com/gin-gonic/gin" -) - -// Register Routes for kpi_c_report -func Register(r *gin.RouterGroup) { - - pmKPIC := r.Group("/kpiC") - { - var k *KpiCReport - pmKPIC.GET("/report", - middleware.AuthorizeUser(nil), - k.GetReport2FE, - ) - pmKPIC.GET("/report/list", - middleware.AuthorizeUser(nil), - k.Get, - ) - pmKPIC.GET("/report/totalList", - middleware.AuthorizeUser(nil), - k.Total, - ) - pmKPIC.GET("/report/total", - middleware.AuthorizeUser(nil), - k.Total, - ) - pmKPIC.POST("/report", - middleware.AuthorizeUser(nil), - k.Post, - ) - pmKPIC.PUT("/report/:id", - middleware.AuthorizeUser(nil), - k.Put, - ) - pmKPIC.DELETE("/report/:id", - middleware.AuthorizeUser(nil), - k.Delete, - ) - } -} diff --git a/features/pm/kpi_c_title/controller.go b/features/pm/kpi_c_title/controller.go deleted file mode 100644 index 50c2b685..00000000 --- a/features/pm/kpi_c_title/controller.go +++ /dev/null @@ -1,312 +0,0 @@ -package kpi_c_title - -import ( - "fmt" - "net/http" - "regexp" - "sort" - "strconv" - "strings" - "time" - - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/database/db" - "be.ems/src/framework/reqctx" - - "github.com/gin-gonic/gin" -) - -// get customize kpi total and list -func (k *KpiCTitle) GetToalList(c *gin.Context) { - var titles []KpiCTitle - var conditions []string - var params []any - i18n := reqctx.AcceptLanguage(c) - - var querys KpiCTitleQuery - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - dbg := db.DB("").Model(&KpiCTitle{}) - // construct condition to get - if neType := querys.NeType; neType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(neType)) - } - if status := querys.Status; status != "" { - conditions = append(conditions, "status = ?") - params = append(params, status) - } else { - conditions = append(conditions, "status != '2'") - } - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - dbg = dbg.Where(whereSql, params...) - } - - // Get total number - var total int64 = 0 - if err := dbg.Count(&total).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - // page number and size - if pageSize := querys.PageSize; pageSize > 0 { - dbg = dbg.Limit(pageSize) - if pageNum := querys.PageNum; pageNum > 0 { - dbg = dbg.Offset((pageNum - 1) * pageSize) - } - } - - // order by - if sortField, sortOrder := querys.SortField, querys.SortOrder; sortField != "" && sortOrder != "" { - orderBy := fmt.Sprintf("%s %s", sortField, sortOrder) - dbg = dbg.Order(orderBy) - } - if err := dbg.Find(&titles).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - k.expressionAlias(titles, i18n) - - c.JSON(http.StatusOK, services.TotalDataResp(titles, total)) - //c.JSON(http.StatusOK, titles) -} - -func (k *KpiCTitle) Get(c *gin.Context) { - var titles []KpiCTitle - var conditions []string - var params []any - i18n := reqctx.AcceptLanguage(c) - - // construct condition to get - if neType := c.Query("neType"); neType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(neType)) - } - if status := c.Query("status"); status != "" { - conditions = append(conditions, "status = ?") - params = append(params, status) - } else { - conditions = append(conditions, "status != '2'") - } - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - } - if err := db.DB("").Where(whereSql, params...).Find(&titles).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - k.expressionAlias(titles, i18n) - - c.JSON(http.StatusOK, services.DataResp(titles)) - //c.JSON(http.StatusOK, titles) -} - -// alias customized kpi expression with cn/en title -func (k *KpiCTitle) expressionAlias(titles []KpiCTitle, i18n string) { - var title *KpiCTitle - for i := 0; i < len(titles); i++ { - title = &titles[i] - title.ExprAlias = *title.Expression - re := regexp.MustCompile(`'([^']+)'`) - matches := re.FindAllStringSubmatch(title.ExprAlias, -1) - - for _, match := range matches { - var alias, sql string - if i18n == "zh" { - sql = fmt.Sprintf("SELECT cn_title FROM kpi_title WHERE kpi_id='%s'", match[1]) - } else { - sql = fmt.Sprintf("SELECT en_title FROM kpi_title WHERE kpi_id='%s'", match[1]) - } - m, err := db.RawDB("", sql, nil) - if err != nil { - log.Warn("Failed to QueryRow:", err) - continue - } - if len(m) > 0 { - if i18n == "zh" { - alias = fmt.Sprintf("%v", m[0]["cn_title"]) - } else { - alias = fmt.Sprintf("%v", m[0]["en_title"]) - } - } - title.ExprAlias = regexp.MustCompile(match[1]).ReplaceAllString(title.ExprAlias, alias) - } - } -} - -func (k *KpiCTitle) Total(c *gin.Context) { - var conditions []string - var params []any - - // construct condition to get - if neType := c.Query("neType"); neType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.ToUpper(neType)) - } - if status := c.Query("status"); status != "" { - conditions = append(conditions, "status = ?") - params = append(params, status) - } else { - conditions = append(conditions, "status != '2'") - } - - whereSql := "" - if len(conditions) > 0 { - whereSql += strings.Join(conditions, " and ") - } - var total int64 = 0 - if err := db.DB("").Table(k.TableName()).Where(whereSql, params...).Count(&total).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - c.JSON(http.StatusOK, services.TotalResp(total)) -} - -func (k *KpiCTitle) Post(c *gin.Context) { - var title KpiCTitle - if err := c.ShouldBindJSON(&title); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - userName := reqctx.LoginUserToUserName(c) - title.CreatedBy = &userName - tx := db.DB("").Model(&KpiCTitle{}) - result := tx.Where("ne_type=? and (kpi_id=? or title=?) and status!='2'", title.NeType, title.KpiID, title.Title).First(&title) - if result.RowsAffected > 0 { - c.JSON(http.StatusOK, services.ErrResp("custom indicator already exist")) - return - } - - // Regexp match like AMF.C.01 - // kpiIDRegexp := "^" + *title.NeType + "\\.C\\.[0-9]{2}$" - // ret := db.DB("").Table("kpi_c_title"). - // Where("ne_type=? and kpi_id REGEXP ? ORDER BY kpi_id DESC LIMIT 1", title.NeType, kpiIDRegexp).Scan(&res) - // if err := ret.Error; err != nil { - // c.JSON(http.StatusOK, services.ErrResp(err.Error())) - // return - // } - - titles := []KpiCTitle{} - ret := db.DB("").Model(&KpiCTitle{}) - ret = ret.Select("kpi_id").Where("ne_type=?", title.NeType).Find(&titles) - - newKpiID := *title.NeType + ".C" + ".01" - if ret.RowsAffected != 0 { - suffixInt := 1 - prefixStr := fmt.Sprintf("%s.C.", *title.NeType) - sort.SliceStable(titles, func(i, j int) bool { - vi := *titles[i].KpiID - vj := *titles[j].KpiID - if strings.HasPrefix(vi, prefixStr) && strings.HasPrefix(vj, prefixStr) { - vvi := strings.Replace(vi, prefixStr, "", 1) - vvii, err := strconv.Atoi(vvi) - if err != nil { - return false - } - vvj := strings.Replace(vj, prefixStr, "", 1) - vvjj, err := strconv.Atoi(vvj) - if err != nil { - return false - } - return vvii > vvjj // desc - } - return false - }) - maxKpiID := *titles[0].KpiID - prefix := maxKpiID[:len(maxKpiID)-2] - suffix := maxKpiID[len(maxKpiID)-2:] - suffixInt, err := strconv.Atoi(suffix) - if err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - if suffixInt >= MAX_KPI_C_ID { - err := fmt.Errorf("exceed the max customized KPI ID") - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - suffixInt++ - newSuffix := fmt.Sprintf("%02d", suffixInt) - newKpiID = prefix + newSuffix - } - title.KpiID = &newKpiID - txx := db.DB("").Model(&KpiCTitle{}) - if err := txx.Create(&title).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - kpiCReportTable := "kpi_c_report_" + strings.ToLower(*title.NeType) - if !db.DB("").Migrator().HasTable(kpiCReportTable) { - // clone table "kpi_c_report" to "kpi_c_report_{neType}" - sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s AS SELECT * FROM %s WHERE 1=0", kpiCReportTable, "kpi_c_report") - if _, err := db.ExecDB("", sql, nil); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - sql = fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN `id` int(11) NOT NULL AUTO_INCREMENT FIRST,ADD PRIMARY KEY IF NOT EXISTS (`id`)", kpiCReportTable) - if _, err := db.ExecDB("", sql, nil); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - sql = fmt.Sprintf("ALTER TABLE %s ADD INDEX IF NOT EXISTS `idx_timestamp`(`created_at`) USING BTREE, ADD INDEX IF NOT EXISTS `idx_uid_datetime`(`rm_uid`, `date`, `start_time`) USING BTREE", kpiCReportTable) - if _, err := db.ExecDB("", sql, nil); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - } - c.JSON(http.StatusCreated, services.DataResp(title)) -} - -func (k *KpiCTitle) Put(c *gin.Context) { - var title KpiCTitle - id := c.Param("id") - - if err := db.DB("").First(&title, id).Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp("custom indicator not found")) - return - } - - if err := c.ShouldBindJSON(&title); err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - title.UpdatedAt = time.Now().UnixMilli() - db.DB("").Save(&title) - - c.JSON(http.StatusOK, services.DataResp(title)) -} - -func (k *KpiCTitle) Delete(c *gin.Context) { - id := c.Param("id") - - if err := db.DB("").Table(k.TableName()).Where("id=?", id).Update("status", "2").Error; err != nil { - c.JSON(http.StatusOK, services.ErrResp(err.Error())) - return - } - - c.JSON(http.StatusNoContent, nil) // 204 No Content -} - -func GetActiveKPICList(neType string) []KpiCTitle { - k := new([]KpiCTitle) - - err := db.DB("").Where("`ne_type` = ? and `status` = '1'", neType).Find(&k).Error - if err != nil { - return nil - } - return *k -} diff --git a/features/pm/kpi_c_title/model.go b/features/pm/kpi_c_title/model.go deleted file mode 100644 index 05170c4b..00000000 --- a/features/pm/kpi_c_title/model.go +++ /dev/null @@ -1,33 +0,0 @@ -package kpi_c_title - -const ( - MAX_KPI_C_ID = 99 -) - -type KpiCTitle struct { - ID int `gorm:"column:id;primary_key;auto_increment" json:"id"` - NeType *string `gorm:"column:ne_type" json:"neType,omitempty"` - KpiID *string `gorm:"column:kpi_id" json:"kpiId,omitempty"` - Title *string `gorm:"column:title" json:"title,omitempty"` - Expression *string `gorm:"column:expression" json:"expression,omitempty"` - ExprAlias string `gorm:"-" json:"exprAlias"` - Status string `gorm:"column:status" json:"status"` // 0-Inactive/1-Active/2-Deleted - Unit *string `gorm:"column:unit" json:"unit,omitempty"` - Description *string `gorm:"column:description" json:"description,omitempty"` - CreatedBy *string `gorm:"column:created_by" json:"createdBy,omitempty"` - UpdatedAt int64 `gorm:"column:updated_at" json:"updatedAt,omitempty"` -} - -type KpiCTitleQuery struct { - ID int `json:"id" form:"id"` - NeType string `json:"neType" form:"neType"` - Status string `json:"status" form:"status"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=created_at"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int `json:"pageNum" form:"pageNum"` - PageSize int `json:"pageSize" form:"pageSize"` -} - -func (k *KpiCTitle) TableName() string { - return "kpi_c_title" -} diff --git a/features/pm/kpi_c_title/route.go b/features/pm/kpi_c_title/route.go deleted file mode 100644 index 485f3f93..00000000 --- a/features/pm/kpi_c_title/route.go +++ /dev/null @@ -1,39 +0,0 @@ -package kpi_c_title - -import ( - "be.ems/src/framework/middleware" - "github.com/gin-gonic/gin" -) - -// Register Routes for kpi_c_title -func Register(r *gin.RouterGroup) { - - pmKPIC := r.Group("/kpiC") - { - var k *KpiCTitle - pmKPIC.GET("/title", - middleware.AuthorizeUser(nil), - k.Get, - ) - pmKPIC.GET("/title/total", - middleware.AuthorizeUser(nil), - k.Total, - ) - pmKPIC.GET("/title/totalList", - middleware.AuthorizeUser(nil), - k.GetToalList, - ) - pmKPIC.POST("/title", - middleware.AuthorizeUser(nil), - k.Post, - ) - pmKPIC.PUT("/title/:id", - middleware.AuthorizeUser(nil), - k.Put, - ) - pmKPIC.DELETE("/title/:id", - middleware.AuthorizeUser(nil), - k.Delete, - ) - } -} diff --git a/features/pm/performance.go b/features/pm/performance.go deleted file mode 100644 index 0a779084..00000000 --- a/features/pm/performance.go +++ /dev/null @@ -1,1227 +0,0 @@ -package pm - -import ( - "encoding/json" - "fmt" - "io" - "math" - "net/http" - "strconv" - "strings" - "time" - - "be.ems/features/pm/kpi_c_report" - "be.ems/features/pm/kpi_c_title" - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/dborm" - evaluate "be.ems/lib/eval" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/database/db" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/parse" - neDataModel "be.ems/src/modules/network_data/model" - neDataService "be.ems/src/modules/network_data/service" - neService "be.ems/src/modules/network_element/service" - wsService "be.ems/src/modules/ws/service" - - "github.com/go-resty/resty/v2" - "github.com/gorilla/mux" -) - -type Response struct { - Data interface{} `json:"data"` -} - -type KpiReport struct { - Timestamp string `json:"TimeStamp"` - Task struct { - Period struct { - StartTime string `json:"StartTime"` - EndTime string `json:"EndTime"` - } `json:"Period"` - NE struct { - NEName string `json:"NEName"` - RmUID string `json:"rmUID"` - NeType string `json:"NeType"` - KPIs []struct { - KPIID string `json:"KPIID"` - Value int64 `json:"Value"` - Err string `json:"Err"` - } `json:"KPIs"` - } `json:"NE"` - } `json:"Task"` -} - -type GoldKpi struct { - // Id int `json:"-" xorm:"pk 'id' autoincr"` - Date string `json:"date" xorm:"date"` - Index int `json:"index"` - Granularity int8 `json:"granularity"` - StartTime string `json:"startTime"` - EndTime string `json:"endTime"` - NEName string `json:"neName" xorm:"ne_name"` - RmUid string `json:"rmUid" xorm:"rm_uid"` - NEType string `json:"neType" xorm:"ne_type"` - KpiId string `json:"kpiId" xorm:"kpi_id"` - Value int64 `json:"value"` - Error string `json:"error"` - Timestamp string `json:"timestamp"` -} - -type KpiData struct { - ID int `json:"id" xorm:"pk 'id' '<-' autoincr"` - NEType string `json:"neType" xorm:"ne_type"` - NEName string `json:"neName" xorm:"ne_name"` - RmUid string `json:"rmUid" xorm:"rm_uid"` - Date string `json:"date" xorm:"date"` - StartTime string `json:"startTime" xorm:"start_time"` - EndTime string `json:"endTime" xorm:"end_time"` - Index int `json:"index" xorm:"index"` - Granularity int64 `json:"granularity" xorm:"granularity"` - KPIValues []KPIVal `json:"kpiValues" xorm:"json 'kpi_values'"` - //CreatedAt int64 `json:"createdAt" xorm:"created 'created_at'"` - CreatedAt int64 `json:"createdAt" xorm:"'created_at'"` -} -type KPIVal struct { - KPIID string `json:"kpi_id" xorm:"kpi_id"` - Value int64 `json:"value" xorm:"value"` - Err string `json:"err" xorm:"err"` -} - -var ( - // performance management - PerformanceUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}" - MeasureTaskUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureTask" - MeasureReportUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureReport" - MeasureReportFmt = config.DefaultUriPrefix + "/performanceManagement/v1/elementType/%s/objectType/measureReport" - MeasurementUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measurement/{index}" - UriMeasureTask = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/measureTask/{netype}" - - // performance management - CustomPerformanceUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}" - CustomMeasureTaskUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureTask" - CustomMeasureReportUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureReport" - CustomMeasureReportFmt = config.UriPrefix + "/performanceManagement/v1/elementType/%s/objectType/measureReport" - CustomMeasurementUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measurement/{index}" - CustomUriMeasureTask = config.UriPrefix + "/performanceManagement/{apiVersion}/measureTask/{netype}" -) - -func GetDateFromTimeString(fmtString string, timeString string) string { - t, _ := time.ParseInLocation(fmtString, timeString, time.Local) - return t.Format("2006-01-02") -} - -func GetDateTimeFromTimeString(fmtString string, timeString string) string { - t, _ := time.ParseInLocation(fmtString, timeString, time.Local) - return t.Format(global.DateTime) -} - -// process KPI report post message from NFs -func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostKPIReportFromNF processing... ") - - apiVer := ctx.GetParam(r, "apiVersion") - if apiVer != global.ApiVersionV1 { - log.Error("Uri api version is invalid. apiVersion:", apiVer) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - var kpiReport KpiReport - if err := ctx.ShouldBindJSON(r, &kpiReport); err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - kpiIndexStr := ctx.GetParam(r, "index") - - // insert kpi_report table, no session - saveKPIData(kpiReport, parse.Number(kpiIndexStr)) - saveKPIDataC(kpiReport, parse.Number(kpiIndexStr)) - - services.ResponseStatusOK204NoContent(w) -} - -// saveKPIData 存储KPI数据并推送到ws订阅组 -func saveKPIData(kpiReport KpiReport, index int64) int64 { - timestamp := kpiReport.Timestamp - taskPeriod := kpiReport.Task.Period - taskNe := kpiReport.Task.NE - taskNeKPIs := kpiReport.Task.NE.KPIs - // 时间数据处理 - receiverTime := date.ParseStrToDate(timestamp, date.YYYY_MM_DDTHH_MM_SSZ) - startTime := date.ParseStrToDate(taskPeriod.StartTime, date.YYYY_MM_DDTHH_MM_SSZ) - endTime := date.ParseStrToDate(taskPeriod.EndTime, date.YYYY_MM_DDTHH_MM_SSZ) - granularity := parse.Number(endTime.Sub(startTime).Seconds()) - // kpi data数据json - KpiValues := make([]map[string]any, 0) - for _, v := range taskNeKPIs { - KpiValues = append(KpiValues, map[string]any{ - "kpiId": v.KPIID, - "value": v.Value, - "err": v.Err, - }) - } - KpiValuesByte, _ := json.Marshal(KpiValues) - kpiData := neDataModel.KpiReport{ - NeType: taskNe.NeType, - NeName: taskNe.NEName, - RmUid: taskNe.RmUID, - Date: date.ParseDateToStr(receiverTime, "2006-01-02"), - StartTime: date.ParseDateToStr(startTime, "15:04:05"), - EndTime: date.ParseDateToStr(endTime, "15:04:05"), - Index: index, - Granularity: granularity, - KpiValues: string(KpiValuesByte), - CreatedAt: receiverTime.UnixMilli(), // 时间戳毫秒实际记录到秒 - } - insertId := neDataService.NewKpiReport.Insert(kpiData) - if insertId > 0 { - // 指标事件对象 - kpiEvent := map[string]any{ - "neType": kpiData.NeType, - "neName": kpiData.NeName, - "rmUID": kpiData.RmUid, - "startIndex": kpiData.Index, - "timeGroup": kpiData.CreatedAt, - // kip_id ... - } - for _, v := range taskNeKPIs { - kpiEvent[v.KPIID] = v.Value - } - - // 发送到匹配的网元 - neInfo := neService.NewNeInfo.FindByRmuid(kpiData.RmUid) - if neInfo.RmUID == kpiData.RmUid { - // 推送到ws订阅组 - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, neInfo.NeType, neInfo.NeId), kpiEvent) - if neInfo.NeType == "UPF" { - // 更新UPF总流量 - upValue := parse.Number(kpiEvent["UPF.03"]) - downValue := parse.Number(kpiEvent["UPF.06"]) - neDataService.NewKpiReport.UPFTodayFlowUpdate(neInfo.RmUID, upValue, downValue) - } - } - } - return insertId -} - -// saveKPIDataC 存储自定义KPI数据并推送到ws订阅组 -func saveKPIDataC(kpiReport KpiReport, index int64) int64 { - timestamp := kpiReport.Timestamp - taskPeriod := kpiReport.Task.Period - taskNe := kpiReport.Task.NE - taskNeKPIs := kpiReport.Task.NE.KPIs - // 时间数据处理 - receiverTime := date.ParseStrToDate(timestamp, date.YYYY_MM_DDTHH_MM_SSZ) - startTime := date.ParseStrToDate(taskPeriod.StartTime, date.YYYY_MM_DDTHH_MM_SSZ) - endTime := date.ParseStrToDate(taskPeriod.EndTime, date.YYYY_MM_DDTHH_MM_SSZ) - granularity := parse.Number(endTime.Sub(startTime).Seconds()) - // kpi data数据 - KpiValues := make([]map[string]any, 0) - kpiValMap := map[string]any{} - for _, v := range taskNeKPIs { - kpiValMap[v.KPIID] = v.Value - } - // 自定义kpiId数据 - cTitles := kpi_c_title.GetActiveKPICList(taskNe.NeType) - for _, v := range cTitles { - item := map[string]any{ - "kpiId": *v.KpiID, - "value": 0, - "err": "", - } - // 计算结果 - result, err := evaluate.CalcExpr(*v.Expression, kpiValMap) - if err != nil { - item["value"] = 0 - item["err"] = err.Error() - } else { - if *v.Unit == "%" && result > 100 { - result = 100 - } - if *v.Unit == "%" && result < 0 { - result = 0 - } - item["value"] = result - } - KpiValues = append(KpiValues, item) - } - - KpiValuesByte, _ := json.Marshal(KpiValues) - kpiData := neDataModel.KpiCReport{ - NeType: taskNe.NeType, - NeName: taskNe.NEName, - RmUid: taskNe.RmUID, - Date: date.ParseDateToStr(receiverTime, "2006-01-02"), - StartTime: date.ParseDateToStr(startTime, "15:04:05"), - EndTime: date.ParseDateToStr(endTime, "15:04:05"), - Index: index, - Granularity: granularity, - KpiValues: string(KpiValuesByte), - CreatedAt: receiverTime.UnixMilli(), // 时间戳毫秒实际记录到秒 - } - insertId := neDataService.NewKpiCReport.Insert(kpiData) - if insertId > 0 { - // 指标事件对象 - kpiEvent := map[string]any{ - "neType": kpiData.NeType, - "neName": kpiData.NeName, - "rmUID": kpiData.RmUid, - "startIndex": kpiData.Index, - "timeGroup": kpiData.CreatedAt, - // kip_id ... - } - for _, v := range KpiValues { - kpiEvent[fmt.Sprint(v["kpiId"])] = v["value"] - } - - // 发送到匹配的网元 - neInfo := neService.NewNeInfo.FindByRmuid(kpiData.RmUid) - if neInfo.RmUID == kpiData.RmUid { - // 推送自定义KPI到ws订阅组 - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, neInfo.NeType, neInfo.NeId), kpiEvent) - } - } - return insertId -} - -// process KPI report post message from NFs 旧版 -func PostKPIReportFromNFOld(w http.ResponseWriter, r *http.Request) { - log.Debug("PostKPIReportFromNF processing... ") - - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - log.Error("Uri api version is invalid. apiVersion:", apiVer) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Faile to io.ReadAll: ", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - //log.Trace("Request body:", string(body)) - kpiReport := new(KpiReport) - _ = json.Unmarshal(body, &kpiReport) - //log.Trace("kpiReport:", kpiReport) - - layout := time.RFC3339Nano - //kpiDate := GetDateFromTimeString(layout, kpiReport.Task.Period.StartTime) - kpiIndex, _ := strconv.Atoi(vars["index"]) - startTime := global.GetFmtTimeString(layout, kpiReport.Task.Period.StartTime, time.DateTime) - endTime := global.GetFmtTimeString(layout, kpiReport.Task.Period.EndTime, time.DateTime) - // get time granularity from startTime and endTime - seconds, _ := global.GetSecondDuration(startTime, endTime) - var granularity int64 = 60 - if seconds != 0 && seconds <= math.MaxInt8 && seconds >= math.MinInt8 { - granularity = int64(seconds) - } - - // insert into new kpi_report_xxx table - kpiData := new(KpiData) - kpiData.Date = startTime - kpiData.Index = kpiIndex - //stime, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.StartTime, time.Local) - //etime, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.EndTime, time.Local) - kpiData.StartTime = startTime - kpiData.EndTime = endTime - kpiData.Granularity = granularity - kpiData.NEName = kpiReport.Task.NE.NEName - kpiData.NEType = kpiReport.Task.NE.NeType - kpiData.RmUid = kpiReport.Task.NE.RmUID - kpiVal := new(KPIVal) - kpiData.CreatedAt = time.Now().UnixMilli() - - // 黄金指标事件对象 - kpiEvent := map[string]any{ - // kip_id ... - "neType": kpiReport.Task.NE.NeType, - "neName": kpiReport.Task.NE.NEName, - "rmUID": kpiReport.Task.NE.RmUID, - "startIndex": kpiIndex, - "timeGroup": kpiData.CreatedAt, - } - - // for custom kpi - kpiValMap := map[string]any{} - for _, k := range kpiReport.Task.NE.KPIs { - kpiEvent[k.KPIID] = k.Value // kip_id - - kpiVal.KPIID = k.KPIID - kpiVal.Value = int64(k.Value) - kpiVal.Err = k.Err - kpiData.KPIValues = append(kpiData.KPIValues, *kpiVal) - kpiValMap[k.KPIID] = k.Value - } - kpiValMap["granularity"] = kpiData.Granularity - - // insert kpi_report table, no session - tableName := "kpi_report_" + strings.ToLower(kpiReport.Task.NE.NeType) - // affected, err := xEngine.Table(tableName).Insert(kpiData) - tx := db.DB("").Table(tableName).Create(kpiData) - if tx.Error != nil && tx.RowsAffected <= 0 { - log.Errorf("Failed to insert %s:%v", tableName, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - report := kpi_c_report.KpiCReport{ - NeType: &kpiData.NEType, - NeName: &kpiData.NEName, - RmUID: &kpiData.RmUid, - Date: kpiData.Date, - StartTime: &kpiData.StartTime, - EndTime: &kpiData.EndTime, - Index: int64(kpiData.Index), - Granularity: &kpiData.Granularity, - } - - // 发送到匹配的网元 - neInfo := neService.NewNeInfo.FindByRmuid(kpiData.RmUid) - // custom kpi report to FE - kpiCEvent := map[string]any{ - // kip_id ... - "neType": kpiData.NEType, - "neId": neInfo.NeId, - "neName": kpiData.NEName, - "rmUID": kpiData.RmUid, - "startIndex": kpiData.Index, - "timeGroup": kpiData.Date[:10] + " " + kpiData.EndTime, - "createdAt": kpiData.CreatedAt, - "granularity": kpiData.Granularity, - } - // kpiCList := kpi_c_title.GetActiveKPICList(kpiData.NEType) - // for _, k := range kpiCList { - // result, err := evaluate.CalcExpr(*k.Expression, kpiValMap) - // kpiCVal := new(kpi_c_report.KpiCVal) - // kpiCVal.KPIID = *k.KpiID - // if err != nil { - // kpiCVal.Value = 0.0 - // kpiCVal.Err = err.Error() - // } else { - // kpiCVal.Value = result - // } - - // report.KpiValues = append(report.KpiValues, *kpiCVal) - - // // set KPIC event kpiid and value - // kpiCEvent[kpiCVal.KPIID] = kpiCVal.Value - // } - - // KPI自定义指标入库 - kpi_c_report.InsertKpiCReport(kpiData.NEType, report) - - if neInfo.RmUID == kpiData.RmUid { - // 推送到ws订阅组 - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, neInfo.NeType, neInfo.NeId), kpiEvent) - // 推送自定义KPI到ws订阅组 - wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, neInfo.NeType, neInfo.NeId), kpiCEvent) - } - - services.ResponseStatusOK204NoContent(w) -} - -// type MeasureTask struct { -// Tasks []Task `json:"Tasks"` -// NotifyUrl string `json:"NotifyUrl"` /* "http://xEngine.xEngine.xEngine.x:xxxx/api/rest/performanceManagement/v1/elementType/smf/objectType/measureReport */ -// } -type ScheduleJ struct { - Type string `json:"Type"` - Days []int `json:"Days"` -} - -type Period struct { - Start string `json:"Start"` - End string `json:"End"` -} -type Task struct { - Id int `json:"Id"` - - StartTime string `json:"StartTime"` - EndTime string `json:"EndTime"` - - Schedule struct { - Type string `json:"Type"` // 计划类型:Weekly/Monthly, 如果type为"", 则任务以StartTime和EndTime为条件进行统计, 否则以Shedule方式进行 - Days []int `json:"Days"` // Weekly: [0,1,...,5,6] 星期日为0, Monthly: [1,2,3,...,30,31] - Periods []Period `json:"Periods"` - /* - Periods []struct { - Start string `json:"Start"` // 零点或者零点加测量粒度的整数倍 - End string `json:"End"` //零点加测量粒度的整数倍 - } `json:"Periods"` - */ - } `json:"Schedule"` - - GranulOption string `json:"GranulOption"` // 测量粒度选项:15M/30M/60M/24H - KPISet []KpiSetJ `json:"KPISet"` - /* - KPISet []struct { - Code string `json:"Code"` // 统计编码 如:SMFHA01 - KPIs []string `json:"KPIs` // 指标项集合 ["SMF.AttCreatePduSession", "SMF.AttCreatePduSession._Dnn"] - } `json:"KPISet"` - */ -} -type KpiSetJ struct { - Code string `json:"Code"` // 统计编码 如:SMFHA01 - KPIs []string `json:"KPIs"` // 指标项集合 ["SMF.AttCreatePduSession", "SMF.AttCreatePduSession._Dnn"] -} - -type MeasureTask struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeIds []string `json:"neIds" xorm:"ne_ids"` - KpiSet []KpiSetJ `json:"KPISet" xorm:"kpi_set"` - StartTime string `json:"startTime" xorm:"start_time"` - EndTime string `json:"endTime" xorm:"end_time"` - Periods []Period `json:"Periods" xorm:"periods"` - Schedule []ScheduleJ `json:"Schedule" xorm:"schedule"` - GranulOption string `json:"granulOption" xorm:"granul_option"` - Status string `json:"status" xorm:"status"` - AccountID string `json:"accountId" xorm:"account_id"` - Comment string `json:"comment" xorm:"comment"` - CreateTime string `json:"createTime" xorm:"create_time"` - UpdateTime string `json:"updateTime" xorm:"update_time"` - DeleteTime string `json:"deleteTime" xorm:"delete_time"` - - Tasks []Task `json:"Tasks"` - NotifyUrl string `json:"NotifyUrl"` /* "http://xEngine.xEngine.xEngine.x:xxxx/api/rest/performanceManagement/v1/elementType/smf/objectType/measureReport */ -} -type MeasureReport struct { - Id int `json:"Id"` - TimeStamp string `json:"TimeStamp"` - NeName string `json:"NeName"` - RmUID string `json:"rmUID"` - NeType string `json:"NeType"` - - Report struct { - Period struct { - StartTime string `json:"StartTime"` - EndTime string `json:"EndTime"` - } `json:"Period"` - - Datas []struct { - Code string `json:"Code"` // 统计编码 如:SMFHA01 - KPIs []struct { - KPIID string `json:"KPIID"` // 指标项, 如: SMF.AttCreatePduSession._Dnn - KPIValues []struct { - Name string `json:"Name"` // 单个的写"Total", 或者指标项有多个测量项,如Dnn的名称写对应的Dnn"cmnet"/"ims" - Value int64 `json:"Value"` - } `json:"KPIValues"` - } `json:"KPIs"` - } `json:"Datas"` - } `json:"Report"` -} - -func GetMeasureTask(taskId int) (*MeasureTask, error) { - log.Debug("GetMeasureTask processing... ") - - measureTask := new(MeasureTask) - tx := db.DB("").Table("measure_task").Where("id=?", taskId).Find(measureTask) - if tx.Error != nil { - log.Error("Failed to get table measure_task from database:", tx.Error) - - return nil, tx.Error - } - - log.Debug("Measure Task:", measureTask) - return measureTask, nil -} - -func XormGetActiveMeasureTask(measureTasks *[]MeasureTask) (*[]MeasureTask, error) { - log.Debug("XormGetActiveMeasureTask processing... ") - tx := db.DB("").Table("measure_task").Where("status='Active'").Find(measureTasks) - if tx.Error != nil { - log.Error("Failed to get table measure_task:", tx.Error) - return nil, tx.Error - } - - log.Debug("measureTasks:", measureTasks) - return measureTasks, nil -} - -type MeasureData struct { - // Id int `json:"id" xorm:"pk 'id' autoincr"` - Id int `json:"id" xorm:"-"` - Date string `json:"date" xorm:"date"` - TaskId int `json:"taskId"` - NeType string `json:"neType" xorm:"ne_type"` - NeName string `json:"neName" xorm:"ne_name"` - RmUid string `json:"rmUid" xorm:"rm_uid"` - GranulOption string `json:"granulOption" xorm:"granul_option"` - StartTime string `json:"startTime"` - EndTime string `json:"endTime"` - KpiCode string `json:"kpiCode" xorm:"kpi_code"` - KpiId string `json:"kpiId" xorm:"kpi_id"` - KpiExt string `json:"kpiExt" xorm:"kpi_ext"` - Value int64 `json:"value"` - Timestamp string `json:"timestamp"` -} - -// process measure report from NFs -func PostMeasureReportFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostMeasureReportFromNF processing... ") - - // vars := mux.Vars(r) - // neType := vars["elementTypeValue"] - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - log.Error("Uri api version is invalid. apiVersion:", apiVer) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Faile to io.ReadAll: ", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Debug("Request body:", string(body)) - measureReport := new(MeasureReport) - _ = json.Unmarshal(body, &measureReport) - log.Debug("measureReport:", measureReport) - - measureData := new(MeasureData) - layout := global.DateTime - measureData.Date = GetDateFromTimeString(layout, measureReport.Report.Period.StartTime) - measureData.TaskId = measureReport.Id - measureData.StartTime = measureReport.Report.Period.StartTime - measureData.EndTime = measureReport.Report.Period.EndTime - measureData.NeType = measureReport.NeType - measureData.NeName = measureReport.NeName - measureData.RmUid = measureReport.RmUID - measureData.GranulOption, _ = dborm.XormGetSingleCol("measure_task", "granul_option", fmt.Sprintf("id=%d", measureReport.Id)) - t, _ := strconv.ParseInt(measureReport.TimeStamp, 10, 64) - timestamp := time.Unix(t, 0) - log.Debug("timestamp:", timestamp.Format(layout)) - measureData.Timestamp = timestamp.Format(layout) - log.Debug("Datas:", measureReport.Report.Datas) - for _, d := range measureReport.Report.Datas { - measureData.KpiCode = d.Code - - log.Debug("KPIs:", d.KPIs) - for _, k := range d.KPIs { - measureData.KpiId = k.KPIID - - log.Debug("KPIValues:", k.KPIValues) - if len(k.KPIValues) != 0 { - for _, v := range k.KPIValues { - measureData.KpiExt = v.Name - measureData.Value = v.Value - log.Debug("measureData:", measureData) - - err := db.DB("").Create(measureData).Error - if err != nil { - log.Error("Failed to insert measure_data:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - } - } else { - measureData.Value = 0 - log.Debug("measureData:", measureData) - - err := db.DB("").Create(measureData).Error - if err != nil { - log.Error("Failed to insert measure_data:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - } - } - } - - services.ResponseStatusOK204NoContent(w) -} - -func PostMeasureTaskToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostMeasureTaskToNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - params := r.URL.Query() - taskIds := params["id"] - log.Debug("taskIds:", taskIds) - - var response *resty.Response - client := resty.New() - measureTask := new(MeasureTask) - measureTask.Tasks = make([]Task, 1) - for _, taskId := range taskIds { - id, _ := strconv.Atoi(taskId) - task, err := GetMeasureTask(id) - if err != nil { - log.Error("Failed to connect database: ", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - log.Debug("Table Task:", task) - - measureTask.Tasks[0].Id = task.Id - measureTask.Tasks[0].StartTime = task.StartTime - measureTask.Tasks[0].EndTime = task.EndTime - // v := new(dborm.ScheduleJson) - // _ = json.Unmarshal(task.Schedule, v) - // measureTask.Task[0].Schedule.Type = v.Type - // measureTask.Task[0].Schedule.Days = v.Days - if len(task.Schedule) >= 1 { - measureTask.Tasks[0].Schedule.Type = task.Schedule[0].Type - measureTask.Tasks[0].Schedule.Days = task.Schedule[0].Days - } - //v := new(dborm.ScheduleJ) - //_ = json.Unmarshal(task.Schedule, v) - measureTask.Tasks[0].Schedule.Periods = task.Periods - measureTask.Tasks[0].GranulOption = task.GranulOption - - measureTask.Tasks[0].KPISet = task.KpiSet - ips, err := global.GetIps() - if err != nil { - log.Error("Failed to get local IP:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("ips:", ips) - - measureTask.NotifyUrl = global.SetNotifyUrl(ips[0], 33030, fmt.Sprintf(MeasureReportFmt, neType)) - log.Debug("Measure Task to NF:", measureTask) - - if len(task.NeIds) == 0 { - var neInfos []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType(neType, &neInfos) - if err != nil { - log.Error("Failed to dborm.XormGetNeInfoByNeType:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - for _, neInfo := range neInfos { - task.NeIds = append(task.NeIds, neInfo.NeId) - } - } - - for _, neId := range task.NeIds { - var err error - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to dborm.XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - if neInfo == nil { - err := fmt.Errorf("not found target NE neType=%s, neId=%s", neType, neId) - log.Error(err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: POST ", requestURI2NF) - - switch task.Status { - case dborm.MeasureTaskStatusInactive: - body, _ := json.Marshal(measureTask) - log.Debug("body: ", string(body)) - - log.Debug("User-Agent: ", config.GetDefaultUserAgent()) - response, err = client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - SetContentLength(true). - Post(requestURI2NF) - - if err != nil { - log.Error("Post to NF failed:", err) - services.ResponseInternalServerError500NFConnectRefused(w) - return - } - log.Debug("response info: ") - log.Debug("Status Code:", response.StatusCode()) - log.Debug("Status:", response.Status()) - log.Debug("Proto:", response.Proto()) - log.Debug("Time:", response.Time()) - log.Debug("Received At:", response.ReceivedAt()) - log.Debug("Size:", response.Size()) - - case dborm.MeasureTaskStatusSuspend: - body, _ := json.Marshal(measureTask) - log.Debug("body: ", string(body)) - response, err = client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - SetContentLength(true). - Put(requestURI2NF) - - if err != nil { - log.Error("Put to NF failed:", err) - services.ResponseInternalServerError500NFConnectRefused(w) - return - } - default: - err = fmt.Errorf("measure task status must be inactive id=%d", id) - log.Error("Unable to active measure task:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - log.Debug("StatusCode: ", response.StatusCode()) - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusActive - taskInfo.CreateTime = time.Now().Format(time.DateTime) - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - default: - log.Error("NF return failure to active measure task") - if response != nil { - log.Info("response body:", string(response.Body())) - services.TransportResponse(w, response.StatusCode(), response.Body()) - return - } else { - err = fmt.Errorf("failed to active measure task, NF return error status=%v", response.Status()) - log.Error("Unable to active measure task:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - } - } - } - - services.ResponseStatusOK204NoContent(w) -} - -func PutMeasureTaskToNF(w http.ResponseWriter, r *http.Request) { - - services.ResponseStatusOK200Null(w) -} - -func DeleteMeasureTaskToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("DeleteMeasureTaskToNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - params := r.URL.Query() - taskIds := params["id"] - log.Debug("taskIds:", taskIds) - - var response *resty.Response - respMsg := make(map[string]interface{}) - for _, taskId := range taskIds { - id, _ := strconv.Atoi(taskId) - task, err := GetMeasureTask(id) - if err != nil { - log.Error("Failed to connect database: ", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - log.Debug("Measure Task:", task) - - if len(task.NeIds) == 0 { - var neInfos []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType(neType, &neInfos) - if err != nil { - log.Error("Failed to dborm.XormGetNeInfoByNeType:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - for _, neInfo := range neInfos { - task.NeIds = append(task.NeIds, neInfo.NeId) - } - } - log.Debug("neIds:", task.NeIds) - if len(task.NeIds) == 0 { - log.Warn("Not found target NE in the measure task") - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusDeleted - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - services.ResponseStatusOK204NoContent(w) - return - } - - for _, neId := range task.NeIds { - var err error - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - if neInfo != nil { - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: DELETE ", requestURI2NF) - client := resty.New() - response, err = client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Delete(requestURI2NF) - if err != nil { - // to avoid can't delete the task for abnormal NF - log.Error("Failed to resty delete:", err) - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusDeleted - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - services.ResponseStatusOK204NoContent(w) - return - } - - log.Info("StatusCode: ", response.StatusCode()) - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusDeleted - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Infof("Not record affected in measure_task") - } - services.ResponseStatusOK204NoContent(w) - return - default: - log.Info("response body:", string(response.Body())) - body := new(map[string]interface{}) - _ = json.Unmarshal(response.Body(), &body) - respMsg["error"] = body - } - } else { - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusDeleted - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - services.ResponseStatusOK204NoContent(w) - return - } - } - } - - services.ResponseWithJson(w, response.StatusCode(), respMsg) -} - -func PatchMeasureTaskToNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PatchMeasureTaskToNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - params := r.URL.Query() - taskIds := params["id"] - log.Debug("taskIds:", taskIds) - - var response *resty.Response - respMsg := make(map[string]interface{}) - for _, taskId := range taskIds { - id, _ := strconv.Atoi(taskId) - task, err := GetMeasureTask(id) - if err != nil { - log.Error("Failed to connect database: ", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - log.Debug("Measure Task:", task) - - // for neType - if len(task.NeIds) == 0 { - var neInfos []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType(neType, &neInfos) - if err != nil { - log.Error("Failed to dborm.XormGetNeInfoByNeType:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - for _, neInfo := range neInfos { - task.NeIds = append(task.NeIds, neInfo.NeId) - } - } - - if len(task.NeIds) == 0 { - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusInactive - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - services.ResponseStatusOK204NoContent(w) - return - } - - for _, neId := range task.NeIds { - var err error - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - if neInfo == nil { - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusInactive - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - services.ResponseStatusOK204NoContent(w) - //services.ResponseInternalServerError500ProcessError(w, em) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: PATCH ", requestURI2NF) - client := resty.New() - response, err = client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Patch(requestURI2NF) - if err != nil { - log.Error("Patch to NF failed:", err) - services.ResponseInternalServerError500NFConnectRefused(w) - return - } - - log.Debug("StatusCode: ", response.StatusCode()) - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - taskInfo := new(MeasureTask) - taskInfo.Status = dborm.MeasureTaskStatusInactive - affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo) - if err != nil { - log.Error("dborm.XormUpdateTableById is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } else if affected <= 0 { - log.Info("Not record affected in measure_task") - } - default: - log.Debug("response body:", string(response.Body())) - body := new(map[string]interface{}) - _ = json.Unmarshal(response.Body(), &body) - respMsg["error"] = body - } - } - } - - services.ResponseWithJson(w, response.StatusCode(), respMsg) -} - -type Measurement struct { - Id int `json:"-" xorm:"pk 'id' autoincr"` - Date string `json:"-" xorm:"date"` - Index int `json:"Index"` // 1天中测量时间粒度(如15分钟)的切片索引: 0~95 - Timestamp string `json:"TimeStamp" xorm:"-"` - NeName string `json:"NeName"` // UserLabel - RmUID string `json:"RmUID" xorm:"rm_uid"` - NeType string `json:"NeType"` // 网元类型 - PmVersion string `json:"PmVersion"` // 性能数据版本号 - Dn string `json:"Dn"` // (???)网元标识, 如:RJN-CMZJ-TZ,SubNetwork=5GC88,ManagedElement=SMF53456,SmfFunction=53456 - Period string `json:"Period"` // 测量时间粒度选项:5/15/30/60 - TimeZone string `json:"TimeZone"` - StartTime string `json:"StartTime"` - - Datas []Data `json:"Datas"` -} - -type KPIValue struct { - Name string `json:"Name"` // 单个的写"Total", 或者指标项有多个测量项,如Dnn的名称写对应的Dnn"cmnet"/"ims" - Value int64 `json:"Value"` -} - -type KPI struct { - KPIID string `json:"KPIID"` // 指标项, 如: SMF.AttCreatePduSession._Dnn - KPIValues []KPIValue `json:"KPIValues"` -} - -type Data struct { - ObjectType string `json:"ObjectType"` // 网络资源类别名称, Pm指标项列表中为空间粒度 如:SmfFunction - KPIs []KPI `json:"KPIs"` // 指标项, 如: SMF.AttCreatePduSession._Dnn -} - -// process measurement post message from NFs -func PostMeasurementFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("PostMeasurementFromNF processing... ") - - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - log.Error("Uri api version is invalid. apiVersion:", apiVer) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Faile to io.ReadAll: ", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - log.Debug("Request body:", string(body)) - // measurement := new(dborm.NorthboundPm) - measurement := new(dborm.NorthboundPm) - _ = json.Unmarshal(body, &measurement) - log.Debug("measurement:", measurement) - - // layout := global.DateTime - layout := time.RFC3339 - measurement.Date = GetDateFromTimeString(layout, measurement.StartTime) - measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime) - // tx := db.DB("").Table("nbi_pm").Create(measurement) - // if tx.Error != nil && tx.RowsAffected <= 0 { - // log.Error("Failed to insert nbi_pm:", err) - // services.ResponseInternalServerError500DatabaseOperationFailed(w) - // return - // } - - services.ResponseStatusOK204NoContent(w) -} - -// get measurement message from NFs -func GetMeasurementFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetMeasurementFromNF processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - log.Error("Uri api version is invalid. apiVersion:", apiVer) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neType := vars["elementTypeValue"] - if neType == "" { - log.Error("elementTypeValue is null.") - services.ResponseNotFound404UriNotExist(w, r) - return - } - params := r.URL.Query() - neIds := params["ne_id"] - if len(neIds) == 0 { - log.Error("ne_id NOT FOUND") - services.ResponseBadRequest400WrongParamValue(w) - return - } - log.Debugf("neType: %s neId:%s", neType, neIds) - - //var neInfo *dborm.NeInfo - neInfo := new(dborm.NeInfo) - - neInfo, err := dborm.XormGetNeInfo(neType, neIds[0]) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF: GET ", requestURI2NF) - - client := resty.New() - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Failed to Get from NF:", err) - services.ResponseInternalServerError500NFConnectRefused(w) - return - } - - respMsg := make(map[string]interface{}) - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - log.Debug("response:", response) - // measurement := new(dborm.NorthboundPm) - measurement := new(dborm.NorthboundPm) - _ = json.Unmarshal(response.Body(), &measurement) - log.Debug("measurement:", measurement) - - layout := time.RFC3339 - measurement.Date = GetDateFromTimeString(layout, measurement.StartTime) - measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime) - // tx := db.DB("").Table("nbi_pm").Create(measurement) - // if tx.Error != nil && tx.RowsAffected <= 0 { - // log.Error("Failed to insert nbi_pm:", err) - // services.ResponseInternalServerError500DatabaseOperationFailed(w) - // return - // } - default: - log.Debug("response body:", string(response.Body())) - body := new(map[string]interface{}) - _ = json.Unmarshal(response.Body(), &body) - respMsg["error"] = body - } - - services.ResponseWithJson(w, response.StatusCode(), respMsg) -} diff --git a/features/pm/service.go b/features/pm/service.go deleted file mode 100644 index ff2a6539..00000000 --- a/features/pm/service.go +++ /dev/null @@ -1,19 +0,0 @@ -package pm - -import ( - "be.ems/features/pm/kpi_c_report" - "be.ems/features/pm/kpi_c_title" - "be.ems/lib/log" - "github.com/gin-gonic/gin" -) - -func InitSubServiceRoute(r *gin.Engine) { - log.Info("======init PM group gin.Engine") - - pmGroup := r.Group("/pm") - // register sub modules routes - kpi_c_title.Register(pmGroup) - kpi_c_report.Register(pmGroup) - - // return featuresGroup -} diff --git a/features/security/account.go b/features/security/account.go deleted file mode 100644 index 919b2bc7..00000000 --- a/features/security/account.go +++ /dev/null @@ -1,176 +0,0 @@ -package security - -import ( - "encoding/json" - "io" - "net/http" - "strings" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/oauth" - "be.ems/lib/services" -) - -var ( - UriOauthToken = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token" - UriOauthHandshake = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake" - - CustomUriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token" - CustomUriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake" -) - -func LoginFromOMC(w http.ResponseWriter, r *http.Request) { - log.Info("LoginFromOMC processing... ") - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("Failed to ReadAll:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // check media type(content type) only support "application/json" - if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // // check extend uri, response 404 - // if !IsValidOAuthUri(r) { - // log.Debug("Uri is invalid") - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - - // Error process .... - // response 400-7 - if !json.Valid([]byte(body)) { - log.Error("Invalid Json Format") - services.ResponseBadRequest400InvalidJson(w) - return - } - - var oAuthBody oauth.OAuthBody - _ = json.Unmarshal(body, &oAuthBody) //转为json - //log.Debug("body:", string(body), "oAuthBody:", oAuthBody) - - defer r.Body.Close() - // response 400-5 - if oauth.IsWrongOAuthInfo(oAuthBody) { - log.Error("Wrong parameter value") - services.ResponseBadRequest400WrongParamValue(w) - return - } - /* - if oauth.IsValidOAuthInfo(oAuthBody) { - plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType) - log.Debug("Permission list:", plist) - - token := globalSession.NewSession(w, r, plist) - services.ResponseStatusOK200Login(w, token) - } else { - // response 400-4 - log.Debug("Authentication failed, mismatch user or password") - - services.ResponseBadRequest400IncorrectLogin(w) - } - */ - - token := oauth.GenRandToken("omc") // Generate new token to session ID - sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")] - affected, err := dborm.XormInsertSession(oAuthBody.UserName, sourceAddr, token, - config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session) - if err != nil { - log.Error("Failed to XormInsertSession:", err) - if affected == -1 { - services.ResponseForbidden403MultiLoginNotAllowed(w) - } else { - services.ResponseBadRequest400IncorrectLogin(w) - } - - return - } - - services.ResponseBadRequest400IncorrectLogin(w) -} - -func LogoutFromOMC(w http.ResponseWriter, r *http.Request) { - log.Info("LogoutFromOMC processing... ") - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // // check media type(content type) only support "application/json" - // if services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) == false { - // log.Error("Invalid Content-Type") - // services.ResponseUnsupportedMediaType415(w) - // return - // } - - // // check extend uri, response 404 - // if !services.IsValidOAuthUri(r) { - // log.Error("Uri is invalid") - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - - // // error processing ... - // // 401-1 response - // token, ret := oauth.IsCarriedToken(r) - // if ret == false { - // log.Error("AccessToken is not carried") - // services.ResponseUnauthorized401AccessTokenNotCarried(w) - // return - // } - - // se, err := dborm.XormLogoutUpdateSession(token) - // if err != nil { - // log.Error("Uri is invalid") - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - // 清除缓存用户信息 - // account.ClearLoginUser(se.AccountId) - services.ResponseStatusOK200Null(w) -} - -func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) { - log.Info("HandshakeFromOMC processing... ") - - // check media type(content type) only support "application/json" - if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) { - log.Debug("Invalid Content-Type") - services.ResponseUnsupportedMediaType415(w) - return - } - - // check extend uri, response 404 - if !services.IsValidOAuthUri(r) { - log.Error("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // error processing ... - // 401-1 response - token, ret := oauth.IsCarriedToken(r) - if !ret { - log.Error("AccessToken is not carried") - services.ResponseUnauthorized401AccessTokenNotCarried(w) - return - } - - _, err := dborm.XormUpdateSessionShakeTime(token) - if err != nil { - log.Error("Uri is invalid") - services.ResponseNotFound404UriNotExist(w, r) - return - } - services.ResponseStatusOK200Null(w) -} diff --git a/features/sm/backup.go b/features/sm/backup.go deleted file mode 100644 index 6795c10c..00000000 --- a/features/sm/backup.go +++ /dev/null @@ -1,45 +0,0 @@ -package sm - -import ( - "net/http" - "time" - - "be.ems/lib/config" - "be.ems/lib/log" - "be.ems/lib/services" - _ "github.com/go-sql-driver/mysql" -) - -var ( - // Get OMC local time - UriOMCLocalTime = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/OMC/objectType/time" - - CustomUriOMCLocalTime = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/OMC/objectType/time" -) - -type OMCLocalTime struct { - Timestamp int64 `json:"timestamp"` // 时间戳 (单位:毫秒) - TimeZone int `json:"timeZone"` // 本地时区偏移(单位:秒) -} - -func GetOMCLocalTime(w http.ResponseWriter, r *http.Request) { - log.Debug("GetOMCLocalTime processing... ") - - // _, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Http request error:", err) - // return - // } - - t := time.Now() - _, offset := t.Zone() - - localTime := OMCLocalTime{ - Timestamp: t.UnixMilli(), - TimeZone: offset, - } - response := services.DataResponse{ - Data: localTime, - } - services.ResponseWithJson(w, http.StatusOK, response) -} diff --git a/features/state/getstate.go b/features/state/getstate.go deleted file mode 100644 index 9e7519e3..00000000 --- a/features/state/getstate.go +++ /dev/null @@ -1,1012 +0,0 @@ -package state - -import ( - "encoding/json" - "fmt" - "net/http" - "os" - "strconv" - "strings" - "time" - - "github.com/go-resty/resty/v2" - "github.com/gorilla/mux" - "github.com/shirou/gopsutil/v4/net" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - cfg "be.ems/src/framework/config" - "be.ems/src/framework/constants" - "be.ems/src/framework/database/db" - "be.ems/src/framework/utils/parse" -) - -type CpuUsage struct { - NfCpuUsage uint16 `json:"nfCpuUsage"` - SysCpuUsage uint16 `json:"sysCpuUsage"` -} - -type MemUsage struct { - TotalMem uint32 `json:"totalMem"` - NfUsedMem uint32 `json:"nfUsedMem"` - SysMemUsage uint16 `json:"sysMemUsage"` -} - -type PartitionInfo struct { - Total uint32 `json:"total"` // MB - Used uint32 `json:"used"` // MB -} - -type DiskSpace struct { - PartitionNum uint8 `json:"partitionNum"` - PartitionInfo []PartitionInfo `json:"partitionInfo"` -} - -type HardwareInfo struct { - CPUs int `json:"cpus"` - Memory int `json:"memory"` -} - -type SysState struct { - HostName string `json:"hostName"` // linux命令: hostname - OsInfo string `json:"osInfo"` // linux命令: uname -a - DbInfo string `json:"dbInfo"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version - Version string `json:"version"` // 软件版本信息: 16.1.1 - IpAddr []string `json:"ipAddr"` // 网管的ipv4和ipv6列表 - Port uint16 `json:"port"` // 用于网管的port - Capability uint32 `json:"capability"` - SerialNum string `json:"serialNum"` - ExpiryDate string `json:"expiryDate"` - HardwareInfo HardwareInfo `json:"hardwareInfo"` - CpuUsage CpuUsage `json:"cpuUsage"` - MemUsage MemUsage `json:"memUsage"` - DiskSpace DiskSpace `json:"diskSpace"` - //Timestamp string `json:"timestamp"` -} - -type SystemState struct { - HostName string `json:"hostName"` // linux命令: hostname - OsInfo string `json:"osInfo"` // linux命令: uname -a - DbInfo string `json:"dbInfo"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version - Version string `json:"version"` // 软件版本信息: 16.1.1 - IpAddr []string `json:"ipAddr"` // 网管的ipv4和ipv6列表 - Port uint16 `json:"port"` // 用于网管的port - Capability uint32 `json:"capability"` - SerialNum string `json:"serialNum"` - ExpiryDate string `json:"expiryDate"` - HardwareInfo struct { - CPUs int `json:"cpus"` // 主机(裸机/虚拟机)的cpu个数 - Memory int `json:"memory"` // 主机(裸机/虚拟机): 配置的内存 - } `json:"hardwareInfo"` - CpuUsage struct { - NfCpuUsage uint16 `json:"nfCpuUsage"` - SysCpuUsage uint16 `json:"sysCpuUsage"` - } `json:"cpuUsage"` - MemUsage struct { - TotalMem uint32 `json:"totalMem"` - NfUsedMem uint32 `json:"nfUsedMem"` - SysMemUsage uint16 `json:"sysMemUsage"` - } `json:"memUsage"` - DiskSpace struct { - PartitionNum uint8 `json:"partitionNum"` - PartitionInfo []struct { - Total uint32 `json:"total"` // MB - Used uint32 `json:"used"` // MB - } `json:"partitionInfo"` - } `json:"diskSpace"` - //Timestamp string `json:"timestamp"` -} - -type SystemInfo struct { - NeType string `json:"neType" map:"neType, omitempty"` - NeId string `json:"neId" map:"neId, omitempty"` - HostName string `json:"hostName" map:"hostName, omitempty"` // linux命令: hostname - OsInfo string `json:"osInfo" map:"osInfo, omitempty"` // linux命令: uname -a - DbInfo string `json:"dbInfo" map:"dbInfo, omitempty"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version - Version string `json:"version" map:"version, omitempty"` // 软件版本信息: 16.1.1 - IpAddr string `json:"ipAddr" map:"ipAddr, omitempty"` // 网管的ipv4和ipv6列表 - Port uint16 `json:"port" map:"port, omitempty"` // 用于网管的port - CPUs int `json:"cpus" map:"cpus, omitempty"` - TotalMem int `json:"totalMem" map:"totalMem, omitempty"` - PvFlag string `json:"pvFlag" map:"pvFlag, omitempty"` - Status string `json:"status" map:"status, omitempty"` -} - -type LicenseInfo struct { - NeType string `json:"neType"` - NeId string `json:"neId"` - SerialNum string `json:"serialNum"` - Capability uint32 `json:"capability"` - CapUsed uint32 `json:"capUsed"` - FeatureEnabled []string `json:"featureEnabled"` - ExpiryDate string `json:"expiryDate"` -} - -type Response struct { - Data interface{} `json:"data"` -} - -var ( - UriSysState = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/systemState" - UriSysState2 = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/systemState" - UriSysInfoAll = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/sysInfo" - UriSysInfoOne = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/sysInfo/{neType}/{neId}" - UriLicenseInfoAll = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/licenseInfo" - UriLicenseInfoOne = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/licenseInfo/{neType}/{neId}" - - CustomUriSysState = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/systemState" - CustomUriSysState2 = config.UriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/systemState" - CustomUriSysInfoAll = config.UriPrefix + "/systemManagement/{apiVersion}/sysInfo" - CustomUriSysInfoOne = config.UriPrefix + "/systemManagement/{apiVersion}/sysInfo/{neType}/{neId}" - CustomUriLicenseInfoAll = config.UriPrefix + "/systemManagement/{apiVersion}/licenseInfo" - CustomUriLicenseInfoOne = config.UriPrefix + "/systemManagement/{apiVersion}/licenseInfo/{neType}/{neId}" -) - -var client = resty.New() - -func init() { - /* - client. - SetTimeout(10 * time.Second). - SetRetryCount(1). - SetRetryWaitTime(1 * time.Second). - SetRetryMaxWaitTime(2 * time.Second). - SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) { - return 0, errors.New("quota exceeded") - }) - */ - client. - SetTimeout(time.Duration(400 * time.Millisecond)) - // SetRetryCount(1). - // SetRetryWaitTime(time.Duration(1 * time.Second)). - // SetRetryMaxWaitTime(time.Duration(2 * time.Second)) - //client.SetTimeout(2 * time.Second) -} - -func NeStatusEnumToStr(intStatus int) string { - switch intStatus { - case 0: - return "active" - case 1: - return "offline" - case 2: - return "standby" - case 3: - return "maintain" - default: - return "unkown" - } -} - -// Get system state from NF/NFs -func GetOneLicenseInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetOneLicenseInfoFromNF processing... ") - - data := make([]map[string]interface{}, 0) - - vars := mux.Vars(r) - neType := vars["neType"] - neId := vars["neId"] - if neType == "" || neId == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("AccessToken:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - //systemState := make(map[string]interface{}) - systemState := &SysState{} - var result map[string]interface{} - //sysInfo := &SystemInfo{} - omcNeTypeLower := "omc" - if config.GetYamlConfig().OMC.NeType != "" { - omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType) - } - if neType != omcNeTypeLower { - log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower) - var requestURI2NF string - if config.GetYamlConfig().OMC.TestMode && strings.ToLower(neType) != "udm" { - var udmNEs []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - if len(udmNEs) > 0 { - udmNe := udmNEs[0] - hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(udmNe.NeType)) - } - } else { - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(neInfo.NeType)) - } - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Failed to get system state:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - log.Trace("resp.Body():", string(resp.Body())) - _ = json.Unmarshal(resp.Body(), &systemState) - - log.Trace("systemState:", systemState) - capUsed := config.TDatas[neInfo.NeType].CapUsed - log.Tracef("neInfo.NeType:%s capUsed: %v", capUsed) - licenseInfo := &LicenseInfo{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - SerialNum: systemState.SerialNum, - Capability: systemState.Capability, - CapUsed: capUsed, - FeatureEnabled: config.TDatas[neInfo.NeType].FeatureEnabled, - ExpiryDate: systemState.ExpiryDate, - } - //neItem := strings.ToUpper(neType) + "/" + neId - result, err = global.ToMap(*licenseInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - } - } else { - systemState := GetEMSState(neInfo.Ip) - licenseInfo := &LicenseInfo{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - SerialNum: systemState.SerialNum, - Capability: systemState.Capability, - CapUsed: config.TDatas[neInfo.NeType].CapUsed, - FeatureEnabled: config.TDatas[neInfo.NeType].FeatureEnabled, - ExpiryDate: systemState.ExpiryDate, - } - result, err = global.ToMap(*licenseInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - // neItem := strings.ToUpper(neType) + "/" + neId - // result[neItem] = sysInfo - } - - data = append(data, result) - log.Trace("data:", data) - - var response Response - response.Data = data - services.ResponseWithJson(w, http.StatusOK, response) -} - -// Get system state from NF/NFs -func GetAllLicenseInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetAllLicenseInfoFromNF processing... ") - - data := make([]map[string]interface{}, 0) - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("AccessToken:", token) - - var neList []dborm.NeInfo - _, err := dborm.XormGetAllNeInfo(&neList) - if err != nil { - log.Error("Failed to XormGetAllNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - omcNeTypeLower := "omc" - if config.GetYamlConfig().OMC.NeType != "" { - omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType) - } - - for _, ne := range neList { - var result map[string]interface{} - log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower) - log.Debug("ne: ", ne) - //if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) { - if strings.ToLower(ne.NeType) != omcNeTypeLower { - // hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port) - // requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - // hostUri, strings.ToLower(ne.NeType)) - var requestURI2NF string - if config.GetYamlConfig().OMC.TestMode && strings.ToLower(ne.NeType) != "udm" { - var udmNEs []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - if len(udmNEs) > 0 { - udmNe := udmNEs[0] - hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(udmNe.NeType)) - } - } else { - hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(ne.NeType)) - } - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.SetTimeout(time.Duration(1 * time.Second)).R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - // errorMessage := services.ErrorMessage{ - // ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused", - // } - // //result["error"] = errorMessage - continue - } else { - systemState := &SysState{} - _ = json.Unmarshal(resp.Body(), &systemState) - licenseInfo := &LicenseInfo{ - NeType: ne.NeType, - NeId: ne.NeId, - SerialNum: systemState.SerialNum, - Capability: systemState.Capability, - CapUsed: config.TDatas[ne.NeType].CapUsed, - FeatureEnabled: config.TDatas[ne.NeType].FeatureEnabled, - ExpiryDate: systemState.ExpiryDate, - } - result, err = global.ToMap(*licenseInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - // neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId - // result[neItem] = sysInfo - } - } else { - systemState := GetEMSState(ne.Ip) - licenseInfo := &LicenseInfo{ - NeType: ne.NeType, - NeId: ne.NeId, - SerialNum: systemState.SerialNum, - Capability: systemState.Capability, - CapUsed: config.TDatas[ne.NeType].CapUsed, - FeatureEnabled: config.TDatas[ne.NeType].FeatureEnabled, - ExpiryDate: systemState.ExpiryDate, - } - result, err = global.ToMap(*licenseInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - // neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId - // result[neItem] = sysInfo - } - - data = append(data, result) - log.Trace("data:", data) - } - - var response Response - response.Data = data - services.ResponseWithJson(w, http.StatusOK, response) -} - -// Get system state from NF/NFs -func GetOneSysinfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetOneSysinfoFromNF processing... ") - - data := make([]map[string]interface{}, 0) - - vars := mux.Vars(r) - neType := vars["neType"] - neId := vars["neId"] - if neType == "" || neId == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("AccessToken:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - //systemState := make(map[string]interface{}) - systemState := &SysState{} - var result map[string]interface{} - //sysInfo := &SystemInfo{} - omcNeTypeLower := "omc" - if config.GetYamlConfig().OMC.NeType != "" { - omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType) - } - if neType != omcNeTypeLower { - log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower) - var requestURI2NF string - if config.GetYamlConfig().OMC.TestMode && strings.ToLower(neType) != "udm" { - var udmNEs []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - if len(udmNEs) > 0 { - udmNe := udmNEs[0] - hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(udmNe.NeType)) - } - } else { - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(neInfo.NeType)) - } - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - log.Trace("resp.Body():", string(resp.Body())) - _ = json.Unmarshal(resp.Body(), &systemState) - - log.Trace("systemState:", systemState) - hostName := "5gc" - if systemState.HostName != "" { - hostName = systemState.HostName - } - osInfo := "Linux 5gc 4.15.0-29-generic SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux" - if systemState.OsInfo != "" { - osInfo = systemState.OsInfo - } - dbInfo := "db v1.4.15" - if systemState.OsInfo != "" { - dbInfo = systemState.DbInfo - } - port, _ := strconv.Atoi(neInfo.Port) - cpus := 4 - if systemState.HardwareInfo.CPUs != 0 { - cpus = systemState.HardwareInfo.CPUs - } - totalMem := 34029125632 - if systemState.HardwareInfo.Memory != 0 { - totalMem = systemState.HardwareInfo.Memory - } - sysInfo := &SystemInfo{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - HostName: hostName, - OsInfo: osInfo, - DbInfo: dbInfo, - Version: systemState.Version, - IpAddr: neInfo.Ip, - Port: uint16(port), - CPUs: cpus, - TotalMem: totalMem, - PvFlag: neInfo.PvFlag, - Status: NeStatusEnumToStr(neInfo.Status), - } - //neItem := strings.ToUpper(neType) + "/" + neId - result, err = global.ToMap(*sysInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - } - } else { - systemState := GetEMSState(neInfo.Ip) - sysInfo := &SystemInfo{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - HostName: systemState.HostName, - OsInfo: systemState.OsInfo, - DbInfo: systemState.DbInfo, - Version: systemState.Version, - IpAddr: neInfo.Ip, - Port: systemState.Port, - CPUs: systemState.HardwareInfo.CPUs, - TotalMem: systemState.HardwareInfo.Memory, - PvFlag: neInfo.PvFlag, - Status: NeStatusEnumToStr(neInfo.Status), - } - result, err = global.ToMap(*sysInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - // neItem := strings.ToUpper(neType) + "/" + neId - // result[neItem] = sysInfo - } - - data = append(data, result) - log.Trace("data:", data) - - var response Response - response.Data = data - services.ResponseWithJson(w, http.StatusOK, response) -} - -// Get system state from NF/NFs -func GetAllSysinfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetAllSysinfoFromNF processing... ") - - data := make([]map[string]interface{}, 0) - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("AccessToken:", token) - - var neList []dborm.NeInfo - _, err := dborm.XormGetAllNeInfo(&neList) - if err != nil { - log.Error("Failed to XormGetAllNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - omcNeTypeLower := "omc" - if config.GetYamlConfig().OMC.NeType != "" { - omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType) - } - - for _, ne := range neList { - var result map[string]interface{} - log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower) - log.Debug("ne: ", ne) - //if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) { - if strings.ToLower(ne.NeType) != omcNeTypeLower { - // hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port) - // requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - // hostUri, strings.ToLower(ne.NeType)) - var requestURI2NF string - if config.GetYamlConfig().OMC.TestMode && strings.ToLower(ne.NeType) != "udm" { - var udmNEs []dborm.NeInfo - err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - if len(udmNEs) > 0 { - udmNe := udmNEs[0] - hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(udmNe.NeType)) - } - } else { - hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port) - requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(ne.NeType)) - } - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.SetTimeout(time.Duration(1 * time.Second)).R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - // errorMessage := services.ErrorMessage{ - // ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused", - // } - // //result["error"] = errorMessage - continue - } else { - systemState := &SysState{} - _ = json.Unmarshal(resp.Body(), &systemState) - hostName := "5gc" - if systemState.HostName != "" { - hostName = systemState.HostName - } - osInfo := "Linux 5gc 4.15.0-29-generic SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux" - if systemState.OsInfo != "" { - osInfo = systemState.OsInfo - } - dbInfo := "db v1.4.15" - if systemState.OsInfo != "" { - dbInfo = systemState.DbInfo - } - port, _ := strconv.Atoi(ne.Port) - cpus := 4 - if systemState.HardwareInfo.CPUs != 0 { - cpus = systemState.HardwareInfo.CPUs - } - totalMem := 34029125632 - if systemState.HardwareInfo.Memory != 0 { - totalMem = systemState.HardwareInfo.Memory - } - sysInfo := &SystemInfo{ - NeType: ne.NeType, - NeId: ne.NeId, - HostName: hostName, - OsInfo: osInfo, - DbInfo: dbInfo, - Version: systemState.Version, - IpAddr: ne.Ip, - Port: uint16(port), - CPUs: cpus, - TotalMem: totalMem, - PvFlag: ne.PvFlag, - Status: NeStatusEnumToStr(ne.Status), - } - // neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId - // result[neItem] = sysInfo - result, err = global.ToMap(*sysInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - } - } else { - port, _ := strconv.Atoi(ne.Port) - systemState := GetEMSState(ne.Ip) - sysInfo := &SystemInfo{ - NeType: ne.NeType, - NeId: ne.NeId, - HostName: systemState.HostName, - OsInfo: systemState.OsInfo, - DbInfo: systemState.DbInfo, - Version: systemState.Version, - IpAddr: ne.Ip, - Port: (uint16(port)), - CPUs: systemState.HardwareInfo.CPUs, - TotalMem: systemState.HardwareInfo.Memory, - PvFlag: ne.PvFlag, - Status: NeStatusEnumToStr(ne.Status), - } - // neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId - // result[neItem] = sysInfo - result, err = global.ToMap(*sysInfo, "json") - if err != nil { - log.Warn("Failed to map:", err) - } - } - - data = append(data, result) - log.Trace("data:", data) - } - - var response Response - response.Data = data - services.ResponseWithJson(w, http.StatusOK, response) -} - -// Get system state from NF/NFs -func GetStateFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetStateFromNF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - neType = strings.ToLower(neType) - - if neType == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - if neType == "all" { - var neList []dborm.NeInfo - _, err := dborm.XormGetAllNeInfo(&neList) - if err != nil { - log.Error("Failed to get all ne info:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - data := make([]map[string]interface{}, 0) - for _, ne := range neList { - result := make(map[string]interface{}) - hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port) - requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - hostUri, strings.ToLower(ne.NeType)) - log.Debug("requestURI2NF:", requestURI2NF) - - result["ipAddress"] = ne.Ip - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - //SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Fail to get state:", err) - - errorMessage := services.ErrorMessage{ - ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused", - } - systemState := make(map[string]interface{}) - systemState["error"] = errorMessage - result["systemState"] = systemState - } else { - systemState := make(map[string]interface{}) - _ = json.Unmarshal(resp.Body(), &systemState) - result["systemState"] = systemState - } - - neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId - mapState := make(map[string]interface{}) - mapState[neItem] = result - data = append(data, mapState) - log.Trace("data:", data) - } - var response Response - response.Data = data - services.ResponseWithJson(w, http.StatusOK, response) - return - } - - if neType == "omc" { - emsState := GetEMSState("127.0.0.1") - services.ResponseWithJson(w, http.StatusOK, emsState) - return - } - - // only support omc and all elementType - err := fmt.Errorf("only support omc or all elementTypeValue") - log.Error("Fail to get state:", err) - services.ResponseInternalServerError500ProcessError(w, err) - - // var neList []dborm.NeInfo - // err := dborm.XormGetNeInfoByNeType(neType, &neList) - // if err != nil { - // log.Error("Failed to dborm.XormGetNeInfoByNeType:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // var omcList []dborm.NeInfo - // err = dborm.XormGetNeInfoByNeType("omc", &omcList) - // if err != nil { - // log.Error("Failed to omc ne list:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - // for i, ne := range neList { - - // } - // data := make([]map[string]interface{}, 0) - // for _, ne := range neList { - // hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port) - // requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", - // hostUri, strings.ToLower(ne.NeType)) - // log.Debug("requestURI2NF:", requestURI2NF) - - // resp, err := client.R(). - // EnableTrace(). - // SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - // SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - // Get(requestURI2NF) - // if err != nil { - // log.Error("Get system state from NF is failed:", err) - // } else { - // systemState := make(map[string]interface{}) - // _ = json.Unmarshal(resp.Body(), &systemState) - // data = append(data, systemState) - // } - // } - - // if len(data) == 1 { - // services.ResponseWithJson(w, http.StatusOK, data[0]) - // return - // } - // var response Response - // response.Data = data - // services.ResponseWithJson(w, http.StatusOK, response) -} - -func GetEMSState(ip string) *SysState { - log.Debug("GetEMSState processing... ") - - sysInfo := new(SysInfo) - err := GetSysInfo(sysInfo) - if err != nil { - log.Error("Failed to GetSysInfo:", err) - return nil - } - - cpuUsage := &CpuUsage{ - NfCpuUsage: sysInfo.MyCpuPercent, - SysCpuUsage: sysInfo.SysCpuPercent, - } - - memUsage := &MemUsage{ - TotalMem: sysInfo.SysTotalRam, - NfUsedMem: sysInfo.MyUsedRam, - SysMemUsage: sysInfo.SysRamUsedPercent, - } - - diskSpace := &DiskSpace{ - PartitionNum: sysInfo.PartitionNum, - PartitionInfo: sysInfo.PartitionInfo, - } - - // 获取主机的 IP 地址列表 - ipAddrs := []string{ip} - if ip == "" || ip == "127.0.0.1" { - ipAddrs = []string{} - interfaces, err := net.Interfaces() - if err == nil { - for _, iface := range interfaces { - for _, v := range iface.Addrs { - name := iface.Name - if name[len(name)-1] == '0' { - name = name[0 : len(name)-1] - name = strings.Trim(name, "") - } - // ignore localhost - if name == "lo" { - continue - } - prefix := strings.Split(v.Addr, "/")[0] - if strings.Contains(prefix, "::") { - ipAddrs = append(ipAddrs, prefix) - } - if strings.Contains(prefix, ".") { - ipAddrs = append(ipAddrs, prefix) - } - } - } - } - } - - CapabilityInt := config.GetYamlConfig().OMC.Capability - if CapabilityInt == 0 { - CapabilityInt = 5000 - } - snStr := config.GetYamlConfig().OMC.Sn - if snStr == "" { - snStr = "-" - } - expiryDateStr := config.GetYamlConfig().OMC.ExpiryDate - if expiryDateStr == "" { - expiryDateStr = "-" - } - var port uint16 = 33030 - httpArr := cfg.Get("server") - if httpArr != nil { - arr := httpArr.([]any) - if len(arr) > 1 { - rest := arr[0].(map[string]any) - port = uint16(parse.Number(rest["port"])) - } - } - hostName, _ := os.Hostname() - dbInfo := getDbInfo() - emsState := &SysState{ - HostName: hostName, - OsInfo: getUnameStr(), - DbInfo: dbInfo, - IpAddr: ipAddrs, - Port: port, - Version: cfg.Version, - Capability: CapabilityInt, - SerialNum: snStr, - ExpiryDate: expiryDateStr, - HardwareInfo: HardwareInfo{CPUs: getCpuNumber(), Memory: getTotalMemory()}, - CpuUsage: *cpuUsage, - MemUsage: *memUsage, - DiskSpace: *diskSpace, - } - - //getSystemInfo() - return emsState -} - -func getDbInfo() string { - var dbConfig map[string]any - defSource := cfg.Get("database.defaultDataSourceName").(string) - datasource := cfg.Get("database.datasource").(map[string]any) - for key, value := range datasource { - item := value.(map[string]any) - if key == defSource { - dbConfig = item - break - } - } - - if dbConfig["type"] == "mysql" { - return getMySQLVersion() - } - if dbConfig["type"] == "sqlite" { - return "3.35.5 SQLite3" - } - return "" -} - -func getMySQLVersion() string { - var info string = "" - - var ver, verComment, verCompileOS, verCompile string - - // 版本 - m, err := db.RawDB("", "SHOW VARIABLES LIKE 'version'", nil) - if err != nil || len(m) != 1 { - return info - } - if v, ok := m[0]["Value"]; ok { - ver = v.(string) - } - - // 详细版本 - m, err = db.RawDB("", "SHOW VARIABLES LIKE 'version_comment'", nil) - if err != nil || len(m) != 1 { - return info - } - if v, ok := m[0]["Value"]; ok { - verComment = v.(string) - } - - // 编译操作系统 - m, err = db.RawDB("", "SHOW VARIABLES LIKE 'version_compile_os'", nil) - if err != nil || len(m) != 1 { - return info - } - if v, ok := m[0]["Value"]; ok { - verCompileOS = v.(string) - } - - // 编译机器 - m, err = db.RawDB("", "SHOW VARIABLES LIKE 'version_compile_machine'", nil) - if err != nil || len(m) != 1 { - return info - } - if v, ok := m[0]["Value"]; ok { - verCompileOS = v.(string) - } - - return fmt.Sprintf("%s %s, for %s (%s)", ver, verComment, verCompileOS, verCompile) -} diff --git a/features/state/state_linux.go b/features/state/state_linux.go deleted file mode 100644 index 30ed20d8..00000000 --- a/features/state/state_linux.go +++ /dev/null @@ -1,243 +0,0 @@ -//go:build linux -// +build linux - -package state - -import ( - "encoding/binary" - "fmt" - "os" - "runtime" - "syscall" - "time" - - "be.ems/lib/log" - "github.com/shirou/gopsutil/v4/cpu" - "github.com/shirou/gopsutil/v4/disk" - "github.com/shirou/gopsutil/v4/mem" - "github.com/shirou/gopsutil/v4/process" -) - -type SysInfo struct { - SysCpuPercent uint16 // x% - MyCpuPercent uint16 // x%, CPU percent of current proccess - - SysTotalRam uint32 // KB - MyUsedRam uint32 // RAM usage of current proccess, KB - SysRamUsedPercent uint16 // x% - - PartitionNum byte - PartitionInfo []PartitionInfo // usage of each partition -} - -const MAX_PARTITION_NUM byte = 32 - -func GetSysStat() ([]byte, int) { - // Get sys info - var sysInfo SysInfo - err := GetSysInfo(&sysInfo) - if err != nil { - return nil, 0 - } - - //log.Tracef("current sys info: %v", sysInfo) - - // build ems buffer - var data []byte = make([]byte, 1024) - var len int - var i byte - binary.BigEndian.PutUint16(data[0:], sysInfo.MyCpuPercent) //x% * 100 - binary.BigEndian.PutUint16(data[2:], sysInfo.SysCpuPercent) //x% * 100 - binary.BigEndian.PutUint32(data[4:], sysInfo.SysTotalRam) // KB - binary.BigEndian.PutUint32(data[8:], sysInfo.MyUsedRam) // KB - binary.BigEndian.PutUint16(data[12:], sysInfo.SysRamUsedPercent) //x% * 100 - data[14] = sysInfo.PartitionNum - for i = 0; i < sysInfo.PartitionNum; i++ { - binary.BigEndian.PutUint32(data[15+8*(i):], sysInfo.PartitionInfo[i].Total) // MB - binary.BigEndian.PutUint32(data[15+8*(i)+4:], sysInfo.PartitionInfo[i].Used) // MB - } - len = int(15 + 8*sysInfo.PartitionNum) - - //log.Tracef("current sys stat buf: %v, len: %d", data, len) - - return data, len -} - -var pProc *process.Process = nil - -func GetSYsCpuPercent() float64 { - totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false) - if err != nil { - return 0.0 - } else { - return totalPercent[0] - } -} - -func GetSysInfo(sysInfo *SysInfo) error { - // sys cpu percent - totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false) - if err != nil { - sysInfo.SysCpuPercent = 0 - } else { - sysInfo.SysCpuPercent = uint16(totalPercent[0] * 100) - } - - if pProc == nil { - checkPid := os.Getpid() - pProc, err = process.NewProcess(int32(checkPid)) - if err != nil { - log.Tracef("get process info error %v", err) - return err - } - } - - // self cpu percent - percent, err := pProc.Percent(0) //(2*time.Second) - if err != nil { - log.Tracef("get process cpu percent error %v", err) - sysInfo.MyCpuPercent = 0 - } else { - sysInfo.MyCpuPercent = uint16(percent * 100) - } - - // self RAM(KB) - myRam, err := pProc.MemoryInfo() - if err != nil { - log.Tracef("get self memory info error %v", err) - sysInfo.MyUsedRam = 0 - } else { - sysInfo.MyUsedRam = uint32(myRam.RSS / 1024) - } - - // system RAM(KB) - sysRam, err := mem.VirtualMemory() - if err != nil { - log.Tracef("gett sys memory info error %v", err) - sysInfo.SysTotalRam = 0 - sysInfo.SysRamUsedPercent = 0 - } else { - sysInfo.SysTotalRam = uint32(sysRam.Total / 1024) - sysInfo.SysRamUsedPercent = uint16(sysRam.UsedPercent * 100) - } - - // partition usage - GetPartitions(sysInfo) - return nil -} - -func getProcess() *process.Process { - checkPid := os.Getpid() - ret, _ := process.NewProcess(int32(checkPid)) - return ret -} - -func GetSystemCpuInfo() { - physicalCnt, _ := cpu.Counts(false) - logicalCnt, _ := cpu.Counts(true) - log.Tracef("physical count:%d logical count:%d", physicalCnt, logicalCnt) - - totalPercent, _ := cpu.Percent(3*time.Second, false) // per cpu is false - perPercents, _ := cpu.Percent(3*time.Second, true) // per cpu is true - log.Tracef("total percent:%v per percents:%v", totalPercent, perPercents) -} - -func GetProcessCpuPercent() { - p := getProcess() - percent, err := p.Percent(0) - if err != nil { - log.Tracef("error %v", err) - } - - numcpu := runtime.NumCPU() - // if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO - if percent < 0.0 { - log.Tracef("Err CPU Percent of Process: %f, CPU num: %d", percent, numcpu) - } else { - log.Tracef("get process CPU percent: %f, CPU num: %d", percent, numcpu) - } -} - -func GetProcessMemoryInfo() { - p := getProcess() - - v, err := p.MemoryInfo() - if err != nil { - log.Tracef("getting memory info error %v", err) - } - - log.Tracef("get process memory info %v", v) - - info, _ := mem.VirtualMemory() - fmt.Println(info) -} - -func GetPartitions(sysInfo *SysInfo) { - sysInfo.PartitionNum = 0 - //sysInfo.PartitionInfo = make([]PartitionInfo, MAX_PARTITION_NUM, MAX_PARTITION_NUM) - infos, _ := disk.Partitions(true) - for _, info := range infos { - GetOnePartitionUsage(info.Mountpoint, sysInfo) - if sysInfo.PartitionNum >= MAX_PARTITION_NUM { - break - } - } -} - -func GetOnePartitionUsage(path string, sysInfo *SysInfo) int { - info, err := disk.Usage(path) - if err != nil { - return -1 - } - - if info.Total <= 0 { // info.Used/(1024 * 1024)MB - return 0 - } - var partition PartitionInfo - partition.Total = uint32(info.Total / 1024 / 1024) - partition.Used = uint32(info.Used / 1024 / 1024) - sysInfo.PartitionInfo = append(sysInfo.PartitionInfo, partition) - sysInfo.PartitionNum++ - - /*data, err := json.MarshalIndent(info, "", " ") - if err != nil { - return -1 - } - - fmt.Println(string(data))*/ - return 1 -} - -func getOS() string { - var osname string - if runtime.GOOS == "linux" { - osname = "GNU/Linux" - } - return osname -} - -func utsnameToString(unameArray [65]int8) string { - var byteString [65]byte - var indexLength int - for ; unameArray[indexLength] != 0 && indexLength < 65; indexLength++ { - byteString[indexLength] = uint8(unameArray[indexLength]) - } - return string(byteString[:indexLength]) -} - -func getUnameStr() string { - var utsname = syscall.Utsname{} - err := syscall.Uname(&utsname) - if err == nil { - name := utsnameToString(utsname.Sysname) - node := utsnameToString(utsname.Nodename) - release := utsnameToString(utsname.Release) - version := utsnameToString(utsname.Version) - machine := utsnameToString(utsname.Machine) - //domain:= utsnameToString(utsname.Domainname) - osName := getOS() - return fmt.Sprintf("%s %s %s %s %s %s", name, node, - release, version, machine, osName) - } - return "" -} diff --git a/features/state/state_windows.go b/features/state/state_windows.go deleted file mode 100644 index cbb027ee..00000000 --- a/features/state/state_windows.go +++ /dev/null @@ -1,231 +0,0 @@ -//go:build windows -// +build windows - -package state - -import ( - "encoding/binary" - "fmt" - "os" - "runtime" - "syscall" - "time" - - "github.com/shirou/gopsutil/v4/cpu" - "github.com/shirou/gopsutil/v4/disk" - "github.com/shirou/gopsutil/v4/mem" - "github.com/shirou/gopsutil/v4/process" -) - -type SysInfo struct { - SysCpuPercent uint16 // x% - MyCpuPercent uint16 // x%, CPU percent of current proccess - - SysTotalRam uint32 // KB - MyUsedRam uint32 // RAM usage of current proccess, KB - SysRamUsedPercent uint16 // x% - - PartitionNum byte - PartitionInfo []PartitionInfo // usage of each partition -} - -const MAX_PARTITION_NUM byte = 32 - -func GetSysStat() ([]byte, int) { - // Get sys info - var sysInfo SysInfo - err := GetSysInfo(&sysInfo) - if err != nil { - return nil, 0 - } - - //fmt.Printf("current sys info: %v", sysInfo) - - // build ems buffer - var data []byte = make([]byte, 1024) - var len int - var i byte - binary.BigEndian.PutUint16(data[0:], sysInfo.MyCpuPercent) //x% * 100 - binary.BigEndian.PutUint16(data[2:], sysInfo.SysCpuPercent) //x% * 100 - binary.BigEndian.PutUint32(data[4:], sysInfo.SysTotalRam) // KB - binary.BigEndian.PutUint32(data[8:], sysInfo.MyUsedRam) // KB - binary.BigEndian.PutUint16(data[12:], sysInfo.SysRamUsedPercent) //x% * 100 - data[14] = sysInfo.PartitionNum - for i = 0; i < sysInfo.PartitionNum; i++ { - binary.BigEndian.PutUint32(data[15+8*(i):], sysInfo.PartitionInfo[i].Total) // MB - binary.BigEndian.PutUint32(data[15+8*(i)+4:], sysInfo.PartitionInfo[i].Used) // MB - } - len = int(15 + 8*sysInfo.PartitionNum) - - //fmt.Printf("current sys stat buf: %v, len: %d", data, len) - - return data, len -} - -var pProc *process.Process = nil - -func GetSYsCpuPercent() float64 { - totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false) - if err != nil { - return 0.0 - } else { - return totalPercent[0] - } -} - -func GetSysInfo(sysInfo *SysInfo) error { - // sys cpu percent - totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false) - if err != nil { - sysInfo.SysCpuPercent = 0 - } else { - sysInfo.SysCpuPercent = uint16(totalPercent[0] * 100) - } - - if pProc == nil { - checkPid := os.Getpid() - pProc, err = process.NewProcess(int32(checkPid)) - if err != nil { - fmt.Printf("get process info error %v", err) - return err - } - } - - // self cpu percent - percent, err := pProc.Percent(0) //(2*time.Second) - if err != nil { - fmt.Printf("get process cpu percent error %v", err) - sysInfo.MyCpuPercent = 0 - } else { - sysInfo.MyCpuPercent = uint16(percent * 100) - } - - // self RAM(KB) - myRam, err := pProc.MemoryInfo() - if err != nil { - fmt.Printf("get self memory info error %v", err) - sysInfo.MyUsedRam = 0 - } else { - sysInfo.MyUsedRam = uint32(myRam.RSS / 1024) - } - - // system RAM(KB) - sysRam, err := mem.VirtualMemory() - if err != nil { - fmt.Printf("gett sys memory info error %v", err) - sysInfo.SysTotalRam = 0 - sysInfo.SysRamUsedPercent = 0 - } else { - sysInfo.SysTotalRam = uint32(sysRam.Total / 1024) - sysInfo.SysRamUsedPercent = uint16(sysRam.UsedPercent * 100) - } - - // partition usage - GetPartitions(sysInfo) - return nil -} - -func getProcess() *process.Process { - checkPid := os.Getpid() - ret, _ := process.NewProcess(int32(checkPid)) - return ret -} - -func GetSystemCpuInfo() { - physicalCnt, _ := cpu.Counts(false) - logicalCnt, _ := cpu.Counts(true) - fmt.Printf("physical count:%d logical count:%d\n", physicalCnt, logicalCnt) - - totalPercent, _ := cpu.Percent(3*time.Second, false) // per cpu is false - perPercents, _ := cpu.Percent(3*time.Second, true) // per cpu is true - fmt.Printf("total percent:%v per percents:%v\n", totalPercent, perPercents) -} - -func GetProcessCpuPercent() { - p := getProcess() - percent, err := p.Percent(0) - if err != nil { - fmt.Printf("error %v", err) - } - - numcpu := runtime.NumCPU() - // if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO - if percent < 0.0 { - fmt.Printf("Err CPU Percent of Process: %f, CPU num: %d", percent, numcpu) - } else { - fmt.Printf("get process CPU percent: %f, CPU num: %d", percent, numcpu) - } -} - -func GetProcessMemoryInfo() { - p := getProcess() - - v, err := p.MemoryInfo() - if err != nil { - fmt.Printf("getting memory info error %v", err) - } - - fmt.Printf("get process memory info %v\n", v) - - info, _ := mem.VirtualMemory() - fmt.Println(info) -} - -func GetPartitions(sysInfo *SysInfo) { - sysInfo.PartitionNum = 0 - //sysInfo.PartitionInfo = make([]PartitionInfo, MAX_PARTITION_NUM, MAX_PARTITION_NUM) - infos, _ := disk.Partitions(true) - for _, info := range infos { - GetOnePartitionUsage(info.Mountpoint, sysInfo) - if sysInfo.PartitionNum >= MAX_PARTITION_NUM { - break - } - } -} - -func GetOnePartitionUsage(path string, sysInfo *SysInfo) int { - info, err := disk.Usage(path) - if err != nil { - return -1 - } - - if info.Total <= 0 { // info.Used/(1024 * 1024)MB - return 0 - } - var partition PartitionInfo - partition.Total = uint32(info.Total / 1024 / 1024) - partition.Used = uint32(info.Used / 1024 / 1024) - sysInfo.PartitionInfo = append(sysInfo.PartitionInfo, partition) - sysInfo.PartitionNum++ - - /*data, err := json.MarshalIndent(info, "", " ") - if err != nil { - return -1 - } - - fmt.Println(string(data))*/ - return 1 -} - -func getOS() string { - var osname string - if runtime.GOOS == "linux" { - osname = "GNU/Linux" - } - return osname -} - -func utsnameToString(unameArray [65]int8) string { - var byteString [65]byte - var indexLength int - for ; unameArray[indexLength] != 0 && indexLength < 65; indexLength++ { - byteString[indexLength] = uint8(unameArray[indexLength]) - } - return string(byteString[:indexLength]) -} - -func getUnameStr() string { - osInfo, _ := syscall.GetVersion() - - return fmt.Sprintf("Widnows %d", osInfo) -} diff --git a/features/state/sysinfo.go b/features/state/sysinfo.go deleted file mode 100644 index f6f25b1c..00000000 --- a/features/state/sysinfo.go +++ /dev/null @@ -1,29 +0,0 @@ -package state - -import ( - "be.ems/lib/log" - "github.com/shirou/gopsutil/v4/cpu" - "github.com/shirou/gopsutil/v4/mem" -) - -func getCpuNumber() int { - // 获取CPU信息 - cpuInfo, err := cpu.Info() - if err != nil { - log.Errorf("Failed to get CPU info: %v", err) - return 0 - } - log.Tracef("CPU info: %+v", cpuInfo) - return len(cpuInfo) -} - -func getTotalMemory() int { - // 获取内存信息 - memInfo, err := mem.VirtualMemory() - if err != nil { - log.Errorf("Failed to get memory info: %v", err) - return 0 - } - log.Tracef("Memory info: %+v", memInfo) - return int(memInfo.Total) -} diff --git a/features/ue/ue.go b/features/ue/ue.go deleted file mode 100644 index 4c4ebb9a..00000000 --- a/features/ue/ue.go +++ /dev/null @@ -1,833 +0,0 @@ -package ue - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - "time" - - "be.ems/lib/config" - "be.ems/lib/core/ctx" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/constants" - neDataModel "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/go-resty/resty/v2" - "github.com/gorilla/mux" -) - -// AmfNBInfo AMF的NodeB信息 -type AmfNBInfo struct { - ID string `json:"id"` //NodeB ID - Name string `json:"name"` // NodeB name - Address string `json:"address"` // 基站地址 - UENum int `jons:"ueNum"` // UE数量 -} - -// SmfUENum SMF在线用户数 -type SmfUENum struct { - UENum int `json:"ueNum"` // 当前在线用户数 -} - -// SmfUEInfo SMF在线用户信息 -type SmfUEInfo struct { - IMSI string `json:"imsi"` - MSISDN string `json:"msisdn"` - RatType string `json:"ratType"` - PduSessionInfo []struct { - PduSessionID int `json:"pduSessionID"` - IPv4 string `json:"ipv4"` - IPv6 string `json:"ipv6"` - Dnn string `json:"dnn"` - Tai string `json:"tai"` - SstSD string `json:"sstSD"` - UpfN3IP string `json:"upfN3IP"` - RanN3IP string `json:"ranN3IP"` - Activetime string `json:"activeTime"` - UpState string `json:"upState"` - } `json:"pduSessionInfo"` -} - -// ImsUEInfo IMS在线用户信息 -type ImsUEInfo struct { - IMSI string `json:"imsi"` - MSISDN string `json:"msisdn"` - IMPU string `json:"impu"` - Barring int `json:"barring"` - RegState int `json:"regState"` - Activetime string `json:"activeTime"` -} - -// N3iwfUEInfo N3IWF在线用户信息 -type N3iwfUEInfo struct { - IMSI string `json:"imsi"` - - NAI string `json:"nai"` - RegState int `json:"regState"` - Activetime string `json:"activeTime"` -} - -type N3iwfUEData struct { - Data []N3iwfUEInfo `json:"data"` -} - -var ( - UriNBState = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbState" - UriNBInfo = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbInfo" - UriUEInfo = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueInfo" - UriUENum = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueNum" - UriPCFUser = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo" - UriPCFUserM = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo/batch/{number}" - UriPCFUserFileImport = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo/file/import" - UriPCFUserFileExport = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo/file/export" - UriNSSFAvailableAMFs = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/availableAMFs" - UriNSSFSubscriptions = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/subscriptions" - - CustomUriNBState = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbState" - CustomUriNBInfo = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbInfo" - CustomUriUEInfo = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueInfo" - CustomUriUENum = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueNum" - CustomUriPCFUser = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo" - CustomUriPCFUserM = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo/batch/{number}" - CustomUriPCFUserFileImport = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo/file/import" - CustomUriPCFUserFileExport = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/pcf/objectType/ueInfo/file/export" - CustomUriNSSFAvailableAMFs = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/availableAMFs" - CustomUriNSSFSubscriptions = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/subscriptions" -) - -var client = resty.New() - -func init() { - /* - client. - SetTimeout(10 * time.Second). - SetRetryCount(1). - SetRetryWaitTime(1 * time.Second). - SetRetryMaxWaitTime(2 * time.Second). - SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) { - return 0, errors.New("quota exceeded") - }) - */ - client.SetTimeout(500 * time.Millisecond) -} - -// Get AvailableAMFs from NSSF -func GetAvailableAMFsFromNSSF(w http.ResponseWriter, r *http.Request) { - log.Info("GetAvailableAMFsFromNSSF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if strings.ToLower(neType) != "nssf" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// Get Subscriptions from NSSF -func GetSubscriptionsFromNSSF(w http.ResponseWriter, r *http.Request) { - log.Info("GetSubscriptionsFromNSSF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if strings.ToLower(neType) != "nssf" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// Get UEInfo from NF/NFs -func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Debug("GetUEInfoFromNF processing... ") - - neId := ctx.GetQuery(r, "neId") - neType := ctx.GetParam(r, "elementTypeValue") - if neType == "" || neId == "" { - log.Error("elementTypeValue/neId is empty") - services.ResponseNotFound404UriNotExist(w, r) - return - } - - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID(neType, neId) - - var response services.MapResponse - if neInfo.NeId == neId && neInfo.NeId != "" { - requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) - log.Debug("requestURI2NF:", requestURI2NF) - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Failed to Get from NF:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - _ = json.Unmarshal(resp.Body(), &response) - } - log.Debug("response:", response) - } - - services.ResponseWithJson(w, http.StatusOK, response) -} - -// POST User Info from NF/NFs -func PostPCFUserInfo(w http.ResponseWriter, r *http.Request) { - log.Info("PostPCFUserInfo processing... ") - - // vars := mux.Vars(r) - // neType := vars["elementTypeValue"] - // if neType == "" { - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - //neTypeLower := strings.ToLower(neType) - neType := "PCF" - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - client.SetTimeout(1 * time.Minute) - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - //SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Post(requestURI2NF) - if err != nil { - log.Error("Failed to post:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// PUT PCF User Info from NF/NFs -func PutPCFUserInfo(w http.ResponseWriter, r *http.Request) { - log.Info("PutPCFUserInfo processing... ") - - // vars := mux.Vars(r) - // neType := vars["elementTypeValue"] - // if neType == "" { - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - //neTypeLower := strings.ToLower(neType) - neType := "PCF" - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - client.SetTimeout(1 * time.Minute) - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - //SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(body). - Put(requestURI2NF) - if err != nil { - log.Error("Failed to put:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// Get UEInfo from NF/NFs -func DeletePCFUserInfo(w http.ResponseWriter, r *http.Request) { - log.Info("DeletePCFUserInfo processing... ") - - // vars := mux.Vars(r) - // neType := vars["elementTypeValue"] - // if neType == "" { - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - //neTypeLower := strings.ToLower(neType) - neType := "PCF" - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - //SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Delete(requestURI2NF) - if err != nil { - log.Error("Failed to delete:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - w.WriteHeader(resp.StatusCode()) - w.Write(resp.Body()) - // var response services.MapResponse - // _ = json.Unmarshal(resp.Body(), &response) - // services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// Get UEInfo from SMF -func GetUENumFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("GetUENumFromNF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// Get Radio Info from NF/NFs -func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("GetNBInfoFromNF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} - -// PostNBInfoFromNF 接收Radio数据请求 -func PostNBInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("PostNBInfoFromNF processing... ") - neType := ctx.GetParam(r, "elementTypeValue") - var body struct { - NeType string `json:"neType" ` - NeName string `json:"neName" ` - RmUID string `json:"rmUID"` - StateList []struct { - Address string `json:"address" ` - Name string `json:"name" ` - Position string `json:"position" ` - NbName string `json:"nbName" ` - State string `json:"state" ` // "OFF" or "ON" - OffTime string `json:"offTime" ` //if State=OFF, will set it - OnTime string `json:"onTime" ` //if State=ON , will set it - } - } - if err := ctx.ShouldBindJSON(r, &body); err != nil { - services.ResponseInternalServerError500ProcessError(w, err) - return - } - - neTypeLower := strings.ToLower(body.NeType) - if neType == "" || neType != neTypeLower { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("inconsistent network element types")) - return - } - - neInfo := neService.NewNeInfo.FindByRmuid(body.RmUID) - if neInfo.RmUID != body.RmUID { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("inconsistent network element rmUID")) - return - } - - if len(body.StateList) == 0 { - services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("no stateList")) - return - } - - nbStateService := neDataService.NewNBState - for _, v := range body.StateList { - if v.Address == "" || v.State == "" { - continue - } - timeStr := v.OffTime - if v.State == "ON" { - timeStr = v.OnTime - } - nbStateService.Insert(neDataModel.NBState{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - RmUid: neInfo.RmUID, - Address: v.Address, - Name: v.Name, - Position: v.Position, - NbName: v.NbName, - State: v.State, - Time: timeStr, - }) - } - - services.ResponseStatusOK204NoContent(w) -} - -// Get Radio Info from NF/NFs -func GetNBInfoAllFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("GetNBInfoAllFromNF processing... ") - - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - // var neID string - neIDs := services.GetParamsArrByName("neId", r) - // if len(neIDs) == 1 { - // neID = neIDs[0] - // } else { - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - //var ret error - var statusCode int = 500 - var dataResponse []services.MapResponse - var neInfos []dborm.NeInfo - dborm.XormGetNeInfo2(neType, neIDs, &neInfos) - for _, neInfo := range neInfos { - // neInfo, err := dborm.XormGetNeInfo(neType, neID) - // if err != nil { - // log.Error("Failed to XormGetNeInfo:", err) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } else if neInfo == nil { - // err := global.ErrCMNotFoundTargetNE - // log.Error(global.ErrCMNotFoundTargetNE) - // services.ResponseInternalServerError500ProcessError(w, err) - // return - // } - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - //SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Failed to GET:", err) - continue - // services.ResponseInternalServerError500ProcessError(w, err) - // return - } else { - switch resp.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - dataResponse = append(dataResponse, response) - statusCode = http.StatusOK - } - } - } - var response services.DataResponse - response.Data = dataResponse - services.ResponseWithJson(w, statusCode, response) -} - -// Get GetUEInfoFileExportNF from NF/NFs -func GetUEInfoFileExportNF(w http.ResponseWriter, r *http.Request) { - log.Info("GetUEInfoFromNF processing... ") - - // vars := mux.Vars(r) - // neType := vars["elementTypeValue"] - // if neType == "" { - // services.ResponseNotFound404UriNotExist(w, r) - // return - // } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) - - neInfo, err := dborm.XormGetNeInfo("PCF", neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return - } - log.Trace("neInfo:", neInfo) - - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - client.SetTimeout(3 * time.Minute) - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: r.Header.Get(constants.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - w.WriteHeader(resp.StatusCode()) - w.Write(resp.Body()) - // var response services.MapResponse - // _ = json.Unmarshal(resp.Body(), &response) - // services.ResponseWithJson(w, resp.StatusCode(), response) - return - } -} diff --git a/lib/aes/aes.go b/lib/aes/aes.go deleted file mode 100644 index 5ce2fb40..00000000 --- a/lib/aes/aes.go +++ /dev/null @@ -1,64 +0,0 @@ -package aes - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "encoding/base64" -) - -func AesEncrypt(orig string, key string) string { - // 转成字节数组 - origData := []byte(orig) - k := []byte(key) - - // 分组秘钥 - block, _ := aes.NewCipher(k) - // 获取秘钥块的长度 - blockSize := block.BlockSize() - // 补全码 - origData = PKCS7Padding(origData, blockSize) - // 加密模式 - blockMode := cipher.NewCBCEncrypter(block, k[:blockSize]) - // 创建数组 - cryted := make([]byte, len(origData)) - // 加密 - blockMode.CryptBlocks(cryted, origData) - - return base64.StdEncoding.EncodeToString(cryted) - -} - -func AesDecrypt(cryted string, key string) string { - // 转成字节数组 - crytedByte, _ := base64.StdEncoding.DecodeString(cryted) - k := []byte(key) - - // 分组秘钥 - block, _ := aes.NewCipher(k) - // 获取秘钥块的长度 - blockSize := block.BlockSize() - // 加密模式 - blockMode := cipher.NewCBCDecrypter(block, k[:blockSize]) - // 创建数组 - orig := make([]byte, len(crytedByte)) - // 解密 - blockMode.CryptBlocks(orig, crytedByte) - // 去补全码 - orig = PKCS7UnPadding(orig) - return string(orig) -} - -// 补码 -func PKCS7Padding(ciphertext []byte, blocksize int) []byte { - padding := blocksize - len(ciphertext)%blocksize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - return append(ciphertext, padtext...) -} - -// 去码 -func PKCS7UnPadding(origData []byte) []byte { - length := len(origData) - unpadding := int(origData[length-1]) - return origData[:(length - unpadding)] -} diff --git a/lib/config/config.go b/lib/config/config.go deleted file mode 100644 index 2ba6afae..00000000 --- a/lib/config/config.go +++ /dev/null @@ -1,475 +0,0 @@ -package config - -import ( - "bufio" - "fmt" - "os" - "reflect" - "strings" - - "be.ems/lib/global" - "be.ems/lib/log" - - "gopkg.in/yaml.v3" -) - -// Yaml struct of config -type YamlConfig struct { - Logger struct { - File string `yaml:"file"` - Level string `yaml:"level"` - Duration int `yaml:"duration"` - Count int `yaml:"count"` - } `yaml:"logger"` - - OMC struct { - UriPrefix string `yaml:"uriPrefix"` - NeType string `yaml:"neType"` - NeId string `yaml:"neId"` - RmUID string `yaml:"rmUID"` - NeName string `yaml:"neName"` - Province string `yaml:"province"` - Vendor string `yaml:"vendor"` - Dn string `yaml:"dn"` - Chk2Ne bool `yaml:"chk2ne"` - Capability uint32 `yaml:"capability"` - Sn string `yaml:"sn"` - ExpiryDate string `yaml:"expiryDate"` - CheckSign bool `yaml:"checksign"` - RootDir string `yaml:"rootDir"` - BinDir string `yaml:"binDir"` - Backup string `yaml:"backup"` - Upload string `yaml:"upload"` - FrontUpload string `yaml:"frontUpload"` - FrontTraceDir string `yaml:"frontTraceDir"` - Software string `yaml:"software"` - License string `yaml:"license"` - GtpUri string `yaml:"gtpUri"` - CheckContentType bool `yaml:"checkContentType"` - TestMode bool `yaml:"testMode"` - RBACMode bool `yaml:"rbacMode"` - RunDir string `yaml:"runDir"` - CmdTimeout int `yaml:"cmdTimeout"` - } `yaml:"omc"` - - Alarm AlarmConfig `yaml:"alarm"` - - MML MMLParam `yaml:"mml"` - - NE struct { - Addr string `yaml:"addr"` - Port uint16 `yaml:"port"` - User string `yaml:"user"` - EtcDir string `yaml:"etcdir"` - BinDir string `yaml:"bindir"` - OmcDir string `yaml:"omcdir"` - ScpDir string `yaml:"scpdir"` - LicenseDir string `yaml:"licensedir"` - EtcListIMS string `yaml:"etcListIMS"` - EtcListDefault string `yaml:"etcListDefault"` - DpkgOverwrite bool `yaml:"dpkgOverwrite"` - DpkgTimeout int `yaml:"dpkgTimeout"` - } `yaml:"ne"` - - Auth struct { - Crypt string `yaml:"crypt"` - Token bool `yaml:"token"` - Expires uint32 `yaml:"expires"` - Session string `yaml:"session"` - PublicKey string `yaml:"publicKey"` - PrivateKey string `yaml:"privateKey"` - } `yaml:"auth"` - - Params struct { - RmUIDMaxNum int `yaml:"rmuidmaxnum"` - AlarmIDMaxNum int `yaml:"alarmidmaxnum"` - PmIDMaxNum int `yaml:"pmidmaxnum"` - SubIDMaxNum int `yaml:"subidmaxnum"` - UriMaxLen int `yaml:"urimaxlen"` - RmUIDRegexp string `yaml:"rmuidregexp"` - } `yaml:"params"` - - TestConfig struct { - Enabled bool `yaml:"enabled"` - File string `yaml:"file"` - } `yaml:"testConfig"` -} - -// type DbConfig struct { -// Type string `yaml:"type"` -// User string `yaml:"user"` -// Password string `yaml:"password"` -// Host string `yaml:"host"` -// Port string `yaml:"port"` -// Name string `yaml:"name"` -// ConnParam string `yaml:"connParam,omitempty"` -// Backup string `yaml:"backup"` -// } - -type AlarmConfig struct { - SplitEventAlarm bool `yaml:"splitEventAlarm"` - //ForwardAlarm bool `yaml:"forwardAlarm"` - - EmailForward struct { - Enable bool `yaml:"enable" json:"enable"` - EmailList string `yaml:"emailList" json:"emailList"` - Title string `yaml:"title" json:"title"` - SMTP string `yaml:"smtp" json:"smtp"` - Port uint16 `yaml:"port" json:"port"` - User string `yaml:"user" json:"user"` - Password string `yaml:"password" json:"password"` - TLSSkipVerify bool `yaml:"tlsSkipVerify" json:"tlsSkipVerify"` - } `yaml:"alarmEmailForward"` - SMSCForward struct { - Enable bool `yaml:"enable" json:"enable"` - MobileList string `yaml:"mobileList" json:"mobileList"` - SMSCAddr string `yaml:"smscAddr" json:"smscAddr"` - SystemID string `yaml:"systemID" json:"systemID"` - Password string `yaml:"password" json:"password"` - SystemType string `yaml:"systemType" json:"systemType"` - DataCoding byte `yaml:"dataCoding" json:"dataCoding"` - ServiceNumber string `yaml:"serviceNumber" json:"serviceNumber"` - } `yaml:"alarmSMSForward"` - SMS struct { - ApiURL string `yaml:"apiURL"` - AccessKeyID string `yaml:"AccessKeyID"` - AccessKeySecret string `yaml:"accessKeySecret"` - SignName string `yaml:"signName"` - TemplateCode string `yaml:"templateCode"` - } `yaml:"smsForward"` - SMProxy string `yaml:"smProxy"` -} - -type MMLParam struct { - Sleep int64 `yaml:"sleep"` - DeadLine int64 `yaml:"deadLine"` - SizeRow int16 `yaml:"sizeRow"` - SizeCol int16 `yaml:"sizeCol"` - BufferSize int `yaml:"bufferSize"` - MmlHome string `yaml:"mmlHome"` -} - -type TestDatas struct { - UDM struct { - CapUsed uint32 `yaml:"capUsed"` - FeatureEnabled []string `yaml:"featureEnabled"` - } `yaml:"udm"` - AUSF struct { - CapUsed uint32 `yaml:"capUsed"` - FeatureEnabled []string `yaml:"featureEnabled"` - } `yaml:"ausf"` - AMF struct { - CapUsed uint32 `yaml:"capUsed"` - FeatureEnabled []string `yaml:"featureEnabled"` - } `yaml:"amf"` - SMF struct { - CapUsed uint32 `yaml:"capUsed"` - FeatureEnabled []string `yaml:"featureEnabled"` - } `yaml:"smf"` - UPF struct { - CapUsed uint32 `yaml:"capUsed"` - FeatureEnabled []string `yaml:"featureEnabled"` - } `yaml:"upf"` -} - -type NeTestData struct { - CapUsed uint32 `yaml:"capUsed"` - FeatureEnabled []string `yaml:"featureEnabled"` -} -type TestDataMap struct { - NeTestDatas []map[string]NeTestData -} - -var yamlConfig YamlConfig = NewYamlConfig() - -type YamlConfigFile struct { - FilePath string `json:"filePath"` - ConfigLines YamlConfig `json:"configLines"` - OrignalLines []string `json:"orignalLines"` -} - -var YamlConfigInfo YamlConfigFile = YamlConfigFile{ - ConfigLines: NewYamlConfig(), -} - -// set default value for yaml config -func NewYamlConfig() YamlConfig { - return YamlConfig{ - // Database: DbConfig{ - // Type: "mysql", - // ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True", - // }, - MML: MMLParam{ - SizeRow: 200, - SizeCol: 120, - BufferSize: 65535, - }, - Alarm: AlarmConfig{ - SplitEventAlarm: true, - }, - } -} - -func ReadConfig(configFile string) { - YamlConfigInfo.FilePath = configFile - - yamlFile, err := os.ReadFile(configFile) - if err != nil { - fmt.Println("Read yaml config file error:", err) - os.Exit(2) - } - // fmt.Println("yamlfile:", string(yamlFile)) - - err = yaml.Unmarshal(yamlFile, &YamlConfigInfo.ConfigLines) - if err != nil { - fmt.Println("Unmarshal error:", err) - os.Exit(3) - } - yamlConfig = YamlConfigInfo.ConfigLines - - ReadOriginalConfig(configFile) -} - -func ReadOriginalConfig(configFile string) { - // 读取原始YAML文件 - inputFile, err := os.Open(configFile) - if err != nil { - fmt.Println("failed to open:", err) - os.Exit(3) - } - defer inputFile.Close() - - scanner := bufio.NewScanner(inputFile) - for scanner.Scan() { - YamlConfigInfo.OrignalLines = append(YamlConfigInfo.OrignalLines, scanner.Text()) - } - - if err := scanner.Err(); err != nil { - fmt.Println("failed to scanner:", err) - os.Exit(3) - } -} - -func WriteOrignalConfig(configFile string, paramName string, paramData map[string]any) error { - lines := YamlConfigInfo.OrignalLines - for i, line := range lines { - if strings.Contains(line, paramName) { - for k, v := range paramData { - // find the first line nearby the paramName - for j := i + 1; j < len(lines); j++ { - if strings.Contains(lines[j], k+":") { - index := strings.Index(lines[j], k) - // Determine the type of v - switch v := v.(type) { - case string: - lines[j] = lines[j][:index] + fmt.Sprintf("%s: \"%s\"", k, v) - // case int: - // lines[j] = lines[j][:index] + fmt.Sprintf("%s: %d", k, v) - // case float64: - // lines[j] = lines[j][:index] + fmt.Sprintf("%s: %f", k, v) - case bool: - lines[j] = lines[j][:index] + fmt.Sprintf("%s: %t", k, v) - default: - lines[j] = lines[j][:index] + fmt.Sprintf("%s: %v", k, v) - } - break - } - } - } - break - } - } - - // write back to yaml file - outputFile, err := os.Create(configFile) - if err != nil { - fmt.Println(err) - return err - } - defer outputFile.Close() - - writer := bufio.NewWriter(outputFile) - for _, line := range YamlConfigInfo.OrignalLines { - writer.WriteString(line + "\n") - } - writer.Flush() - return nil -} - -func WriteYamlConfig(newConfigData YamlConfig, configFile string) error { - // 将配置转换回YAML数据 - newYamlData, err := yaml.Marshal(&newConfigData) - if err != nil { - log.Errorf("Failed to marshal YAML: %v", err) - return err - } - - // 将新的YAML数据写入文件 - err = os.WriteFile(configFile, newYamlData, 0644) - if err != nil { - log.Errorf("Failed to write YAML file: %v", err) - return err - } - return nil -} - -var mapYaml map[string]interface{} - -func ReadParamConfig(fileName string) *map[string]interface{} { - file, err := os.ReadFile(fileName) - if err != nil { - fmt.Println("Read yaml file error:", err) - } - - mapYaml = make(map[string]interface{}) - - err = yaml.Unmarshal(file, &mapYaml) - if err != nil { - fmt.Printf("yaml.Unmarshal: %v when to struct", err) - } - // fmt.Println("mapYaml:", mapYaml) - - return &mapYaml -} - -func UpdateStructFromMap(s any, updates map[string]any) { - v := reflect.ValueOf(s).Elem() - t := v.Type() - - for key, value := range updates { - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - if field.Tag.Get("json") == key { - structField := v.FieldByName(field.Name) - if structField.IsValid() && structField.CanSet() { - // Convert value to the appropriate type if necessary - convertedValue := reflect.ValueOf(value).Convert(structField.Type()) - if structField.Type() == convertedValue.Type() { - structField.Set(convertedValue) - } - } - break - } - } - } -} - -func GetYamlConfig() *YamlConfig { - return &YamlConfigInfo.ConfigLines -} - -func GetAuthFromConfig() interface{} { - return yamlConfig.Auth -} - -func GetExpiresFromConfig() uint32 { - return yamlConfig.Auth.Expires -} - -func GetRmUIDFromConfig() string { - return yamlConfig.OMC.RmUID -} - -func GetRmUIDRegexpFromConfig() string { - return yamlConfig.Params.RmUIDRegexp -} - -func GetRmUIDMaxNumFromConfig() int { - return yamlConfig.Params.RmUIDMaxNum -} - -func GetAlarmIDMaxNumFromConfig() int { - return yamlConfig.Params.AlarmIDMaxNum -} - -func GetPmIDMaxNumFromConfig() int { - return yamlConfig.Params.PmIDMaxNum -} - -func GetSubIDMaxNumFromConfig() int { - return yamlConfig.Params.SubIDMaxNum -} - -func GetUriMaxLenFromConfig() int { - return yamlConfig.Params.UriMaxLen -} - -func GetLogLevel() log.LogLevel { - var logLevel log.LogLevel - switch strings.ToLower(yamlConfig.Logger.Level) { - case "trace": - logLevel = log.LOG_TRACE - case "info": - logLevel = log.LOG_INFO - case "debug": - logLevel = log.LOG_DEBUG - case "warn": - logLevel = log.LOG_WARN - case "error": - logLevel = log.LOG_ERROR - case "fatal": - logLevel = log.LOG_FATAL - case "off": - logLevel = log.LOG_OFF - default: - logLevel = log.LOG_DEBUG - } - return logLevel -} - -var ( - DefaultUriPrefix string = "/api/rest" - UriPrefix string = "/omc/rest" - //TestDataUDM []map[string]interface{} - TDatas map[string]NeTestData -) - -func ReadTestConfigYaml(pfile string) (ret error) { - file, err := os.ReadFile(pfile) - if err != nil { - return err - } - - err = yaml.Unmarshal(file, &TDatas) - if err != nil { - fmt.Println("Failed to Unmarshal:", err) - return err - } - - return nil -} - -func GetDefaultUserAgent() string { - return "OMC/" + global.Version -} - -// const defaultConfigFile = "./etc/restconf.yaml" - -// func init() { -// cfile := flag.String("c", defaultConfigFile, "config file") -// pv := flag.Bool("version", false, "print version") -// ph := flag.Bool("help", false, "print help") - -// //global.BuildTime = "Wed May 31 18:24:04 CST 2023" -// //global.GoVer = "go version go1.15.7 linux/arm64" -// flag.Parse() -// if *pv { -// fmt.Printf("OMC restagent version: %s\n%s\n%s\n\n", global.Version, global.BuildTime, global.GoVer) -// os.Exit(0) -// } -// if *ph { -// flag.Usage() -// os.Exit(0) -// } - -// // 使用viper读取配置 -// conf.InitConfig(*cfile) - -// ReadConfig(*cfile) -// if GetYamlConfig().OMC.UriPrefix != "" { -// UriPrefix = GetYamlConfig().OMC.UriPrefix -// } -// if GetYamlConfig().TestConfig.Enabled { -// ReadTestConfigYaml(GetYamlConfig().TestConfig.File) -// } -// } diff --git a/lib/config/map.go b/lib/config/map.go deleted file mode 100644 index 4c012791..00000000 --- a/lib/config/map.go +++ /dev/null @@ -1,111 +0,0 @@ -package config - -import ( - "io/ioutil" - "log" - - "gopkg.in/yaml.v3" - - "be.ems/lib/global" -) - -type Uri2Object struct { - Uri string `yaml:"uri"` - Object []Object `yaml:"object"` -} - -type Object struct { - Name string `yaml:"name"` - Syntax string `yaml:"syntax"` - Oid string `yaml:"oid"` -} - -var uri2Object []Uri2Object - -func ReadMap(pfile string) (ret error) { - file, err := ioutil.ReadFile(pfile) - if err != nil { - log.Println(err) - return err - } - - err = yaml.Unmarshal(file, &uri2Object) - if err != nil { - log.Println(err) - return err - } - /* - for _, v := range uri2Object { - log.Println(v) - } - */ - return nil -} - -func GetOid(uri string, oids *[]string) *[]string { - for _, v := range uri2Object { - if uri == v.Uri { - for _, o := range v.Object { - *oids = append(*oids, o.Oid) - } - } - } - - return oids -} - -func GetOidByFileds(uri string, fields []string, oids *[]string) *[]string { - for _, v := range uri2Object { - if uri == v.Uri { - for _, o := range v.Object { - if global.IsContain(o.Name, fields) || len(fields) == 0 { - *oids = append(*oids, o.Oid) - } - } - } - } - - return oids -} - -type NameOid struct { - Name string - Oid string -} - -type NameValue struct { - Name string - Value string -} - -func GetDataOid(Uri string, nameOids *[]NameOid) *[]NameOid { - var nameOid NameOid - for _, v := range uri2Object { - if Uri == v.Uri { - for _, o := range v.Object { - nameOid.Name = o.Name - nameOid.Oid = o.Oid - *nameOids = append(*nameOids, nameOid) - } - } - } - - return nameOids -} - -func GetDataOidByFields(uri string, fields []string, nameOids *[]NameOid) *[]NameOid { - var nameOid NameOid - for _, v := range uri2Object { - if uri == v.Uri { - for _, o := range v.Object { - nameOid.Name = o.Name - nameOid.Oid = o.Oid - if len(fields) == 0 || global.IsContainP(nameOid.Name, &fields, len(fields)) { - *nameOids = append(*nameOids, nameOid) - } - } - } - } - - return nameOids -} diff --git a/lib/core/ctx/ctx.go b/lib/core/ctx/ctx.go deleted file mode 100644 index 57cda575..00000000 --- a/lib/core/ctx/ctx.go +++ /dev/null @@ -1,185 +0,0 @@ -package ctx - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strings" - - "be.ems/src/framework/constants" - "be.ems/src/framework/token" - "github.com/gorilla/mux" -) - -// GetParam 地址栏参数{id} -func GetParam(r *http.Request, key string) string { - vars := mux.Vars(r) - v, ok := vars[key] - if ok { - return v - } - return "" -} - -// GetQuery 查询参数 -func GetQuery(r *http.Request, key string) string { - return r.URL.Query().Get(key) -} - -// GetHeader 请求头参数 -func GetHeader(r *http.Request, key string) string { - return r.Header.Get(key) -} - -// QueryMap 查询参数转换Map -func QueryMap(r *http.Request) map[string]any { - queryValues := r.URL.Query() - queryParams := make(map[string]any) - for key, values := range queryValues { - queryParams[key] = values[0] - } - return queryParams -} - -// ShouldBindQuery 查询参数读取json请求结构团体 &xxx -func ShouldBindQuery(r *http.Request, args any) error { - queryParams := QueryMap(r) - body, err := json.Marshal(queryParams) - if err != nil { - return err - } - return json.Unmarshal(body, args) -} - -// ShouldBindJSON 读取json请求结构团体 &xxx -func ShouldBindJSON(r *http.Request, args any) error { - body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 设置较大的长度,例如 1<<20 (1MB) - if err != nil { - return err - } - err = json.Unmarshal(body, args) - return err -} - -// JSON 相应json数据 -func JSON(w http.ResponseWriter, code int, data any) { - w.Header().Set("Content-Type", "application/json;charset=UTF-8") - - response, err := json.Marshal(data) - if err != nil { - w.WriteHeader(500) - w.Write([]byte(err.Error())) - } else { - w.WriteHeader(code) - w.Write(response) - } -} - -// 将文件导出到外部下载 -func FileAttachment(w http.ResponseWriter, r *http.Request, filepath, filename string) { - w.Header().Set("Content-Disposition", `attachment; filename=`+url.QueryEscape(filename)) - w.Header().Set("Content-Type", "application/octet-stream") - http.ServeFile(w, r, filepath) -} - -// 将文件上传保存到指定目录 -// file, handler, err := r.FormFile("file") -// SaveUploadedFile uploads the form file to specific dst. -func SaveUploadedFile(r *http.Request, dst string) error { - // 解析请求中的文件 - _, handler, err := r.FormFile("file") - if err != nil { - return err - } - - src, err := handler.Open() - if err != nil { - return err - } - defer src.Close() - - if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil { - return err - } - - out, err := os.Create(dst) - if err != nil { - return err - } - defer out.Close() - - _, err = io.Copy(out, src) - return err -} - -/// ==== 登录用户信息, 通过中间件后预置入 - -// Authorization 解析请求头 -func Authorization(r *http.Request) string { - // Query请求查询 - if authQuery := r.URL.Query().Get(constants.ACCESS_TOKEN); authQuery != "" { - return authQuery - } - // Header请求头 - if authHeader := r.Header.Get(constants.ACCESS_TOKEN); authHeader != "" { - return authHeader - } - - // Query请求查询 - if authQuery := r.URL.Query().Get(constants.ACCESS_TOKEN_QUERY); authQuery != "" { - return authQuery - } - // Header请求头 - authHeader := r.Header.Get(constants.HEADER_KEY) - if authHeader == "" { - return "" - } - // 拆分 Authorization 请求头,提取 JWT 令牌部分 - tokenStr := strings.Replace(authHeader, constants.HEADER_PREFIX, "", 1) - if len(tokenStr) > 64 { - return strings.TrimSpace(tokenStr) // 去除可能存在的空格 - } - return "" -} - -// ContextKey 定义自定义类型作为键 -type ContextKey string - -// LoginUser 登录用户信息需要Authorize中间件 -func LoginUser(r *http.Request) (token.UserInfo, error) { - // 获取请求头标识信息 - tokenStr := Authorization(r) - if tokenStr == "" { - return token.UserInfo{}, fmt.Errorf("not token info") - } - if tokenStr == "" { - return token.UserInfo{}, fmt.Errorf("authorization token is empty") - } - - // 验证令牌 - claims, err := token.UserTokenVerify(tokenStr, "access") - if err != nil { - return token.UserInfo{}, err - } - - // 获取缓存的用户信息 - info := token.UserInfoGet(claims) - if info.UserId <= 0 { - return token.UserInfo{}, fmt.Errorf("invalid login user information") - } - - return info, nil -} - -// LoginUserToUserName 登录用户信息-用户名称 -func LoginUserToUserName(r *http.Request) string { - loginUser, err := LoginUser(r) - if err != nil { - return "" - } - return loginUser.User.UserName -} diff --git a/lib/dborm/dborm.go b/lib/dborm/dborm.go deleted file mode 100644 index cfe12f29..00000000 --- a/lib/dborm/dborm.go +++ /dev/null @@ -1,1561 +0,0 @@ -package dborm - -import ( - "database/sql" - "encoding/json" - "errors" - "fmt" - "strconv" - "time" - - "strings" - - "be.ems/lib/log" - neService "be.ems/src/modules/network_element/service" - - _ "github.com/go-sql-driver/mysql" - "xorm.io/xorm" - "xorm.io/xorm/core" -) - -const ( - TableNameMeasureTask = "measure_task" - TableNameNeInfo = "ne_info" -) - -type Menu struct { - Id int `json:"id"` - Title string `json:"title"` - Icon string `json:"icon"` - Href string `json:"href"` - ParentId int `json:"parent_id"` - Remark int `json:"remark"` -} - -type DatabaseClient struct { - dbType string - dbUrl string - dbConnMaxLifetime time.Duration - dbMaxIdleConns int - dbMaxOpenConns int - IsShowSQL bool - - XEngine *xorm.Engine -} - -var DbClient DatabaseClient - -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", - dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) - DbClient.dbType = dbType - DbClient.dbConnMaxLifetime = 0 - DbClient.dbMaxIdleConns = 0 - DbClient.dbMaxOpenConns = 0 - if log.GetLevel() == log.LOG_TRACE { - DbClient.IsShowSQL = true - } - log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) - - var err error - DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) - if err != nil { - log.Error("Failed to connet database:", err) - return err - } - DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) - DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) - DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) - DbClient.XEngine.DatabaseTZ = time.Local // 必须 - DbClient.XEngine.TZLocation = time.Local // 必须 - if DbClient.IsShowSQL { - DbClient.XEngine.ShowSQL(true) - } - - xEngine = DbClient.XEngine - - return nil -} - -// func InitDbClient() error { -// db := config.GetYamlConfig().Database -// DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", db.User, db.Password, db.Host, db.Port, db.Name) -// DbClient.dbType = db.Type -// DbClient.dbConnMaxLifetime = 0 -// DbClient.dbMaxIdleConns = 0 -// DbClient.dbMaxOpenConns = 0 -// if log.GetLevel() == log.LOG_TRACE { -// DbClient.IsShowSQL = true -// } -// log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s", DbClient.dbType, db.User, db.Host, db.Port, db.Name) -// var err error -// DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) -// if err != nil { -// log.Error("Failed to connet database:", err) -// return err -// } -// DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) -// DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) -// DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) -// if DbClient.IsShowSQL { -// DbClient.XEngine.ShowSQL(true) -// } -// xEngine = DbClient.XEngine - -// return nil -// } - -var xEngine *xorm.Engine - -func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) { - sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) - log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) - var err error - xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine - if err != nil { - log.Error("Failed to connect database:", err) - return nil, err - } - if log.GetLevel() == log.LOG_TRACE { - xEngine.ShowSQL(true) - } - return xEngine, nil -} - -func XCoreDB() *core.DB { - return xEngine.DB() -} - -func XEngDB() *xorm.Engine { - return xEngine -} - -func ConstructInsertSQL(tableName string, insertData interface{}) (string, []string) { - log.Debug("ConstructInsertSQL processing... ") - log.Debug("Request insertData:", insertData) - - var sql []string - var dataTag string - for t, d := range insertData.(map[string]interface{}) { - log.Tracef("t: %v d: %v", t, d) - dataTag = t - - for i, r := range d.([]interface{}) { - var cl, vl string - log.Tracef("i: %v r: %v", i, r) - for c, v := range r.(map[string]interface{}) { - log.Tracef("c: %v v: %v", c, v) - if cl == "" { - cl = fmt.Sprint(c) - } else { - cl = fmt.Sprintf("%s, %s", cl, c) - } - if vl == "" { - vl = fmt.Sprintf("'%v'", v) - } else { - vl = fmt.Sprintf("%s, '%v'", vl, v) - } - - log.Tracef("cl: %s vl: %s", cl, vl) - } - sql = append(sql, "insert into "+tableName+"("+cl+")"+" values("+vl+")") - } - - log.Debug("sql:", sql) - } - - return dataTag, sql -} - -func InsertDataWithJson(insertData interface{}) (int64, error) { - log.Debug("InsertDataWithJson processing... ") - - var data map[string]interface{} - var tableName string - for k, v := range insertData.(map[string]interface{}) { - log.Tracef("k: %v v: %v", k, v) - tableName = k - data = v.(map[string]interface{}) - } - - log.Tracef("data: %v", data) - xSession := xEngine.NewSession() - defer xSession.Close() - affected, err := xSession.Insert(data, tableName) - xSession.Commit() - - return affected, err -} - -type NeInfo struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeId string `json:"neId" xorm:"ne_id"` // neUID/rmUID 网元唯一标识 - RmUID string `json:"rmUid" xorm:"rm_uid"` // neUID/rmUID网元UID - NeName string `json:"neName" xorm:"ne_name"` // NeName/UserLabel 网元名称/网元设备友好名称 - Ip string `json:"ip" xorm:"ip"` - Port string `json:"port" xorm:"port"` - PvFlag string `json:"pvFlag" xorm:"pv_flag"` // 网元虚实性标识 VNF/PNF: 虚拟/物理 - NeAddress string `json:"neAddress" xorm:"ne_address"` // 只对PNF - Province string `json:"province" xorm:"province"` // 网元所在省份 - VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称 - Dn string `json:"dn" xorm:"dn"` // 网络标识 - Status int `json:"status" xorm:"status"` - UpdateTime time.Time `json:"updateTime" xorm:"<-"` -} - -func XormGetNeInfo(neType string, neId string) (*NeInfo, error) { - log.Debug("XormGetNeInfo processing... ") - neInfox := neService.NewNeInfo.FindByNeTypeAndNeID(neType, neId) - - neInfo := new(NeInfo) - neInfo.NeType = neType - neInfo.NeId = neId - neInfo.RmUID = neInfox.RmUID - neInfo.NeName = neInfox.NeName - neInfo.Ip = neInfox.IP - neInfo.Port = fmt.Sprint(neInfox.Port) - neInfo.PvFlag = neInfox.PvFlag - neInfo.NeAddress = neInfox.NeAddress - neInfo.Province = neInfox.Province - neInfo.VendorName = neInfox.VendorName - neInfo.Dn = neInfox.Dn - neInfo.Status = int(neInfox.Status) - neInfo.UpdateTime = time.UnixMilli(neInfox.UpdateTime) - - return neInfo, nil -} - -func XormGetNeInfoByRmUID(neType string, rmUID string) (*NeInfo, error) { - log.Debug("XormGetNeInfoByRmUID processing... ") - - neInfo := new(NeInfo) - has, err := xEngine.Where("ne_type=? and rm_uid=?", strings.ToUpper(neType), rmUID).Get(neInfo) - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return nil, err - } else if !has { - log.Infof("Not found ne_info from database, neType=%s, neId=%s", neType, rmUID) - return nil, nil - } - - log.Debug("NE Info:", neInfo) - return neInfo, nil -} - -func XormGetAllNeInfo(nes *[]NeInfo) (*[]NeInfo, error) { - log.Debug("XormGetAllNeInfo processing... ") - - ne := new(NeInfo) - rows, err := xEngine.Table("ne_info").Rows(ne) - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return nil, err - } - defer rows.Close() - for rows.Next() { - err := rows.Scan(ne) - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return nil, err - } - *nes = append(*nes, *ne) - } - log.Trace("nes:", nes) - return nes, nil -} - -func XormGetNeInfoByNeType(neType string, nes *[]NeInfo) error { - log.Debug("XormGetNeInfoByNeType processing... ") - - ne := new(NeInfo) - rows, err := xEngine.Table("ne_info").Where("ne_type=?", neType).Rows(ne) - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return err - } - defer rows.Close() - for rows.Next() { - err := rows.Scan(ne) - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return err - } - *nes = append(*nes, *ne) - } - - return nil -} - -func XormGetNeInfo2(neType string, neIDs []string, nes *[]NeInfo) error { - log.Info("XormGetNeInfo2 processing... ") - - ne := new(NeInfo) - var rows *xorm.Rows - var err error - if len(neIDs) == 0 { - rows, err = xEngine.Table("ne_info"). - Where("ne_type=?", neType). - Rows(ne) - } else { - rows, err = xEngine.Table("ne_info"). - In("ne_id", neIDs). - And("ne_type=?", neType). - Rows(ne) - } - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return err - } - defer rows.Close() - for rows.Next() { - err := rows.Scan(ne) - if err != nil { - log.Error("Failed to get table ne_info from database:", err) - return err - } - *nes = append(*nes, *ne) - } - - return nil -} - -func XormInsertNeInfo(neInfo *NeInfo) (int64, error) { - log.Debug("XormInsertNeInfo processing... ") - - var affected int64 = 0 - var err error = nil - - xSession := xEngine.NewSession() - defer xSession.Close() - ex, _ := xEngine.Table("ne_info").Where("status = '1' and ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId).Exist() - if ex { - neInfo.Status = 0 - affected, err = xSession.Where("ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId).Update(neInfo) - } else { - affected, err = xSession.InsertOne(neInfo) - } - xSession.Commit() - return affected, err -} - -func XormUpdateNeInfo(neInfo *NeInfo) (int64, error) { - log.Debug("XormUpdateNeInfo processing... ") - - xSession := xEngine.NewSession() - defer xSession.Close() - affected, err := xSession.ID(neInfo.Id).MustCols("status").Update(neInfo) - xSession.Commit() - return affected, err -} - -func XormDeleteNeInfo(neInfo *NeInfo) (int64, error) { - log.Debug("XormDeleteNeInfo processing... ") - - xSession := xEngine.NewSession() - defer xSession.Close() - affected, err := xSession.Where("ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId).Delete(neInfo) - xSession.Commit() - return affected, err -} - -func XormParseResult(body []byte) ([]NeInfo, error) { - log.Debug("XormParseResult processing... ") - - data := make(map[string]interface{}) - err := json.Unmarshal(body, &data) - if err != nil { - return nil, err - } - var neInfo []NeInfo - var re interface{} - if data["data"] == nil { - return nil, errors.New("the data is not found") - } - for _, d := range data["data"].([]interface{}) { - if d == nil { - return nil, errors.New("the data is Not found") - } - for _, re = range d.(map[string]interface{}) { - if re == nil { - return nil, errors.New("the data is Not found") - } - for _, rc := range re.([]interface{}) { - if rc == nil { - return nil, errors.New("the data is Not found") - } - var s NeInfo - record := rc.(map[string]interface{}) - s.NeName = fmt.Sprintf("%v", record["ne_name"]) - s.NeId = fmt.Sprintf("%v", record["ne_id"]) - s.NeType = fmt.Sprintf("%v", strings.ToLower(record["ne_type"].(string))) - s.Ip = fmt.Sprintf("%v", record["ip"]) - s.Port = fmt.Sprintf("%v", record["port"]) - s.PvFlag = fmt.Sprintf("%v", record["pv_flag"]) - - neInfo = append(neInfo, s) - } - } - } - - log.Debug("neInfo:", neInfo) - return neInfo, nil -} - -func ConstructUpdateSQLArray(tableName string, updateData interface{}, whereCondition string) (string, []string) { - log.Debug("ConstructUpdateSQL processing... ") - log.Debug("Request updateData:", updateData) - - var sql []string - var tblName string - for t, d := range updateData.(map[string]interface{}) { - log.Tracef("t: %v d: %v", t, d) - tblName = t - - for i, r := range d.([]interface{}) { - var cv string - log.Tracef("i: %v r: %v", i, r) - for c, v := range r.(map[string]interface{}) { - log.Tracef("c: %v v: %v", c, v) - if cv == "" { - cv = fmt.Sprintf("`%s`='%s'", c, v) - } else { - cv = fmt.Sprintf("%s,`%s`='%s'", cv, c, v) - } - - log.Tracef("cv: %s", cv) - } - sql = append(sql, "UPDATE "+tableName+" SET "+cv+" WHERE "+whereCondition) - } - - log.Debug("sql:", sql) - } - - return tblName, sql -} - -func ConstructUpdateSQL(tableName string, updateData interface{}, whereCondition string) (string, []string) { - log.Debug("ConstructUpdateSQL processing... ") - log.Debug("Request updateData:", updateData) - - var sql []string - var tblName string - for t, d := range updateData.(map[string]interface{}) { - log.Tracef("t: %v d: %v", t, d) - tblName = t - - var cv string - for c, v := range d.(map[string]interface{}) { - log.Tracef("c: %v v: %v", c, v) - if cv == "" { - //cv = fmt.Sprintf("`%s`=%s", c, v) - cv = fmt.Sprintf("`%s`='%s'", c, v) - } else { - //cv = fmt.Sprintf("%s,`%s`=%s", cv, c, v) - cv = fmt.Sprintf("%s,`%s`='%s'", cv, c, v) - } - - log.Tracef("cv: %s", cv) - } - sql = append(sql, "UPDATE "+tableName+" SET "+cv+" WHERE "+whereCondition) - - log.Debug("sql:", sql) - } - - return tblName, sql -} - -func ConstructDeleteSQL(tableName string, whereCondition string) string { - log.Debug("ConstructDeleteSQL processing... ") - - var sql string = "DELETE from " + tableName + " WHERE " + whereCondition - log.Debug("sql:", sql) - return sql -} - -type TaskStatus string - -const ( - MeasureTaskStatusInactive = "Inactive" - MeasureTaskStatusActive = "Active" - MeasureTaskStatusSuspend = "Suspend" - MeasureTaskStatusDeleted = "Deleted" -) - -type ScheduleJ struct { - Type string `json:"Type"` - Days []int `json:"Days"` -} - -type Period struct { - Start string `json:"Start"` - End string `json:"End"` -} - -func GetTableByWhere(whereCondition string, tableName string) (*[]interface{}, error) { - log.Debug("GetTableByWhere processing... ") - - rows := new([]interface{}) - has, err := xEngine.Table(tableName).Where(whereCondition).Get(rows) - if err != nil { - log.Errorf("Failed to get table %s from database:%v", tableName, err) - return nil, err - } else if !has { - log.Infof("Not found table %s from database:where=%d", tableName, whereCondition) - return nil, nil - } - - log.Debugf("%s:%v", tableName, rows) - return rows, nil -} - -func GetTableById(id int, tableName string) (*[]interface{}, error) { - log.Debug("GetTableById processing... ") - - rows := new([]interface{}) - has, err := xEngine.Table(tableName).ID(id).Get(rows) - if err != nil { - log.Errorf("Failed to get table %s from database:id=%d, %v", tableName, id, err) - return nil, err - } else if !has { - log.Infof("Not found table %s from database:id=%d", tableName, id) - return nil, nil - } - - log.Debugf("%s:%v", tableName, rows) - return rows, nil -} - -func XormUpdateTableById(id int, tableName string, tbInfo interface{}) (int64, error) { - log.Debug("XormUpdateTableById processing...id: ", id) - - affected, err := xEngine.Table(tableName).ID(id).Update(tbInfo) - if err != nil { - log.Errorf("Failed to update table %s from database:%v", tableName, err) - return 0, err - } - - return affected, nil -} - -func XormUpdateTableByWhere(whereCondition string, tableName string, tbInfo interface{}) (int64, error) { - log.Debug("UpdateTableByWhere processing... ") - - affected, err := xEngine.Table(tableName).Where(whereCondition).Update(tbInfo) - if err != nil { - log.Errorf("Failed to update table %s from database:%v", tableName, err) - return 0, err - } - - return affected, nil -} - -func XormIsExistUser(accid string) (bool, error) { - log.Info("xormIsExistUser processing... ") - - exist, err := xEngine.Table("user"). - Where("account_id=?", accid). - Exist() - if err != nil { - log.Error("Failed to exist user:", err) - - return false, err - } - - return exist, nil -} - -func XormGetConfig(moduleName, configTag string) (map[string]any, error) { - result, err := DbClient.XEngine.QueryInterface("select * from config where module_name=? and config_tag=?", moduleName, configTag) - if err != nil { - log.Error("Failed to get config:", err) - return nil, err - } - if len(result) > 0 { - return result[0], nil - } - return map[string]any{}, nil -} - -func XormGetConfigValue(moduleName, configTag string) (string, error) { - var value string - _, err := xEngine.Table("config"). - Where("module_name=? and config_tag=?", moduleName, configTag). - Cols("value"). - Get(&value) - if err != nil { - log.Error("Failed to get config:", err) - return "", err - } - return value, nil -} - -type Session struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - AccountId string `json:"accountId" xorm:"account_id"` - Name string `json:"name" xorm:"name"` - Host string `json:"host" xorm:"host"` - AccessToken string `json:"accessToken" xorm:"access_token"` - Expires uint32 `json:"expires" xorm:"expires"` - Status string `json:"status" xorm:"status"` - LoginTime string `json:"loginTime" xorm:"-"` - ShakeTime sql.NullTime `son:"shakeTime" xorm:"shake_time"` - LogoutTime sql.NullTime `json:"logoutTime" xorm:"logout_time"` -} - -// XormInsertSession create session -func XormInsertSession(name, host, token string, expires uint32, sessionFlag string) (int64, error) { - log.Info("XormInsertSession processing... ") - - var affected int64 = 0 - var err error = nil - currentTime := time.Now() - timeValue := currentTime.Local() - nullTime := sql.NullTime{Valid: true, Time: timeValue} - value, err := XormGetConfigValue("Security", "sessionExpires") - if err != nil { - return affected, err - } - if value != "" { - intValue, _ := strconv.Atoi(value) - expires = uint32(intValue) - log.Debugf("intValue=%d, expires=%d", intValue, expires) - } - - session := Session{AccountId: name, - Name: name, Host: host, AccessToken: token, - Status: "online", Expires: expires, - ShakeTime: nullTime, - } - - //session.ShakeTime.Time - xSession := xEngine.NewSession() - defer xSession.Close() - if strings.ToLower(sessionFlag) == "multiple" { - exist, err := xEngine.Table("session").Where("status = 'online' and account_id = ? and host = ?", name, host).Exist() - if err != nil { - return affected, err - } - if exist { - affected, _ = xSession.Table("session").Where("account_id = ? and host = ?", name, host).Update(session) - } else { - affected, _ = xSession.InsertOne(session) - } - } else { // single session for a user - exist, err := xEngine.Table("session").Where("status = 'online' and account_id = ?", name).Exist() - if err != nil { - return affected, err - } - if exist { - // todo... - err := errors.New("user is logged in") - return -1, err - } else { - affected, _ = xSession.InsertOne(session) - } - } - xSession.Commit() - return affected, err -} - -// XormUpdateSession update session -func XormLogoutUpdateSession(token string) (Session, error) { - log.Info("XormLogoutUpdateSession processing... ") - - session := Session{Status: "offline", AccessToken: token} - session.LogoutTime.Valid = true - session.LogoutTime.Time = time.Now() - - xSession := xEngine.NewSession() - defer xSession.Close() - _, err := xSession.Table("session").Where("access_token = ?", token).Update(session) - xSession.Commit() - // 查询记录返回 - if err == nil { - session := Session{} - _, err = xSession.Table("session").Where("access_token = ?", token).Get(&session) - return session, err - } - return session, err -} - -// XormUpdateSessionShakeTime create session -func XormUpdateSessionShakeTime(token string) (Session, error) { - log.Debug("XormUpdateSessionShakeTime processing... ") - - session := Session{AccessToken: token} - session.ShakeTime.Valid = true - session.ShakeTime.Time = time.Now() - xSession := xEngine.NewSession() - defer xSession.Close() - _, err := xSession.Table("session").Where("access_token = ?", token).Update(session) - xSession.Commit() - // 查询记录返回 - if err == nil { - session := Session{} - _, err = xSession.Table("session").Where("access_token = ?", token).Get(&session) - return session, err - } - return session, err -} - -func XormExistValidToken(token string, expires uint32) bool { - log.Info("XormExistValidToken processing... ") - - exist, err := xEngine.Table("session"). - Where("status = 'online' and access_token = ? and DATE_ADD(shake_time, INTERVAL expires SECOND) > NOW()", token). - Exist() - if err != nil { - return false - } - - return exist -} - -/* - type NorthboundPm struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - Date string `json:"date" xorm:"date"` - Index int `json:"index"` - StartTime string `json:"startTime" xorm:"start_time"` - TimeZone string `json:"timeZone" xorm:"time_zone"` - NEName string `json:"neName" xorm:"ne_name"` - PmVersion string `json:"pmVersion" xorm:"pm_version"` - Period string `json:"period" xorm:"pevalue" - RmUid string `json:"rmUid" xorm:"rm_uid"` - NEType string `json:"neType" xorm:"ne_type"` - Dn string `json:"neType" xorm:"ne_type"` - ObjectType string `json:"objectType" xorm:"object_type"` - PmName string `json:"pmName" xorm:"pm_name"` - PmExt string `json:"pmExt" xorm:"pm_ext"` - Value int `json:"value" xorm:"value"` - Timestamp string `json:"timestamp" xorm:"timestamp"` - } -*/ -type NorthboundPm struct { - Id int `json:"-" xorm:"pk 'id' autoincr"` - Date string `json:"Date" xorm:"date"` - Index int `json:"Index" xorm:"index"` // 1天中测量时间粒度(如15分钟)的切片索引: 0~95 - Timestamp string `json:"-" xorm:"-"` - NeName string `json:"NeName" xorm:"ne_name"` // UserLabel - RmUID string `json:"RmUID" xorm:"rm_uid"` - NeType string `json:"NeType" xorm:"ne_type"` // 网元类型 - PmVersion string `json:"PmVersion" xorm:"pm_version"` // 性能数据版本号 - Dn string `json:"Dn" xorm:"dn"` // (???)网元标识, 如:RJN-CMZJ-TZ,SubNetwork=5GC88,ManagedElement=SMF53456,SmfFunction=53456 - Period string `json:"Period" xorm:"period"` // 测量时间粒度选项:5/15/30/60 - TimeZone string `json:"TimeZone" xorm:"time_zone"` - StartTime string `json:"StartTime" xorm:"start_time"` - - Datas []struct { - ObjectType string `json:"ObjectType" xorm:"object_type"` // 网络资源类别名称, Pm指标项列表中为空间粒度 如:SmfFunction - PmDatas []struct { - PmName string `json:"KPIID" xorm:"pm_name"` // 指标项, 如: SMF.AttCreatePduSession._Dnn - SubDatas []struct { - SN string `json:"Name" xorm:"sn"` // 单个的写"Total", 或者指标项有多个测量项,如Dnn的名称写对应的Dnn"cmnet"/"ims" - SV int64 `json:"Value" xorm:"sv"` - } `json:"KPIValues" xorm:"sub_datas"` - } `json:"KPIs" xorm:"pm_datas"` - } `json:"Datas" xorm:"datas"` -} - -type Alarm struct { - AlarmSeq int `json:"alarmSeq"` - AlarmId string `json:"alarmId" xorm:"alarm_id"` - NeId string `json:"neId"` - AlarmCode int `json:"alarmCode"` - AlarmTitle string `json:"alarmTitle"` - EventTime string `json:"eventTime"` - AlarmType string `json:"alarmType"` - OrigSeverity string `json:"origSeverity"` - PVFlag string `json:"pvFlag" xorm:"pv_flag"` - NeName string `json:"neName"` - NeType string `json:"neType"` - ObjectUid string `json:"objectUid" xorm:"object_uid"` - ObjectName string `json:"objectName" xorm:"object_name"` - ObjectType string `json:"objectType" xorm:"object_type"` - LocationInfo string `json:"locationInfo"` - Province string `json:"province"` - AlarmStatus int `json:"alarmStatus"` - SpecificProblem string `json:"specificProblem"` - SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"` - AddInfo string `json:"addInfo"` - - // AckState int `json:"ackState" xorm:"-"` - // AckTime string `json:"ackTime" xorm:"-"` - ClearType int `json:"clearType" xorm:"-"` // 0: Unclear, 1: Auto clear, 2: Manual clear - ClearTime string `json:"clearTime" xorm:"-"` -} - -func XormGetAlarmByAlarmId(alarmId string, alarms *[]Alarm) (*[]Alarm, error) { - log.Debug("XormGetAlarmByAlarmId processing... ") - - alarm := new(Alarm) - rows, err := xEngine.Table("alarm").Where("alarm_id=?", alarmId).Rows(alarm) - if err != nil { - log.Error("Failed to get table alarm from database:", err) - return nil, err - } - - defer rows.Close() - for rows.Next() { - err := rows.Scan(alarm) - if err != nil { - log.Error("Failed to get table alarm from database:", err) - return nil, err - } - *alarms = append(*alarms, *alarm) - } - - log.Trace("alarms:", alarms) - return alarms, nil -} - -func XormSQLGetStringValue(querySQL string) (string, error) { - log.Debug("XormSQLGetStringValue processing... ") - - row := make(map[string]interface{}) - _, err := xEngine.SQL(querySQL).Get(&row) - if err != nil { - log.Errorf("Failed to get by SQL=%s:%v", querySQL, err) - return "", err - } - - for _, v := range row { - return fmt.Sprintf("%v", v), nil - } - - return "", nil -} - -func XormGetSingleCol(table, col, where string) (string, error) { - log.Debug("XormGetSingleCol processing... ") - - row := make(map[string]interface{}) - _, err := xEngine.Table(table).Where(where).Cols(col).Get(&row) - if err != nil { - log.Errorf("Failed to get %s from table %s:%v", col, table, err) - return "", err - } - - for _, v := range row { - return fmt.Sprintf("%v", v), nil - } - - return "", nil -} - -func XormGetSingleColStringArrayByIn(table, col, incol string, conditions []string, cols *[]string) error { - log.Debug("XormGetSingleColStringArrayByIn processing... ") - - err := xEngine.Table(table).In(incol, conditions).Cols(col).Distinct().Find(cols) - if err != nil { - log.Errorf("Failed to get %s from table %s:%v", col, table, err) - return err - } - return nil -} - -func XormGetColStringArrayByWhere(table, coln, where string, colv *[]string) error { - log.Debug("XormGetColStringArrayByWhere processing... ") - - _, err := xEngine.Table(table).Where(where).Cols(coln).Get(colv) - if err != nil { - log.Errorf("Failed to Get %s from table %s:%v", coln, table, err) - return err - } - return nil -} - -func XormFindColStringArrayByWhere(table, col, where string, cols *[]string) error { - log.Debug("XormFindColStringArrayByWhere processing... ") - - err := xEngine.Table(table).Where(where).Cols(col).Distinct().Find(cols) - if err != nil { - log.Errorf("Failed to Find %s from table %s:%v", col, table, err) - return err - } - return nil -} - -func XormGetSingleColStringByWhere(table, col, where string) (string, error) { - log.Info("XormFindSingleColStringByWhere processing... ") - - var colv string - _, err := xEngine.Table(table).Where(where).Cols(col).Get(&colv) - if err != nil { - log.Errorf("Failed to Find %s from table %s:%v", col, table, err) - return colv, err - } - return colv, nil -} - -func XormGetSingleColStringArrayByID(table, col string, id int, cols *[]string) error { - log.Debug("XormGetSingleColStringArrayByID processing... ") - - err := xEngine.Table(table).ID(id).Cols(col).Find(cols) - if err != nil { - log.Errorf("Failed to Find %s from table %s:%v", col, table, err) - return err - } - return nil -} - -func XormGetStringValue(table, col string, id int) (string, error) { - log.Debug("XormGetStringValue processing... ") - - row := make(map[string]interface{}) - _, err := xEngine.ID(id).Table(table).Cols(col).Get(&row) - if err != nil { - log.Errorf("Failed to get %s from table %s:%v", col, table, err) - return "", err - } - - for _, v := range row { - return fmt.Sprintf("%v", v), nil - } - - return "", nil -} - -type NeBackup struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeId string `json:"neId" xorm:"ne_id"` - FileName string `json:"neName" xorm:"file_name"` - Path string `json:"path"` - Md5Sum string `json:"md5Sum" xorm:"md5_sum"` - CreateTime string `json:"createTime" xorm:"-" ` -} - -// XormInsertSession create session -func XormInsertTableOne(tableName string, tbInfo interface{}) (int64, error) { - log.Debug("XormInsertTableOne processing... ") - - var affected int64 = 0 - var err error = nil - - xSession := xEngine.NewSession() - defer xSession.Close() - affected, err = xSession.Table(tableName).InsertOne(tbInfo) - xSession.Commit() - return affected, err -} - -// XormExistTableOne create session -func XormExistTableOne(tableName string, where string) (bool, error) { - log.Debug("XormExistTableOne processing... ") - - has, err := xEngine.Table(tableName).Where(where).Exist() - - return has, err -} - -func XormGetTableRows(tableName string, where string, tbInfo *[]interface{}) (*[]interface{}, error) { - log.Debug("XormGetTableRows processing... ") - - row := make(map[string]interface{}) - rows, err := xEngine.Table(tableName).Where(where).Rows(row) - if err != nil { - log.Errorf("Failed to Rows table %s from database: %v", tableName, err) - return nil, err - } - defer rows.Close() - for rows.Next() { - err := rows.Scan(row) - if err != nil { - log.Errorf("Failed to Scan table %s from database: %v", tableName, err) - return nil, err - } - *tbInfo = append(*tbInfo, row) - } - log.Trace("tbInfo:", tbInfo) - return tbInfo, nil -} - -type MeasureThreshold struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - KpiSet []string `json:"kpiSet" xorm:"kpi_set"` - Threshold int64 `json:"threshold"` - Status string `json:"md5Sum" xorm:"md5_sum"` - OrigSeverity string `json:"createTime" xorm:"orig_severity"` - AlarmId string `json:"alarmId" xorm:"alarm_id"` -} - -type NeSoftware struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - FileName string `json:"fileName" xorm:"name"` - Path string `json:"path" xorm:"path"` - Version string `json:"version" ` - Md5Sum string `json:"md5Sum" xorm:"-"` - Comment string `json:"comment" xorm:"description"` - // Status string `json:"status"` - UpdateTime string `json:"createTime" xorm:"-" ` -} - -type NeVersion struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeId string `json:"neId" xorm:"ne_id"` - Version string `json:"version" ` - FilePath string `json:"filePath" xorm:"path"` - NewVersion string `json:"newVersion" xorm:"new_version"` - NewFile string `json:"newFile" xorm:"new_path"` - PreVersion string `json:"preVersion" xorm:"pre_version"` - PreFile string `json:"preFile" xorm:"pre_path"` - Status string `json:"status" xorm:"status"` - UpdateTime string `json:"createTime" xorm:"-" ` -} - -func XormGetDataBySQL(sql string) (*[]map[string]string, error) { - log.Debug("XormGetDataBySQL processing... ") - - rows := make([]map[string]string, 0) - rows, err := DbClient.XEngine.QueryString(sql) - if err != nil { - log.Error("Failed to QueryString:", err) - return nil, err - } - - return &rows, nil -} - -func XormDeleteDataByWhere(where, table string) (int64, error) { - log.Debug("XormDeleteDataByWhere processing... ") - - xSession := DbClient.XEngine.NewSession() - defer xSession.Close() - affected, err := xSession.Table(table).Where(where).Delete() - if err != nil { - log.Error("Failed to Delete:", err) - return 0, err - } - xSession.Commit() - - return affected, nil -} - -func XormDeleteDataByWhereNoSession(where, table string) (int64, error) { - affected, err := DbClient.XEngine.Table(table).Where(where).Delete() - if err != nil { - log.Error("Failed to Delete:", err) - return 0, err - } - return affected, nil -} - -func XormDeleteDataById(id int, table string) (int64, error) { - log.Debug("XormDeleteDataByWhere processing... ") - - xSession := DbClient.XEngine.NewSession() - defer xSession.Close() - affected, err := xSession.Table(table).ID(id).Delete() - if err != nil { - log.Error("Failed to Delete:", err) - return 0, err - } - xSession.Commit() - - return affected, nil -} - -type ColOutput struct { - Name string `json:"name"` - Display string `json:"display"` - Length int `json:"length"` - Alias []string `json:"Alias"` -} - -type ColInput struct { - Name string `json:"name"` - Alias string `json:"Alias"` - Type string `json:"type"` - Length int `json:"length"` - Value any `json:"value"` -} - -type MmlInput struct { - BodyFmt string `json:"bodyFmt"` - BodyKey string `json:"bodyKey"` - CallFunc string `json:"callFunc"` - Cols []ColInput `json:"cols"` -} - -type MmlOutput struct { - RetFmt string `json:"retFmt"` - RetMsg string `json:"retMsg"` - ErrMsg string `json:"errMsg"` - Title string `json:"title"` - SingleList bool `json:"singleList"` - SepSpaceNum int `json:"sepSpaceNum"` - AlignmentM string `json:"alignmentM"` - AlignmentSN string `json:"alignmentSN"` - AlignmentSV string `json:"alignmentSV"` - Cols []ColOutput `json:"cols"` - End string `json:"end"` -} - -type MmlHttpMap struct { - ID int `json:"-" xorm:"id"` - NeType string `json:"neType" xorm:"ne_type"` - Operation string `json:"operation"` - Object string `json:"object"` - Method string `json:"method"` - URI string `json:"uri" xorm:"uri"` - ExtUri string `json:"extUri"` - ParamTag string `json:"paramTag"` - Params string `json:"params"` - Input string `json:"input"` - Output string `json:"output"` -} - -func XormGetMmlHttpMap(table, where string) (*MmlHttpMap, error) { - mmlMap := new(MmlHttpMap) - _, err := DbClient.XEngine.Table(table).Where(where).Get(mmlMap) - if err != nil { - log.Error("Failed to Get:", err) - return nil, err - } - return mmlMap, nil -} - -type MmlCommand struct { - ID int `json:"-" xorm:"id"` - NeType string `json:"neType" xorm:"ne_type"` - Category string `json:"category"` - CatDisplay string `json:"catDisplay"` - Operation string `json:"operation"` - Object string `json:"object" xorm:"object"` - MmlDisplay string `json:"mmlDisplay"` - ParamJson []struct { - Name string `json:"name"` - Alias string `json:"alias"` - Type string `json:"type"` - Optional string `json:"optional"` - Apostr string `json:"apostr"` - Loc string `json:"loc"` - Filter string `json:"filter"` - Display string `json:"display"` - Comment string `json:"comment"` - } `json:"paramJson"` -} - -func XormGetMmlCommand(table, where string) (*MmlCommand, error) { - mmlCmd := new(MmlCommand) - _, err := DbClient.XEngine.Table(table).Where(where).Get(mmlCmd) - if err != nil { - log.Error("Failed to Get:", err) - return nil, err - } - return mmlCmd, nil -} - -type AlarmOMCConfig struct { - ID int `json:"-" xorm:"id"` - ModuleName string `json:"moduleName"` - ConfigTag string `json:"configTag"` - Value string `json:"value"` - ValueJson string `json:"valueJson"` -} - -type ValueJson struct { - AlarmStatus string `json:"alarm_status"` - AlarmType string `json:"alarm_type"` - OrigSeverity string `json:"orig_severity"` - AckUser string `json:"ack_user"` -} - -type AlarmForwardToUsers struct { - Interface string `json:"interface"` - ToUser []string `json:"to_user"` -} - -func XormGetAAConfig() (*ValueJson, error) { - aaConfig := new(AlarmOMCConfig) - _, err := DbClient.XEngine.Table("config"). - Where("module_name=? and config_tag=?", "Alarm", "autoAlarmAck"). - Cols("value", "value_json"). - Get(aaConfig) - if err != nil { - log.Error("Failed to Get:", err) - return nil, err - } - log.Debug("aaConfig:", aaConfig) - valueJson := new(ValueJson) - err = json.Unmarshal([]byte(aaConfig.ValueJson), valueJson) - if err != nil { - log.Error("Failed to Unmarshal:", err) - return nil, err - } - log.Debug("valueJson:", valueJson) - return valueJson, nil -} - -func XormGetAlarmForward(interfaceName string) (*[]string, error) { - alarmForwardConfig := new(AlarmOMCConfig) - _, err := DbClient.XEngine.Table("config"). - Where("module_name=? and config_tag=?", "Alarm", "forwardAlarm"). - Cols("value", "value_json"). - Get(alarmForwardConfig) - if err != nil { - log.Error("Failed to Get:", err) - return nil, err - } - log.Debug("alarmForwardConfig:", alarmForwardConfig) - alarmForwardToUsers := new([]AlarmForwardToUsers) - err = json.Unmarshal([]byte(alarmForwardConfig.ValueJson), alarmForwardToUsers) - if err != nil { - log.Error("Failed to Unmarshal:", err) - return nil, err - } - log.Debug("alarmForwardToUsers:", alarmForwardToUsers) - for _, a := range *alarmForwardToUsers { - if a.Interface == interfaceName { - return &(a.ToUser), nil - } - } - return nil, nil -} - -type AlarmForwardLog struct { - ID int `json:"-" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeID string `json:"neID" xorm:"ne_id"` - AlarmID string `json:"alarmID" xorm:"alarm_id"` - AlarmTitle string `json:"alarmTitle" xorm:"alarm_title"` - AlarmSeq int `json:"alarmSeq" xorm:"alarm_seq"` - EventTime string `json:"eventTime" xorm:"event_time"` - Interface string `json:"interface" xorm:"interface"` - ToUser string `json:"toUser" xorm:"to_user"` - OperResult string `json:"operResult" xorm:"oper_result"` - LogTime string `json:"logTime" xorm:"<-"` -} - -func XormInsertAlarmForwardLog(logData *AlarmForwardLog) (int64, error) { - log.Debug("XormInsertAlarmForwardLog processing... ") - - xSession := xEngine.NewSession() - defer xSession.Close() - affected, err := xSession.Insert(logData) - xSession.Commit() - - return affected, err -} - -type SystemLog struct { - ID int `json:"-" xorm:"pk 'id' autoincr"` - UserName string `json:"user_name" xorm:"user_name"` - ProcessName string `json:"process_name" xorm:"process_name"` - ProcessID int32 `json:"process_id" xorm:"process_id"` - Operation string `json:"operation" xorm:"operation"` - StartTime string `json:"start_time" ` - LogTime string `json:"-" xorm:"-"` -} - -func XormInsertSystemLog(logData *SystemLog) (int64, error) { - log.Info("XormInsertSystemLog processing... ") - - xSession := xEngine.NewSession() - defer xSession.Close() - affected, err := xSession.Insert(logData) - xSession.Commit() - - return affected, err -} - -type Permission struct { - ID int `json:"-" xorm:"pk 'id' autoincr"` - PermissionName string `json:"permissionName"` - Method string `json:"method"` - Element string `json:"element"` - Object string `json:"object"` -} - -func IsPermissionAllowed(token, method, module, dbname, tbname, pack string) (bool, error) { - log.Info("IsPermissionAllowed processing... ") - - exist, err := xEngine.Table("permission"). - Join("INNER", "role_permission", "permission.permission_name = role_permission.p_name"). - Join("INNER", "user_role", "role_permission.r_name = user_role.r_name"). - Join("INNER", "session", "user_role.u_name = session.account_id and session.access_token=?", token). - Where("method in ('*',?) and module in ('*',?) and management in ('*',?) and element in ('*',?) and object in ('*',?)", method, pack, module, dbname, tbname). - Exist() - if err != nil { - return false, err - } - - return exist, nil -} - -type NeLicense struct { - NeType string `json:"neType" xorm:"ne_type"` - NeID string `json:"neID" xorm:"ne_id"` - SerialNo string `json:"serialNo" xorm:"serial_num"` - Capcity int `json:"capcity" xorm:"-"` - Used int `json:"used" xorm:"-"` - FeatureEnabled string `json:"featureEnabled" xorm:"-"` - ExpirationDate string `json:"expirationDate" xorm:"expiry_date"` - Status string `json:"status" xorm:"status"` - Path string `json:"path" xorm:"license_path"` - FileName string `json:"file_name" xorm:"-"` - Comment string `json:"comment" xorm:"remark"` - CreatedAt string `json:"createdAt" xorm:"-"` - UpdatedAt string `json:"updatedAt" xorm:"-"` - DeletedAt string `json:"deletedAt" xorm:"-"` -} - -func XormAdjustmentNeLicense(neType, neID string, value int) (int64, error) { - return 1, nil - //neLicense := NeLicense{NeType: neType, NeID: neID, Capability: value} - // session.LogoutTime.Valid = true - // session.LogoutTime.Time = time.Now() - // res, err := xEngine.Exec("update ne_license set capcity=capcity+? where IFNULL(ne_type, '')=? and IFNULL(ne_id, '')=?", value, neType, neID) - // defer xSession.Close() - - //affected, err := xSession.Table("ne_license").Where("ne_type=? and ne_id=?", neType, neID).Update(&neLicense) - - // //affected, err := xSession.Table("ne_license").SQL("ne_tye=? and ne_id=?", neType, neID).Update(session) - // err := xSession.SQL("update ne_license set capability=capability+? where ne_type=? and ne_id=?", value, neType, neID) - //xSession.Commit() - // affected, err := res.RowsAffected() - // return affected, err -} - -func XormUpdateNeLicense(neType, neID string, capcity int) (int64, error) { - return 1, nil - // var err error - // var res sql.Result - // if neType != "" && neID != "" { - // res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=? and ne_id=?", capcity, neType, neID) - // } else if neType != "" && neID == "" { - // res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=?", capcity, neType) - // } else if neType == "" && neID != "" { - // res, err = xEngine.Exec("update ne_license set capcity=? where ne_id=?", capcity, neID) - // } else { - // res, err = xEngine.Exec("update ne_license set capcity=?", capcity) - // } - - // affected, err := res.RowsAffected() - // return affected, err -} - -type NorthboundCm struct { - ID int `json:"-" xorm:"pk '-' autoincr"` - Timestamp string `json:"timestamp" xorm:"timestamp"` - TimeZone string `json:"timeZone" xorm:"time_zone"` - VendorName string `json:"vendorName" xorm:"vendor_name"` - NeType string `json:"neType" xorm:"ne_type"` - CmVersion string `json:"cmVersion" xorm:"cm_version"` - RmUID string `json:"rmUID" xorm:"rm_uid"` - NeID string `json:"neID" xorm:"ne_id"` - UserLabel string `json:"userLabel" xorm:"user_label"` - ObjectType string `json:"objectType" xorm:"object_type"` - PvFlag string `json:"pvFlag" xorm:"pv_flag"` - VMID string `json:"vmID" xorm:"vm_id"` - VnfInstanceID string `json:"vnf_instance_id"` - ValueJSON string `json:"valueJson" xorm:"value_json"` - Status string `json:"status" xorm:"status"` -} - -func XormGetNorthboundCm(neType string, cmResults *[]NorthboundCm) error { - log.Info("XormGetNorthboundCm processing... ") - - cmResult := new(NorthboundCm) - rows, err := xEngine.Table("nbi_cm"). - Distinct("object_type"). - Where("`ne_type` = ?", neType). - Desc("timestamp"). - Cols("*"). - Rows(cmResult) - if err != nil { - log.Error("Failed to get table nbi_cm:", err) - return err - } - defer rows.Close() - for rows.Next() { - err := rows.Scan(cmResult) - if err != nil { - log.Error("Failed to get table nbi_cm:", err) - return err - } - *cmResults = append(*cmResults, *cmResult) - } - return nil -} - -func XormGetNorthboundCmLatestObject(neType, neID, objectType string) (*NorthboundCm, error) { - log.Info("XormGetNorthboundCmLatestObject processing... ") - - cmResult := new(NorthboundCm) - _, err := xEngine.Table("nbi_cm"). - Where("`ne_type`=? and `ne_id`=? and `object_type`=?", neType, neID, objectType). - Desc("timestamp"). - Cols("*"). - Limit(1). - Get(cmResult) - if err != nil { - log.Error("Failed to get table nbi_cm:", err) - return nil, err - } - - return cmResult, nil -} - -type TraceData struct { - ID int `json:"-" xorm:"pk 'id' autoincr"` - TaskID int `json:"taskID" xorm:"task_id"` - Imsi string `json:"imsi" xorm:"imsi"` - Msisdn string `json:"msisdn" xorm:"msisdn"` - SrcAddr string `json:"srcAddr" xorm:"src_addr"` - DstAddr string `json:"dstAddr" xorm:"dst_addr"` - IfType int `json:"ifType" xorm:"if_type"` - MsgType int `json:"msgType" xorm:"msg_type"` - MsgDirect int `json:"msgDirect" xorm:"msg_direct"` - Length int `json:"length" xorm:"length"` - Timestamp int64 `json:"timestamp" xorm:"timestamp"` - RawMsg []byte `json:"rawMsg" xorm:"raw_msg"` - DecMsg string `json:"decMsg" xorm:"dec_msg"` -} - -func XormGetTraceData(id int) (*TraceData, error) { - result := new(TraceData) - _, err := xEngine.Table("trace_data"). - Where("id=?", id). - Get(result) - if err != nil { - log.Error("Failed to get table trace_data:", err) - return nil, err - } - - return result, nil -} - -func XormUpdateTraceData(id int, data *TraceData) (int64, error) { - affected, err := xEngine.Table("trace_data"). - Where("id=?", id). - Update(data) - if err != nil { - log.Error("Failed to update table trace_data:", err) - return 0, err - } - - return affected, nil -} - -func XormInsertTraceData(data *TraceData) (int64, error) { - affected, err := xEngine.Table("trace_data"). - InsertOne(data) - if err != nil { - log.Error("Failed to insert table trace_data:", err) - return 0, err - } - - return affected, nil -} - -func XormDeleteTraceData(id int) (int64, error) { - affected, err := xEngine.Table("trace_data"). - Where("id=?", id). - Delete() - if err != nil { - log.Error("Failed to delete table trace_data:", err) - return 0, err - } - - return affected, nil -} - -func XormGetTraceRawMsg(id int) (int64, []byte, error) { - var rawMsg []byte - var timestamp int64 - _, err := xEngine.Table("trace_data"). - Where("id=?", id). - Cols("timestamp", "raw_msg"). - Get(×tamp, &rawMsg) - if err != nil { - log.Error("Failed to get table trace_data:", err) - return timestamp, rawMsg, err - } - - return timestamp, rawMsg, nil -} - -func XormGetNEStateInfo(neType, neID string) (string, string, error) { - SN := "-" - Version := "-" - _, err := xEngine.Table("ne_state"). - Where("ne_type=? and ne_id=?", neType, neID). - Desc("timestamp"). - Cols("serial_num", "version"). - Limit(1). - Get(&SN, &Version) - return SN, Version, err -} - -type NeState struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeId string `json:"neId" xorm:"ne_id"` - Version string `json:"version" xorm:"column 'version' VARCHAR(16)"` - Capability uint32 `json:"capability" xorm:"capability"` - SerialNum string `json:"serialNum" xorm:"serial_num"` - ExpiryDate string `json:"expiryDate" xorm:"expiry_date"` - CpuUsage string `json:"cpuUsage" xorm:"cpu_usage"` - MemUsage string `json:"memUsage" xorm:"mem_usage"` - DiskSpace string `json:"diskSpace" xorm:"disk_space"` - Timestamp string `json:"timestamp" xorm:"-" ` -} - -func XormInsertNeState(neState *NeState) (int64, error) { - log.Debug("XormInsertNeState processing... ") - - var affected int64 = 0 - - session := xEngine.NewSession() - defer session.Close() - affected, err := session.InsertOne(neState) - if err != nil { - return 0, err - } - err = session.Commit() - if err != nil { - return 0, err - } - return affected, err -} - -type AlarmDefine struct { - AlarmId string `json:"alarmId" xorm:"alarm_id"` - AlarmCode int `json:"alarmCode" xorm:"alarm_code"` - AlarmTitle string `json:"alarmTitle" xorm:"alarm_title"` - NeType string `json:"neType" xorm:"ne_type"` - AlarmType string `json:"alarmType" xorm:"alarm_type"` - OrigSeverity string `json:"origSeverity" xorm:"orig_severity"` - ObjectUid string `json:"objectUid" xorm:"object_uid"` - ObjectName string `json:"objectName" xorm:"object_name"` - ObjectType string `json:"objectType" xorm:"object_type"` - LocationInfo string `json:"locationInfo"` - SpecificProblem string `json:"specificProblem"` - SpecificProblemId string `json:"specificProblemId" xorm:"specific_problem_id"` - AddInfo string `json:"addInfo" xorm:"add_info"` - Threshold int64 `json:"threshold" xorm:"threshold"` - Status string `json:"status" xorm:"status"` -} - -func XormGetAlarmDefine(alarmCode string) (*AlarmDefine, error) { - log.Debug("XormGetAlarmDefine processing... ") - - alarmDefine := new(AlarmDefine) - _, err := xEngine. - Where("alarm_code=? and status='Active'", alarmCode). - Get(alarmDefine) - if err != nil { - log.Error("Failed to get table alarm_define from database:", err) - return nil, err - } - - return alarmDefine, nil -} diff --git a/lib/eval/evaluate.go b/lib/eval/evaluate.go deleted file mode 100644 index 664d7176..00000000 --- a/lib/eval/evaluate.go +++ /dev/null @@ -1,119 +0,0 @@ -package evaluate - -import ( - "fmt" - "go/ast" - "go/parser" - "go/token" - "math" - "regexp" - "strconv" - "strings" -) - -// Parse and caculate expression -func CalcExpr(expr string, paramValues map[string]any) (float64, error) { - // match parameter with '' - re := regexp.MustCompile(`'([^']+)'`) - matches := re.FindAllStringSubmatch(expr, -1) - - // replace to value - for _, match := range matches { - paramName := match[1] - value, exists := paramValues[paramName] - if !exists { - return 0, fmt.Errorf("parameter '%s' not found", paramName) - } - - expr = strings.Replace(expr, match[0], fmt.Sprintf("%v", value), 1) - } - - // expression to evaluate - result, err := evalExpr(expr) - if math.IsNaN(result) { - return 0.0, err - } - return result, err -} - -// eval 解析和计算表达式 -func evalExpr(expr string) (float64, error) { - //fset := token.NewFileSet() - node, err := parser.ParseExpr(expr) - if err != nil { - return 0, err - } - return evalNode(node) -} - -// EvaluateExpr 解析并计算给定的表达式 -func EvalExpr(expr string, values map[string]any) (float64, error) { - // 解析表达式 - node, err := parser.ParseExpr(expr) - if err != nil { - return 0, err - } - - // 遍历 AST 并替换变量 - ast.Inspect(node, func(n ast.Node) bool { - if ident, ok := n.(*ast.Ident); ok { - if val, ok := values[ident.Name]; ok { - // 替换标识符为对应值 - ident.Name = fmt.Sprintf("%v", val) - } - } - return true - }) - - // 计算表达式 - return evalNode(node) -} - -// eval 递归计算 AST 节点 -func evalNode(node ast.Node) (float64, error) { - var result float64 - - switch n := node.(type) { - case *ast.BinaryExpr: - left, err := evalNode(n.X) - if err != nil { - return 0, err - } - right, err := evalNode(n.Y) - if err != nil { - return 0, err - } - switch n.Op { - case token.ADD: - result = left + right - case token.SUB: - result = left - right - case token.MUL: - result = left * right - case token.QUO: - if right == 0 { - return math.NaN(), fmt.Errorf("divisor cannot be zero") - } - - result = left / right - } - case *ast.BasicLit: - var err error - result, err = strconv.ParseFloat(n.Value, 64) - if err != nil { - return 0, err - } - case *ast.Ident: - val, err := strconv.ParseFloat(n.Name, 64) - if err != nil { - return 0, fmt.Errorf("unsupported expression: %s", n.Name) - } - result = val - case *ast.ParenExpr: - return evalNode(n.X) // 递归评估括号中的表达式 - default: - return 0, fmt.Errorf("unsupported expression: %T", n) - } - - return result, nil -} diff --git a/lib/file/file.go b/lib/file/file.go deleted file mode 100644 index 7bc2a57e..00000000 --- a/lib/file/file.go +++ /dev/null @@ -1,27 +0,0 @@ -package file - -import ( - "os" - "path/filepath" -) - -func GetFileAndDirCount(dir string) (int, int, error) { - var fileCount, dirCount int - - err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if path == dir { - return nil // 跳过当前目录 - } - if info.IsDir() { - dirCount++ - } else { - fileCount++ - } - return nil - }) - - return fileCount, dirCount, err -} diff --git a/lib/file/file_linux.go b/lib/file/file_linux.go deleted file mode 100644 index e8936bb9..00000000 --- a/lib/file/file_linux.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build linux -// +build linux - -package file - -import ( - "fmt" - "os" - "os/user" - "path/filepath" - "syscall" -) - -type FileInfo struct { - FileType string `json:"fileType"` // file type: file/directory - FileMode string `json:"fileMode"` // file mode - LinkCount int64 `json:"linkCount"` // link count - Owner string `json:"owner"` // owner - Group string `json:"group"` // group - Size int64 `json:"size"` // size: xx byte - ModifiedTime int64 `json:"modifiedTime"` // last modified time:seconds - FilePath string `json:"filePath"` // file path - FileName string `json:"fileName"` // file name -} - -func GetFileInfo(dir, suffix string) ([]FileInfo, error) { - var files []FileInfo - - err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if path == dir { - return nil // 跳过当前目录 - } - - fileType := "file" - if info.IsDir() { - fileType = "directory" - } else if info.Mode()&os.ModeSymlink != 0 { - fileType = "symlink" - } - - // check if match suffix - if (suffix != "" && filepath.Ext(path) == suffix) || suffix == "" { - stat, ok := info.Sys().(*syscall.Stat_t) - if !ok { - return fmt.Errorf("not a syscall.Stat_t") - } - userInfo, err := user.LookupId(fmt.Sprint(stat.Uid)) - if err != nil { - return err - } - groupInfo, err := user.LookupGroupId(fmt.Sprint(stat.Gid)) - if err != nil { - return err - } - fileInfo := FileInfo{ - FileType: fileType, - FileMode: info.Mode().String(), - LinkCount: int64(info.Sys().(*syscall.Stat_t).Nlink), - Owner: userInfo.Username, - Group: groupInfo.Name, - Size: info.Size(), - ModifiedTime: info.ModTime().Unix(), - FilePath: dir, - FileName: info.Name(), - } - files = append(files, fileInfo) - } - return nil - }) - if err != nil { - return nil, err - } - return files, nil -} diff --git a/lib/file/file_windows.go b/lib/file/file_windows.go deleted file mode 100644 index 7c97f111..00000000 --- a/lib/file/file_windows.go +++ /dev/null @@ -1,63 +0,0 @@ -//go:build windows -// +build windows - -package file - -import ( - "os" - "path/filepath" -) - -type FileInfo struct { - FileType string `json:"fileType"` // file type: file/directory - FileMode string `json:"fileMode"` // file mode - LinkCount int64 `json:"linkCount"` // link count - Owner string `json:"owner"` // owner - Group string `json:"group"` // group - Size int64 `json:"size"` // size: xx byte - ModifiedTime int64 `json:"modifiedTime"` // last modified time:seconds - FilePath string `json:"filePath"` // file path - FileName string `json:"fileName"` // file name -} - -func GetFileInfo(dir, suffix string) ([]FileInfo, error) { - var files []FileInfo - - err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if path == dir { - return nil // 跳过当前目录 - } - - fileType := "file" - if info.IsDir() { - fileType = "directory" - } else if info.Mode()&os.ModeSymlink != 0 { - fileType = "symlink" - } - - // check if match suffix - if (suffix != "" && filepath.Ext(path) == suffix) || suffix == "" { - fileInfo := FileInfo{ - FileType: fileType, - FileMode: info.Mode().String(), - LinkCount: 0, - Owner: "-", - Group: "-", - Size: info.Size(), - ModifiedTime: info.ModTime().Unix(), - FilePath: dir, - FileName: info.Name(), - } - files = append(files, fileInfo) - } - return nil - }) - if err != nil { - return nil, err - } - return files, nil -} diff --git a/lib/global/exec_linux.go b/lib/global/exec_linux.go deleted file mode 100644 index e4aa8584..00000000 --- a/lib/global/exec_linux.go +++ /dev/null @@ -1,47 +0,0 @@ -//go:build linux -// +build linux - -package global - -import ( - "bytes" - "os/exec" -) - -func ExecCmd(command string) ([]byte, error) { - cmd := exec.Command("/bin/bash", "-c", command) - out, err := cmd.CombinedOutput() - if err != nil { - return nil, err - } - - return out, nil -} - -func ExecShell(command string) error { - in := bytes.NewBuffer(nil) - cmd := exec.Command("sh") - cmd.Stdin = in - in.WriteString(command) - in.WriteString("exit\n") - if err := cmd.Start(); err != nil { - return err - } - return nil -} - -func ExecOsCmd(command, os string) ([]byte, error) { - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - if err != nil { - return nil, err - } - return out, nil -} diff --git a/lib/global/exec_windows.go b/lib/global/exec_windows.go deleted file mode 100644 index 285005c2..00000000 --- a/lib/global/exec_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build windows -// +build windows - -package global - -import ( - "os/exec" -) - -func ExecCmd(command string) ([]byte, error) { - cmd := exec.Command("cmd", "/C", command) - out, err := cmd.CombinedOutput() - if err != nil { - return nil, err - } - - return out, nil -} - -func ExecOsCmd(command, os string) ([]byte, error) { - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - if err != nil { - return nil, err - } - return out, nil -} diff --git a/lib/global/global.go b/lib/global/global.go deleted file mode 100644 index 228fdf20..00000000 --- a/lib/global/global.go +++ /dev/null @@ -1,65 +0,0 @@ -package global - -import "errors" - -// 跨package引用的首字母大写 -const ( - RequestBodyMaxLen = 2000000 - ApiVersionV1 = "v1" - ApiVersionV2 = "v2" - LineBreak = "\n" -) - -const ( - DateTime = "2006-01-02 15:04:05" - DateData = "20060102150405" - DateHour = "2006010215" - DateZone = "2006-01-02 15:04:05 +0000 UTC" -) - -const ( - MaxInt32Number = 2147483647 -) - -const ( - MaxLimitData = 1000 -) - -var ( - Version string = "-" - BuildTime string = "-" - GoVer string = "-" -) - -var ( - DefaultUriPrefix = "/api/rest" -) -var ( - ErrParamsNotAdapted = errors.New("the number of params is not adapted") - - // PM module error message - ErrPMNotFoundData = errors.New("not found PM data") - - // CM module error message - ErrCMNotFoundTargetNE = errors.New("not found target NE") - ErrCMCannotDeleteActiveNE = errors.New("can not delete an active NE") - ErrCMInvalidBackupFile = errors.New("invalid backup file") - ErrCMNotMatchMD5File = errors.New("md5 not match between file and url") - ErrCMNotMatchSignFile = errors.New("digests signatures not match in the file") - ErrCMExistSoftwareFile = errors.New("exist the same software package file") - ErrCMNotFoundTargetSoftware = errors.New("not found the target software package") - ErrCMNotFoundTargetNeVersion = errors.New("not found the target NE version") - ErrCMNotFoundRollbackNeVersion = errors.New("not found the rollback NE version") - ErrCMUnknownServiceAction = errors.New("unknown service action") - ErrCMUnknownInstanceAction = errors.New("unknown instance action") - - ErrCMNotFoundTargetBackupFile = errors.New("not found the target NE backup") - ErrCMUnknownSoftwareFormat = errors.New("unknown software package format") // 未知软件包格式 - - // TRACE module error message - ErrTraceFailedDistributeToNEs = errors.New("failed to distribute trace task to target NEs") - ErrTraceNotCarriedTaskID = errors.New("not carried task id in request url") - - // MML module error define - ErrMmlInvalidCommandFormat = errors.New("invalid mml command format") -) diff --git a/lib/global/kits.go b/lib/global/kits.go deleted file mode 100644 index 22091f08..00000000 --- a/lib/global/kits.go +++ /dev/null @@ -1,728 +0,0 @@ -package global - -import ( - "archive/zip" - "bytes" - "crypto/md5" - "encoding/hex" - "encoding/json" - "fmt" - "io" - "net" - "net/http" - "os" - "path/filepath" - "reflect" - "regexp" - "sort" - "strings" - "time" -) - -const ( - IsIPv4 = "IPv4" - IsIPv6 = "IPv6" - NonIP = "NonIp" -) - -type em struct{} - -func GetPkgName() string { - return reflect.TypeOf(em{}).PkgPath() -} - -// interface{} change to map[string]interface{} -// interface{} data is []interface{} -func ListToMap(list interface{}, key string) map[string]interface{} { - res := make(map[string]interface{}) - arr := ToSlice(list) - for _, row := range arr { - immutable := reflect.ValueOf(row) - val := immutable.FieldByName(key).String() - res[val] = row - } - return res -} - -// interface{} change to []interface{} -func ToSlice(arr interface{}) []interface{} { - ret := make([]interface{}, 0) - v := reflect.ValueOf(arr) - if v.Kind() != reflect.Slice { - ret = append(ret, arr) - return ret - } - l := v.Len() - for i := 0; i < l; i++ { - ret = append(ret, v.Index(i).Interface()) - } - return ret -} - -var TodoList []Todo - -type Todo struct { - Id int64 - Item string -} - -// JSON序列化方式 -func jsonStructToMap(TodoList Todo) (map[string]interface{}, error) { - // 结构体转json - strRet, err := json.Marshal(TodoList) - if err != nil { - return nil, err - } - // json转map - var mRet map[string]interface{} - err1 := json.Unmarshal(strRet, &mRet) - if err1 != nil { - return nil, err1 - } - return mRet, nil -} - -func IsContain(item string, items []string) bool { - for _, e := range items { - if e == item { - return true - } - } - return false -} - -func IsContainP(item string, items *[]string, size int) bool { - for i := 0; i < size; i++ { - if (*items)[i] == item { - return true - } - } - return false -} - -// 将字符串 分割成 字符串数组 -// @s:分割符 -func SplitString(str string, s string) []string { - sa := strings.Split(str, s) - return sa -} - -//  合并字符串数组 -func MergeStringArr(a, b []string) []string { - var arr []string - for _, i := range a { - arr = append(arr, i) - } - for _, j := range b { - arr = append(arr, j) - } - return arr -} - -// 数组去重 -func UniqueStringArr(m []string) []string { - d := make([]string, 0) - tempMap := make(map[string]bool, len(m)) - for _, v := range m { // 以值作为键名 - if tempMap[v] == false { - tempMap[v] = true - d = append(d, v) - } - } - return d -} - -//  合并整型数组 -func MergeArr(a, b []int) []int { - var arr []int - for _, i := range a { - arr = append(arr, i) - } - for _, j := range b { - arr = append(arr, j) - } - return arr -} - -// 数组去重 -func UniqueArr(m []int) []int { - d := make([]int, 0) - tempMap := make(map[int]bool, len(m)) - for _, v := range m { // 以值作为键名 - if tempMap[v] == false { - tempMap[v] = true - d = append(d, v) - } - } - return d -} - -// 升序 -func AscArr(e []int) []int { - sort.Ints(e[:]) - return e -} - -// 降序 -func DescArr(e []int) []int { - sort.Sort(sort.Reverse(sort.IntSlice(e))) - return e -} - -func MatchRmUID(p string, s string) bool { - match, _ := regexp.MatchString(p, s) - return match -} - -type OrderedMap struct { - Order []string - Map map[string]interface{} -} - -func (om *OrderedMap) UnmarshalJson(b []byte) error { - json.Unmarshal(b, &om.Map) - - index := make(map[string]int) - for key := range om.Map { - om.Order = append(om.Order, key) - esc, _ := json.Marshal(key) //Escape the key - index[key] = bytes.Index(b, esc) - } - - sort.Slice(om.Order, func(i, j int) bool { return index[om.Order[i]] < index[om.Order[j]] }) - return nil -} - -func (om OrderedMap) MarshalJson() ([]byte, error) { - var b []byte - buf := bytes.NewBuffer(b) - buf.WriteRune('{') - l := len(om.Order) - for i, key := range om.Order { - km, err := json.Marshal(key) - if err != nil { - return nil, err - } - buf.Write(km) - buf.WriteRune(':') - vm, err := json.Marshal(om.Map[key]) - if err != nil { - return nil, err - } - buf.Write(vm) - if i != l-1 { - buf.WriteRune(',') - } - fmt.Println(buf.String()) - } - buf.WriteRune('}') - fmt.Println(buf.String()) - return buf.Bytes(), nil -} - -func GetBodyCopy(r *http.Request) (*bytes.Buffer, error) { - // If r.bodyBuf present, return the copy - // if r.bodyBuf != nil { - // return bytes.NewBuffer(r.bodyBuf.Bytes()), nil - // } - - // Maybe body is `io.Reader`. - // Note: Resty user have to watchout for large body size of `io.Reader` - if r.Body != nil { - b, err := io.ReadAll(r.Body) - if err != nil { - return nil, err - } - - // Restore the Body - // close(r.Body) - r.Body = io.NopCloser(bytes.NewReader(b)) - - // Return the Body bytes - return bytes.NewBuffer(b), nil - } - return nil, nil -} - -func UnmarshalBody(r *http.Request, v *interface{}, maxLen int64) error { - body, err := io.ReadAll(io.LimitReader(r.Body, maxLen)) - if err != nil { - return err - } - - return json.Unmarshal(body, v) -} - -func SetNotifyUrl(ip string, port uint16, uri string) string { - return fmt.Sprintf("http://%s:%d%s", ip, port, uri) -} - -func GetIps() (ips []string, err error) { - interfaceAddr, err := net.InterfaceAddrs() - if err != nil { - return ips, err - } - - for _, address := range interfaceAddr { - ipNet, isVailIpNet := address.(*net.IPNet) - // 检查ip地址判断是否回环地址 - if isVailIpNet && !ipNet.IP.IsLoopback() { - if ipNet.IP.To4() != nil { - ips = append(ips, ipNet.IP.String()) - } - } - } - return ips, nil -} - -func GetCurrentTimeSliceIndexByPeriod(t time.Time, period int) int { - index := int((t.Hour()*60+t.Minute())/period) - 1 - if index < 0 { - return int(24*60/period) - 1 - } - return index -} - -var ( - cst *time.Location -) - -// RFC3339ToDateTime convert rfc3339 value to china standard time layout -func RFC3339ToDateTime(value string) (string, error) { - ts, err := time.Parse(time.RFC3339, value) - if err != nil { - return "", err - } - - return ts.In(cst).Format("2006-01-02 15:04:05"), nil -} - -// CreateTimeDir 根据当前时间格式来创建文件夹 -func CreateTimeDir(fmt string, path string) string { - folderName := time.Now().Format(fmt) - folderPath := filepath.Join(path, folderName) - if _, err := os.Stat(folderPath); os.IsNotExist(err) { - // 必须分成两步:先创建文件夹、再修改权限 - os.Mkdir(folderPath, 0664) //0644也可以os.ModePerm - os.Chmod(folderPath, 0664) - } - return folderPath -} - -// CreateDir 根据传入的目录名和路径来创建文件夹 -func CreateDir(folderName string, path string) string { - folderPath := filepath.Join(path, folderName) - if _, err := os.Stat(folderPath); os.IsNotExist(err) { - // 必须分成两步:先创建文件夹、再修改权限 - os.MkdirAll(folderPath, 0664) //0644也可以os.ModePerm - os.Chmod(folderPath, 0664) - } - return folderPath -} - -func GetFmtTimeString(srcFmt string, timeString string, dstFmt string) string { - t, _ := time.ParseInLocation(srcFmt, timeString, time.Local) - return t.Format(dstFmt) -} - -func GetFileMD5Sum(filePath string) (string, error) { - file, err := os.Open(filePath) - if err != nil { - return "", err - } - defer file.Close() - md5 := md5.New() - _, err = io.Copy(md5, file) - if err != nil { - return "", err - } - - md5str := hex.EncodeToString(md5.Sum(nil)) - - return md5str, nil -} - -// PathExists check path is exist or no -func PathExists(path string) (bool, error) { - _, err := os.Stat(path) - if err == nil { //文件或者目录存在 - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -// PathExists check path is exist or no -func FilePathExists(filePath string) (bool, error) { - _, err := os.Stat(filePath) - if err == nil { //文件或者目录存在 - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -func GetDayDuration(d1, d2 string) int64 { - a, _ := time.Parse("2006-01-02", d1) - b, _ := time.Parse("2006-01-02", d2) - d := a.Sub(b) - - return (int64)(d.Hours() / 24) -} - -func GetSecondsSinceDatetime(datetimeStr string) (int64, error) { - loc1, _ := time.LoadLocation("Local") - // 解析日期时间字符串为时间对象 - datetime, err := time.ParseInLocation(time.DateTime, datetimeStr, loc1) - if err != nil { - return 0, err - } - - // 计算时间差 - duration := time.Since(datetime) - - // 获取时间差的秒数 - seconds := int64(duration.Seconds()) - - return seconds, nil -} - -func GetSecondDuration(time1, time2 string) (int64, error) { - loc1, _ := time.LoadLocation("Local") - // 解析日期时间字符串为时间对象 - t1, err := time.ParseInLocation(time.DateTime, time1, loc1) - if err != nil { - return 0, err - } - t2, err := time.ParseInLocation(time.DateTime, time2, loc1) - if err != nil { - return 0, err - } - - // 计算时间差 - duration := t2.Sub(t1) - - // 获取时间差的秒数 - seconds := int64(duration.Seconds()) - - return seconds, nil -} - -// 0: invalid ip -// 4: IPv4 -// 6: IPv6 -func ParseIP(s string) (net.IP, int) { - ip := net.ParseIP(s) - if ip == nil { - return nil, 0 - } - for i := 0; i < len(s); i++ { - switch s[i] { - case '.': - return ip, 4 - case ':': - return ip, 6 - } - } - return nil, 0 -} - -func BytesCombine1(pBytes ...[]byte) []byte { - return bytes.Join(pBytes, []byte("")) -} - -func BytesCombine(pBytes ...[]byte) []byte { - length := len(pBytes) - s := make([][]byte, length) - for index := 0; index < length; index++ { - s[index] = pBytes[index] - } - sep := []byte("") - return bytes.Join(s, sep) -} - -func ParseIPAddr(ip string) string { - ipAddr := net.ParseIP(ip) - - if ipAddr != nil { - if ipAddr.To4() != nil { - return IsIPv4 - } else { - return IsIPv6 - } - } - - return NonIP -} - -func CombineHostUri(ip string, port string) string { - var hostUri string = "" - ipType := ParseIPAddr(ip) - if ipType == IsIPv4 { - hostUri = fmt.Sprintf("http://%s:%v", ip, port) - } else { - hostUri = fmt.Sprintf("http://[%s]:%v", ip, port) - } - - return hostUri -} - -func StructToMap(obj interface{}) map[string]interface{} { - objValue := reflect.ValueOf(obj) - objType := objValue.Type() - - m := make(map[string]interface{}) - - for i := 0; i < objValue.NumField(); i++ { - field := objValue.Field(i) - fieldName := objType.Field(i).Name - - m[fieldName] = field.Interface() - } - - return m -} - -// ToMap 结构体转为Map[string]interface{} -func ToMap(in interface{}, tagName string) (map[string]interface{}, error) { - out := make(map[string]interface{}) - - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - - if v.Kind() != reflect.Struct { // 非结构体返回错误提示 - return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v) - } - - t := v.Type() - // 遍历结构体字段 - // 指定tagName值为map中key;字段值为map中value - for i := 0; i < v.NumField(); i++ { - fi := t.Field(i) - if tagValue := fi.Tag.Get(tagName); tagValue != "" { - out[tagValue] = v.Field(i).Interface() - } - } - return out, nil -} - -func ZipOneFile(srcFile, dstZip string, pathFlag bool) error { - zipFile, err := os.Create(dstZip) - if err != nil { - return err - } - defer zipFile.Close() - - zipWriter := zip.NewWriter(zipFile) - defer zipWriter.Close() - - fileToCompress, err := os.Open(srcFile) - if err != nil { - return err - } - defer fileToCompress.Close() - - var fileInZip io.Writer - if pathFlag { - fileInZip, err = zipWriter.Create(srcFile) - if err != nil { - return err - } - } else { - // 获取文件的基本名称 - fileName := filepath.Base(fileToCompress.Name()) - fileInZip, err = zipWriter.Create(fileName) - if err != nil { - return err - } - } - - _, err = io.Copy(fileInZip, fileToCompress) - if err != nil { - return err - } - return nil -} - -func ZipDirectoryFile(srcDir, dstZip string) error { - // Create a new zip file - zipfileWriter, err := os.Create(dstZip) - if err != nil { - return err - } - defer zipfileWriter.Close() - - // Create a new zip archive - zipWriter := zip.NewWriter(zipfileWriter) - defer zipWriter.Close() - - // Walk through the directory and add files to the zip archive - err = filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - // Create a new file header for the current file - header, err := zip.FileInfoHeader(info) - if err != nil { - return err - } - - // Set the name of the file within the zip archive - header.Name = filepath.Join(filepath.Base(srcDir), path[len(srcDir):]) - - // If the current file is a directory, skip it - if info.IsDir() { - return nil - } - - // Create a new file in the zip archive - fileWriter, err := zipWriter.CreateHeader(header) - if err != nil { - return err - } - - // Open the current file - file, err := os.Open(path) - if err != nil { - return err - } - defer file.Close() - - // Copy the contents of the current file to the zip archive - _, err = io.Copy(fileWriter, file) - if err != nil { - return err - } - - return nil - }) - - return err -} - -// 判断软件包是rpm或者deb, 1:rpm, 2:deb, 0:unknown format -func JudgeRpmOrDebPackage(filePath string) (int, error) { - var fileType int = 0 - file, err := os.Open(filePath) - if err != nil { - return fileType, err - } - defer file.Close() - - // Read the first 6 bytes of the file - header := make([]byte, 6) - _, err = file.Read(header) - if err != nil { - return fileType, err - } - - // Check the magic numbers to determine the package format - if string(header) == "!" { - fileType = 1 - } else if string(header) == "!\n" - magic := []byte("!\n") - buffer := make([]byte, len(magic)) - - _, err := file.Read(buffer) - if err != nil && err != io.EOF { - return false - } - - return string(buffer) == string(magic) -} - -func CheckRpmOrDebPackage(filePath string) (int, error) { - var fileType int = 0 - file, err := os.Open(filePath) - if err != nil { - return fileType, err - } - defer file.Close() - - isRpm := isRpmPackage(file) - isDeb := isDebPackage(file) - - if isRpm { - fileType = 1 - } else if isDeb { - fileType = 2 - } else { - fileType = 0 - } - - return fileType, nil -} - -func IsRpmOrDebPackage(filePath string) int { - var fileType int = 0 - - if strings.Contains(filePath, ".rpm") { - fileType = 1 - } else if strings.Contains(filePath, ".deb") { - fileType = 2 - } else { - fileType = 0 - } - - return fileType -} - -func RecurseStructToMap(obj any) map[string]any { - out := make(map[string]any) - v := reflect.ValueOf(obj) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - - // 递归函数,用于处理嵌套结构体 - var recurse func(reflect.Value) any - recurse = func(value reflect.Value) any { - if value.Kind() == reflect.Struct { - nestedOut := make(map[string]any) - for i := 0; i < value.NumField(); i++ { - nestedOut[value.Type().Field(i).Name] = recurse(value.Field(i)) - } - return nestedOut - } else if value.Kind() == reflect.Ptr { - return recurse(value.Elem()) - } - return value.Interface() - } - - t := v.Type() - for i := 0; i < v.NumField(); i++ { - f := v.Field(i) - out[t.Field(i).Name] = recurse(f) - } - return out -} diff --git a/lib/log/logger.go b/lib/log/logger.go deleted file mode 100644 index 3246b89e..00000000 --- a/lib/log/logger.go +++ /dev/null @@ -1,338 +0,0 @@ -// logger for omc/ems - -package log - -import ( - "fmt" - "io" - "log" -) - -// LogLevel defines a log level -type LogLevel int - -// enum all LogLevels -const ( - // following level also match syslog.Priority value - LOG_TRACE LogLevel = iota - LOG_DEBUG - LOG_INFO - LOG_WARN - LOG_ERROR - LOG_FATAL - LOG_OFF - LOG_NODEF -) - -// default log options -const ( - DEFAULT_LOG_PREFIX = "omc" - DEFAULT_LOG_FLAG = log.Lshortfile | log.Ldate | log.Lmicroseconds - DEFAULT_LOG_LEVEL = LOG_DEBUG - DEFAULT_CALL_DEPTH = 3 -) - -// Logger is a logger interface -type Logger interface { - Fatal(v ...interface{}) - Fatalf(format string, v ...interface{}) - Error(v ...interface{}) - Errorf(format string, v ...interface{}) - Warn(v ...interface{}) - Warnf(format string, v ...interface{}) - Info(v ...interface{}) - Infof(format string, v ...interface{}) - Debug(v ...interface{}) - Debugf(format string, v ...interface{}) - Trace(v ...interface{}) - Tracef(format string, v ...interface{}) - - Level() LogLevel - LevelString() string - SetLevel(l LogLevel) -} - -var _ Logger = DiscardLogger{} - -// DiscardLogger don't log implementation for ILogger -type DiscardLogger struct{} - -// Trace empty implementation -func (DiscardLogger) Trace(v ...interface{}) {} - -// Tracef empty implementation -func (DiscardLogger) Tracef(format string, v ...interface{}) {} - -// Debug empty implementation -func (DiscardLogger) Debug(v ...interface{}) {} - -// Debugf empty implementation -func (DiscardLogger) Debugf(format string, v ...interface{}) {} - -// Info empty implementation -func (DiscardLogger) Info(v ...interface{}) {} - -// Infof empty implementation -func (DiscardLogger) Infof(format string, v ...interface{}) {} - -// Warn empty implementation -func (DiscardLogger) Warn(v ...interface{}) {} - -// Warnf empty implementation -func (DiscardLogger) Warnf(format string, v ...interface{}) {} - -// Error empty implementation -func (DiscardLogger) Error(v ...interface{}) {} - -// Errorf empty implementation -func (DiscardLogger) Errorf(format string, v ...interface{}) {} - -// Fatal empty implementation -func (DiscardLogger) Fatal(v ...interface{}) {} - -// Fatalf empty implementation -func (DiscardLogger) Fatalf(format string, v ...interface{}) {} - -// Level empty implementation -func (DiscardLogger) Level() LogLevel { - return LOG_NODEF -} - -// Level empty implementation -func (DiscardLogger) LevelString() string { - return "" -} - -// SetLevel empty implementation -func (DiscardLogger) SetLevel(l LogLevel) {} - -// EmsLogger is the default implment of ILogger -type EmsLogger struct { - TRACE *log.Logger - DEBUG *log.Logger - INFO *log.Logger - WARN *log.Logger - ERROR *log.Logger - FATAL *log.Logger - level LogLevel - levelString []string - depth int -} - -var _ Logger = &EmsLogger{} - -// NewEmsLogger use a special io.Writer as logger output -func NewEmsLogger(out io.Writer) *EmsLogger { - return NewEmsLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG) -} - -// NewEmsLogger2 let you customrize your logger prefix and flag -func NewEmsLogger2(out io.Writer, prefix string, flag int) *EmsLogger { - return NewEmsLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL) -} - -// NewEmsLogger3 let you customrize your logger prefix and flag and logLevel -func NewEmsLogger3(out io.Writer, prefix string, flag int, l LogLevel) *EmsLogger { - return &EmsLogger{ - TRACE: log.New(out, fmt.Sprintf("[%s] [trace] ", prefix), flag), - DEBUG: log.New(out, fmt.Sprintf("[%s] [debug] ", prefix), flag), - INFO: log.New(out, fmt.Sprintf("[%s] [info ] ", prefix), flag), - WARN: log.New(out, fmt.Sprintf("[%s] [warn ] ", prefix), flag), - ERROR: log.New(out, fmt.Sprintf("[%s] [error] ", prefix), flag), - FATAL: log.New(out, fmt.Sprintf("[%s] [fatal] ", prefix), flag), - level: l, - levelString: []string{"trace", "debug", "info", "warn", "error", "fatal"}, - depth: DEFAULT_CALL_DEPTH, - } -} - -// Trace implement ILogger -func (s *EmsLogger) Trace(v ...interface{}) { - if s.level <= LOG_TRACE { - _ = s.TRACE.Output(s.depth, fmt.Sprintln(v...)) - } -} - -// Tracef implement ILogger -func (s *EmsLogger) Tracef(format string, v ...interface{}) { - if s.level <= LOG_TRACE { - _ = s.TRACE.Output(s.depth, fmt.Sprintf(format, v...)) - } -} - -// Debug implement ILogger -func (s *EmsLogger) Debug(v ...interface{}) { - if s.level <= LOG_DEBUG { - _ = s.DEBUG.Output(s.depth, fmt.Sprintln(v...)) - } -} - -// Debugf implement ILogger -func (s *EmsLogger) Debugf(format string, v ...interface{}) { - if s.level <= LOG_DEBUG { - _ = s.DEBUG.Output(s.depth, fmt.Sprintf(format, v...)) - } -} - -// Info implement ILogger -func (s *EmsLogger) Info(v ...interface{}) { - if s.level <= LOG_INFO { - _ = s.INFO.Output(s.depth, fmt.Sprintln(v...)) - } -} - -// Infof implement ILogger -func (s *EmsLogger) Infof(format string, v ...interface{}) { - if s.level <= LOG_INFO { - _ = s.INFO.Output(s.depth, fmt.Sprintf(format, v...)) - } -} - -// Warn implement ILogger -func (s *EmsLogger) Warn(v ...interface{}) { - if s.level <= LOG_WARN { - _ = s.WARN.Output(s.depth, fmt.Sprintln(v...)) - } -} - -// Warnf implement ILogger -func (s *EmsLogger) Warnf(format string, v ...interface{}) { - if s.level <= LOG_WARN { - _ = s.WARN.Output(s.depth, fmt.Sprintf(format, v...)) - } -} - -// Error implement ILogger -func (s *EmsLogger) Error(v ...interface{}) { - if s.level <= LOG_ERROR { - _ = s.ERROR.Output(s.depth, fmt.Sprintln(v...)) - } -} - -// Errorf implement ILogger -func (s *EmsLogger) Errorf(format string, v ...interface{}) { - if s.level <= LOG_ERROR { - _ = s.ERROR.Output(s.depth, fmt.Sprintf(format, v...)) - } -} - -// Warn implement ILogger -func (s *EmsLogger) Fatal(v ...interface{}) { - if s.level <= LOG_FATAL { - _ = s.FATAL.Output(s.depth, fmt.Sprintln(v...)) - } -} - -// Warnf implement ILogger -func (s *EmsLogger) Fatalf(format string, v ...interface{}) { - if s.level <= LOG_FATAL { - _ = s.FATAL.Output(s.depth, fmt.Sprintf(format, v...)) - } -} - -// Level implement ILogger -func (s *EmsLogger) Level() LogLevel { - return s.level -} - -// Level implement ILogger -func (s *EmsLogger) LevelString() string { - return s.levelString[s.level] -} - -// SetLevel implement ILogger -func (s *EmsLogger) SetLevel(l LogLevel) { - s.level = l -} - -var Elogger Logger - -func InitLogger(logFile string, period int, count int, prefix string, logLevel LogLevel) io.Writer { - - /* - logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766) - if err != nil { - panic(err) - } - */ - - logWriter := getLogWriter(logFile, period, count) - Elogger = NewEmsLogger3(logWriter, prefix, DEFAULT_LOG_FLAG, logLevel) - // fmt.Printf("logFile=%s, period=%d, count=%d, prefix=%s, logLevel=%s\n", logFile, period, count, prefix, GetLevelString()) - return logWriter -} - -// Trace implement ILogger -func Trace(v ...interface{}) { - Elogger.Trace(v...) -} - -// Tracef implement ILogger -func Tracef(format string, v ...interface{}) { - Elogger.Tracef(format, v...) -} - -// Debug implement ILogger -func Debug(v ...interface{}) { - Elogger.Debug(v...) -} - -// Debugf implement ILogger -func Debugf(format string, v ...interface{}) { - Elogger.Debugf(format, v...) -} - -// Info implement ILogger -func Info(v ...interface{}) { - Elogger.Info(v...) -} - -// Infof implement ILogger -func Infof(format string, v ...interface{}) { - Elogger.Infof(format, v...) -} - -// Warn implement ILogger -func Warn(v ...interface{}) { - Elogger.Warn(v...) -} - -// Warnf implement ILogger -func Warnf(format string, v ...interface{}) { - Elogger.Warnf(format, v...) -} - -// Error implement ILogger -func Error(v ...interface{}) { - Elogger.Error(v...) -} - -// Errorf implement ILogger -func Errorf(format string, v ...interface{}) { - Elogger.Errorf(format, v...) -} - -// Warn implement ILogger -func Fatal(v ...interface{}) { - Elogger.Fatal(v...) -} - -// Warnf implement ILogger -func Fatalf(format string, v ...interface{}) { - Elogger.Fatalf(format, v...) -} - -// Level implement ILogger -func GetLevel() LogLevel { - return Elogger.Level() -} - -// Level implement ILogger -func GetLevelString() string { - return Elogger.LevelString() -} - -// SetLevel implement ILogger -func SetLevel(l LogLevel) { - Elogger.SetLevel(l) -} diff --git a/lib/log/partition.go b/lib/log/partition.go deleted file mode 100644 index 5d32e583..00000000 --- a/lib/log/partition.go +++ /dev/null @@ -1,71 +0,0 @@ -package log - -import ( - "io" - "time" - - rotatelogs "github.com/lestrrat/go-file-rotatelogs" -) - -type WriteSyncer interface { - io.Writer - Sync() error -} - -// 得到LogWriter -func getLogWriter(filePath string, period, count int) WriteSyncer { - warnIoWriter := getWriter(filePath, period, count) - return addSync(warnIoWriter) -} - -// 日志文件切割 -func getWriter(filename string, period, count int) io.Writer { - // 保存日志count天,每period小时分割一次日志 - duration := time.Hour * time.Duration(period) - var logfile string - if period >= 24 { - logfile = filename + "-%Y%m%d" - } else { - logfile = filename + "-%Y%m%d%H" - } - hook, err := rotatelogs.New( - - logfile, - rotatelogs.WithLinkName(filename), - // rotatelogs.WithMaxAge(duration), - rotatelogs.WithRotationCount(count), - rotatelogs.WithRotationTime(duration), - rotatelogs.WithLocation(time.Local), - ) - - //保存日志30天,每1分钟分割一次日志 - /* - hook, err := rotatelogs.New( - filename+"_%Y%m%d%H%M.log", - rotatelogs.WithLinkName(filename), - rotatelogs.WithMaxAge(time.Hour*24*30), - rotatelogs.WithRotationTime(time.Minute*1), - ) - */ - if err != nil { - panic(err) - } - return hook -} - -func addSync(w io.Writer) WriteSyncer { - switch w := w.(type) { - case WriteSyncer: - return w - default: - return writerWrapper{w} - } -} - -type writerWrapper struct { - io.Writer -} - -func (w writerWrapper) Sync() error { - return nil -} diff --git a/lib/log/syslogger.go.bak b/lib/log/syslogger.go.bak deleted file mode 100644 index e5990202..00000000 --- a/lib/log/syslogger.go.bak +++ /dev/null @@ -1,89 +0,0 @@ -//go:build !windows && !nacl && !plan9 -// +build !windows,!nacl,!plan9 - -package log - -import ( - "fmt" - "log/syslog" -) - -var _ Logger = &SyslogLogger{} - -// SyslogLogger will be depricated -type SyslogLogger struct { - w *syslog.Writer -} - -// NewSyslogLogger implements Logger -func NewSyslogLogger(w *syslog.Writer) *SyslogLogger { - return &SyslogLogger{w: w} -} - -// Trace log content as Trace -func (s *SyslogLogger) Trace(v ...interface{}) { - _ = s.w.Trace(fmt.Sprint(v...)) -} - -// Tracef log content as Trace and format -func (s *SyslogLogger) Tracef(format string, v ...interface{}) { - _ = s.w.Trace(fmt.Sprintf(format, v...)) -} - -// Debug log content as Debug -func (s *SyslogLogger) Debug(v ...interface{}) { - _ = s.w.Debug(fmt.Sprint(v...)) -} - -// Debugf log content as Debug and format -func (s *SyslogLogger) Debugf(format string, v ...interface{}) { - _ = s.w.Debug(fmt.Sprintf(format, v...)) -} - -// Error log content as Error -func (s *SyslogLogger) Error(v ...interface{}) { - _ = s.w.Err(fmt.Sprint(v...)) -} - -// Errorf log content as Errorf and format -func (s *SyslogLogger) Errorf(format string, v ...interface{}) { - _ = s.w.Err(fmt.Sprintf(format, v...)) -} - -// Info log content as Info -func (s *SyslogLogger) Info(v ...interface{}) { - _ = s.w.Info(fmt.Sprint(v...)) -} - -// Infof log content as Infof and format -func (s *SyslogLogger) Infof(format string, v ...interface{}) { - _ = s.w.Info(fmt.Sprintf(format, v...)) -} - -// Warn log content as Warn -func (s *SyslogLogger) Warn(v ...interface{}) { - _ = s.w.Warn(fmt.Sprint(v...)) -} - -// Warnf log content as Warnf and format -func (s *SyslogLogger) Warnf(format string, v ...interface{}) { - _ = s.w.Warn(fmt.Sprintf(format, v...)) -} - -// Fatal log content as Fatal -func (s *SyslogLogger) Fatal(v ...interface{}) { - _ = s.w.Fatal(fmt.Sprint(v...)) -} - -// Fatalf log content as Fatalf and format -func (s *SyslogLogger) Fatalf(format string, v ...interface{}) { - _ = s.w.Fatal(fmt.Sprintf(format, v...)) -} - -// Level shows log level -func (s *SyslogLogger) Level() LogLevel { - return LOG_NODEF -} - -// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created -func (s *SyslogLogger) SetLevel(l LogLevel) {} diff --git a/lib/midware/midhandle.go b/lib/midware/midhandle.go deleted file mode 100644 index 3e79cebf..00000000 --- a/lib/midware/midhandle.go +++ /dev/null @@ -1,80 +0,0 @@ -package midware - -import ( - "net/http" - "strings" - - "be.ems/lib/log" - "be.ems/lib/services" - "be.ems/src/framework/constants" - - "github.com/gorilla/mux" -) - -func LoggerTrace(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Do stuff here - log.Trace("Http Trace Info:") - log.Trace(" From Host:", r.RemoteAddr) - log.Trace(" To Host:", r.Host) - log.Debug(" RequestUri:", r.RequestURI) - log.Trace(" Method:", r.Method) - log.Trace(" Proto:", r.Proto) - log.Trace(" ContentLength:", r.ContentLength) - log.Trace(" User-Agent:", r.Header.Get("User-Agent")) - log.Trace(" Content-Type:", r.Header.Get("Content-Type")) - log.Trace(" AccessToken:", r.Header.Get("AccessToken")) - log.Trace(" Authorization:", r.Header.Get(constants.HEADER_KEY)) - log.Trace("Trace End=====") - //body, _ := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) - // nop-close to ready r.Body !!! - //r.Body = ioutil.NopCloser(bytes.NewReader(body)) - //log.Trace("Body:", string(body)) - // Call the next handler, which can be another middleware in the chain, or the final handler. - // if r.Method == "OPTIONS" { - // services.ResponseStatusOK201Accepted(w) - // return - // } - - next.ServeHTTP(w, r) - }) -} - -// 已禁用 -func OptionProcess(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == "OPTIONS" { - services.ResponseStatusOK201Accepted(w) - return - } - - next.ServeHTTP(w, r) - }) -} - -// 已禁用 -func CheckPermission(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token := r.Header.Get("AccessToken") - vars := mux.Vars(r) - management := vars["managedType"] - element := vars["elementTypeValue"] - object := vars["objectTypeValue"] - pack := "*" - if token != "" && element != "oauth" { - log.Debugf("token:%s, method:%s, management:%s, element:%s, object:%s, pack:%s", token, r.Method, management, element, object, pack) - exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), management, element, object, pack) - if err != nil { - log.Error("Failed to get permission:", err) - services.ResponseForbidden403NotPermission(w) - return - } - if !exist { - log.Error("Not permission!") - services.ResponseForbidden403NotPermission(w) - return - } - } - next.ServeHTTP(w, r) - }) -} diff --git a/lib/midware/mml_log.go b/lib/midware/mml_log.go deleted file mode 100644 index 190e9629..00000000 --- a/lib/midware/mml_log.go +++ /dev/null @@ -1,60 +0,0 @@ -package midware - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - "time" - - "be.ems/lib/core/ctx" - "be.ems/lib/log" - "be.ems/src/framework/database/db" - "be.ems/src/framework/utils/date" -) - -// LogMML mml操作日志搜集 -func LogMML(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // 读取请求体内容 - body, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - // 解析json内参数 - var bodyArgs map[string]any - _ = json.Unmarshal(bytes.Clone(body), &bodyArgs) - // 将请求体内容存储在临时缓冲区中 - buffer := bytes.NewBuffer(body) - r.Body = io.NopCloser(buffer) - - next.ServeHTTP(w, r) - - // 收尾存入数据库的参数 - mmlCmd := bodyArgs["mml"].([]any)[0] - ipAddr := strings.Split(r.RemoteAddr, ":")[0] - neType := ctx.GetParam(r, "elementTypeValue") - neId := ctx.GetQuery(r, "ne_id") - timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS) - - // 响应内容长度和状态码作为结果 - str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}") - strArr := strings.Split(str, " ") - size := strArr[1] - status := strArr[2] - contentType := w.Header().Get("Content-Type") - resultStr := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, contentType) - - // 用户名 - username := ctx.LoginUserToUserName(r) - // 执行插入 - sql := "insert into mml_log (user,ip,ne_type,ne_id,mml,result,log_time)values(?,?,?,?,?,?,?)" - _, sqlerr := db.ExecDB("", sql, []any{username, ipAddr, neType, neId, mmlCmd, resultStr, timeStr}) - if sqlerr != nil { - log.Errorf("insert row : %v", sqlerr.Error()) - } - }) -} diff --git a/lib/midware/operate_log.go b/lib/midware/operate_log.go deleted file mode 100644 index dd028b2b..00000000 --- a/lib/midware/operate_log.go +++ /dev/null @@ -1,135 +0,0 @@ -package midware - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "reflect" - "runtime" - "strings" - "time" - - "be.ems/lib/core/ctx" - "be.ems/src/framework/constants" - "be.ems/src/framework/ip2region" - "be.ems/src/framework/middleware/collectlogs" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/system/model" - "be.ems/src/modules/system/service" -) - -// 敏感属性字段进行掩码 -var maskProperties []string = []string{ - "password", - "oldPassword", - "newPassword", - "confirmPassword", -} - -// LogOperate 操作日志搜集 -func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - startTime := time.Now() - - // 只对前端发送的数据进行记录 - appCodeStr := r.Header.Get("X-App-Code") - if appCodeStr == "" { - next.ServeHTTP(w, r) - return - } - - // 函数名 - funcName := runtime.FuncForPC(reflect.ValueOf(next).Pointer()).Name() - lastDotIndex := strings.LastIndex(funcName, "/") - funcName = funcName[lastDotIndex+1:] - - // 用户名 - username := ctx.LoginUserToUserName(r) - - // 解析ip地址 - ip := strings.Split(r.RemoteAddr, ":")[0] - ipaddr := ip2region.ClientIP(ip) - location := "-" //ip2region.RealAddressByIp(ipaddr) - // 操作日志记录 - operLog := model.SysLogOperate{ - Title: options.Title, - BusinessType: options.BusinessType, - OperaMethod: funcName, - OperaUrl: r.RequestURI, - OperaUrlMethod: r.Method, - OperaIp: ipaddr, - OperaLocation: location, - OperaBy: username, - } - - // 是否需要保存request,参数和值 - if options.IsSaveRequestData && (r.Method == "POST" || r.Method == "PUT") { - // 读取请求体内容 - body, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - // 解析json内参数 - var bodyArgs map[string]any - _ = json.Unmarshal(bytes.Clone(body), &bodyArgs) - // 将请求体内容存储在临时缓冲区中 - buffer := bytes.NewBuffer(body) - r.Body = io.NopCloser(buffer) - - params := bodyArgs - for k, v := range params { - // 敏感属性字段进行掩码 - for _, s := range maskProperties { - if s == k { - params[k] = parse.SafeContent(v.(string)) - break - } - } - } - jsonStr, _ := json.Marshal(params) - paramsStr := string(jsonStr) - if len(paramsStr) > 2000 { - paramsStr = paramsStr[:2000] - } - operLog.OperaParam = paramsStr - } - - next.ServeHTTP(w, r) - - // 响应内容长度和状态码作为结果 - str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}") - strArr := strings.Split(str, " ") - size := strArr[1] - status := strArr[2] - - // 响应状态 - if status == "200" || status == "204" { - operLog.StatusFlag = constants.STATUS_YES - } else { - operLog.StatusFlag = constants.STATUS_NO - } - - // 是否需要保存response,参数和值 - if options.IsSaveResponseData { - contentDisposition := w.Header().Get("Content-Disposition") - contentType := w.Header().Get("Content-Type") - content := contentType + contentDisposition - msg := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, content) - operLog.OperaMsg = msg - } - - // 日志记录时间 - duration := time.Since(startTime) - operLog.CostTime = duration.Milliseconds() - operLog.OperaTime = time.Now().UnixMilli() - - // 保存操作记录到数据库 - service.NewSysLogOperate.Insert(operLog) - - }) - } -} diff --git a/lib/mmlp/parse.go b/lib/mmlp/parse.go deleted file mode 100644 index 02408cec..00000000 --- a/lib/mmlp/parse.go +++ /dev/null @@ -1,1059 +0,0 @@ -package mmlp - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "math" - "net/http" - "regexp" - "strconv" - "strings" - - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/run" - "be.ems/src/framework/constants" - - "github.com/go-resty/resty/v2" -) - -type Param struct { - Name string `json:"name"` - Value string `json:"value"` -} - -type MmlCommand struct { - Operation string `json:"operation"` - Object string `json:"object"` - Params []Param `json:"params"` - PaList []string `json:"paList"` - AaList []string `json:"aaList"` - AaMap map[string]interface{} `json:"aaMap"` - NaMap map[string]interface{} `json:"naMap"` - AaUri []string `json:"aaUri"` - AaLoc []string `json:"aaLoc"` // for loc parameter -} - -type MmlVar struct { - Version string `json:"version"` - Output string `json:"output"` - MmlHome string `json:"mmlHome"` - Limit int `json:"limit"` - User string `json:"user"` - SessionToken string `josn:"sessionToken"` - Authorization string `josn:"authorization"` - HttpUri string `json:"httpUri"` - UserAgent string `json:"userAgent"` - TagNE string `json:"tagNE"` -} - -// func init() { -// OmcMmlVar = &MmlVar{ -// Version: "16.1.1", -// Output: DefaultFormatType, -// Limit: 50, -// } -// } - -// func SetOmcMmlVarOutput(output string) { -// OmcMmlVar.Output = output -// } - -// func SetOmcMmlVarLimit(limit int) { -// OmcMmlVar.Limit = limit -// } - -func splitByColon(str string) []string { - return splitBy(str, ':') -} - -func splitByComma(str string) []string { - return splitBy(str, ',') -} - -func splitBy(str string, sep rune) []string { - var result []string - var stack []string - var current []rune - var quotes, apoFlag bool = false, false - - for _, c := range str { - if c == '{' || c == '[' || (c == '\'' && apoFlag == false) || (c == '"' && quotes == false) { // "'" - apoFlag = true - quotes = true - stack = append(stack, string(c)) - } else if c == '}' || c == ']' || (c == '\'' && apoFlag == true) || (c == '"' && quotes == true) { - apoFlag = false - quotes = false - if len(stack) > 0 { - stack = stack[:len(stack)-1] - } - } - - if c == sep && len(stack) == 0 { - result = append(result, string(current)) - current = []rune{} - } else { - current = append(current, c) - } - } - - result = append(result, string(current)) - return result -} - -func ParseMMLCommand(mmlStr string, mmlComms *[]MmlCommand) error { - log.Info("ParseMMLCommand processing ...") - log.Debug("mmlStr: ", mmlStr) - - mc := new(MmlCommand) - reg := regexp.MustCompile(`\s*;\s*`) - mmls := reg.Split(mmlStr, -1) - for _, mml := range mmls { - log.Trace("mml:", mml) - if len(mml) == 0 { - continue - } - //reg := regexp.MustCompile(`\s*:\s*`) - //ms := reg.Split(mml, -1) - ms := splitByColon(mml) - if len(ms) < 1 || len(ms) > 2 { - err := global.ErrMmlInvalidCommandFormat - log.Error(err) - return err - } - if len(ms) == 2 { - cmd := strings.Trim(ms[0], " ") - reg = regexp.MustCompile(`\s+`) - cs := reg.Split(cmd, -1) - //cs := strings.Split(cmd, " ") - if len(cs) == 2 { - mc.Operation = cs[0] - mc.Object = cs[1] - } else { - err := global.ErrMmlInvalidCommandFormat - log.Error(err) - return err - } - //reg = regexp.MustCompile(`\s*,\s*`) - //reg = regexp.MustCompile(`(?U)(? 0 { - extUri := strings.Join(mml.AaUri, "/") - requestURI = requestURI + fmt.Sprintf(mmlMap.ExtUri, extUri) - } - if mmlMap.Params != "" { - params := strings.Join(mml.AaLoc, "+and+") - params = strings.ReplaceAll(params, " ", "+") // replace " " to "+" - log.Trace("params:", params) - if mmlMap.ParamTag == "SQL" && strings.TrimSpace(params) != "" { - params = "+where+" + params - } - requestURI = fmt.Sprintf("%s%s%s", requestURI, mmlMap.Params, params) - } - return requestURI -} - -func DeploymentLicense(mml *MmlCommand, omcMmlVar *MmlVar, outputJson *dborm.MmlOutput) *[]byte { - var output []byte - log.Debug("mml:", mml) - var srcNeType, srcNeid, dstNeType, dstNeId, value string - for _, Param := range mml.Params { - switch Param.Name { - case "srcnetype": - srcNeType = Param.Value - case "srcneid": - srcNeid = Param.Value - case "dstnetype": - dstNeType = Param.Value - case "dstneid": - dstNeId = Param.Value - case "number": - value = Param.Value - } - } - intValue, _ := strconv.Atoi(value) - log.Debugf("srcNeType:%s, srcNeid:%s dstNeType:%s dstNeId:%s intValue:%d", srcNeType, srcNeid, dstNeType, dstNeId, intValue) - a1, err := dborm.XormAdjustmentNeLicense(srcNeType, srcNeid, intValue) - if err != nil { - log.Error("Failed to Put:", err) - } - - a2, err := dborm.XormAdjustmentNeLicense(dstNeType, dstNeId, -intValue) - if err != nil { - log.Error("Failed to Put:", err) - output = *ParseErrorOutput(err) - } else { - //response := &resty.Response{StatusCode: http.StatusOK} - //output = ParseOutputResponse(omcMmlVar, outputJson, response.) - str := fmt.Sprintf("RetCode = 0 operation succeeded\n\nAffected rows = %d \n\n", a1+a2) - output = []byte(str) - } - - return &output -} - -func AdjustmentLicense(mml *MmlCommand, omcMmlVar *MmlVar, outputJson *dborm.MmlOutput) *[]byte { - var output []byte - log.Debug("mml:", mml) - var neType, neid, number string - for _, Param := range mml.Params { - switch Param.Name { - case "netype": - neType = Param.Value - case "neid": - neid = Param.Value - case "number": - number = Param.Value - } - } - intValue, _ := strconv.Atoi(number) - log.Debugf("neType:%s, neid:%s intValue:%d", neType, neid, intValue) - affected, err := dborm.XormAdjustmentNeLicense(neType, neid, intValue) - if err != nil { - log.Error("Failed to XormAdjustmentNeLicense:", err) - output = *ParseErrorOutput(err) - } else { - str := fmt.Sprintf("RetCode = 0 operation succeeded\n\nAffected rows = %d \n\n", affected) - output = []byte(str) - } - - return &output -} - -func InstallLicense(mml *MmlCommand, omcMmlVar *MmlVar, outputJson *dborm.MmlOutput) *[]byte { - var output []byte - log.Debug("mml:", mml) - var neType, neid, number string - for _, Param := range mml.Params { - switch Param.Name { - case "netype": - neType = Param.Value - case "neid": - neid = Param.Value - case "number": - number = Param.Value - } - } - intValue, _ := strconv.Atoi(number) - log.Debugf("neType:%s, neid:%s intValue:%d", neType, neid, intValue) - affected, err := dborm.XormUpdateNeLicense(neType, neid, intValue) - if err != nil { - log.Error("Failed to XormUpdateNeLicense:", err) - output = *ParseErrorOutput(err) - } else { - str := fmt.Sprintf("RetCode = 0 operation succeeded\n\nAffected rows = %d \n\n", affected) - output = []byte(str) - } - - return &output -} - -func RunShellCommand(mml *MmlCommand, omcMmlVar *MmlVar, outputJson *dborm.MmlOutput) *[]byte { - var output []byte - log.Debug("mml:", mml) - var command string - for _, Param := range mml.Params { - switch Param.Name { - case "cmd": - command = Param.Value - default: - } - } - out, err := run.ExecCmd(command, omcMmlVar.MmlHome) - //cmd := exec.Command("/bin/bash", "-c", command) - - //out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - str := fmt.Sprintf("Command: %s output:\n\n%v\n", command, string(out)) - //output = *ParseErrorOutput(err) - output = []byte(str) - //return &output - } else { - str := fmt.Sprintf("Command: %s output:\n\n%v\n", command, string(out)) - output = []byte(str) - } - - return &output -} - -func TransMml2HttpReq(omcMmlVar *MmlVar, mml *MmlCommand) (*[]byte, error) { - log.Info("TransMml2HttpReq processing ...") - log.Debug("mml: ", mml) - - where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object) - mmlMap, err := dborm.XormGetMmlHttpMap("mml_http_map", where) - if err != nil { - log.Error("Failed to XormGetMmlHttpMap: ", err) - return ParseErrorOutput(err), err - } - if mmlMap == nil { - err := errors.New("Not found mml map") - log.Error(err) - return ParseErrorOutput(err), err - } - log.Trace("mmlMap: ", mmlMap) - if mmlMap.Output == "" { - mmlMap.Output = "{}" - } - outputJson := new(dborm.MmlOutput) - err = json.Unmarshal([]byte(mmlMap.Output), outputJson) - if err != nil { - log.Error("Failed to Unmarshal:", err) - return ParseErrorOutput(err), err - } - log.Trace("outputJson: ", outputJson) - inputJson := new(dborm.MmlInput) - log.Trace("mmlMap.Input: ", mmlMap.Input) - if mmlMap.Input == "" { - mmlMap.Input = "{}" - } - err = json.Unmarshal([]byte(mmlMap.Input), inputJson) - if err != nil { - log.Error("Failed to Unmarshal:", err) - return ParseErrorOutput(err), err - } - log.Trace("inputJson: ", inputJson) - - var requestURI string - var output *[]byte - client := resty.New() - switch strings.ToLower(mmlMap.Method) { - case "get": - requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml) - log.Debugf("method: Get requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: omcMmlVar.Authorization}). - // SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}). - SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI) - if err != nil { - log.Error("Failed to Get:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(omcMmlVar, outputJson, response) - } - case "post": - requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml) - body := ParseInputBody(inputJson, mml) - log.Debugf("method: Post requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: omcMmlVar.Authorization}). - // SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}). - SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(*body). - Post(requestURI) - if err != nil { - log.Error("Failed to Post:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(omcMmlVar, outputJson, response) - } - case "put": - switch inputJson.CallFunc { - case "DeploymentLicense": - output = DeploymentLicense(mml, omcMmlVar, outputJson) - return output, nil - case "AdjustmentLicense": - output = AdjustmentLicense(mml, omcMmlVar, outputJson) - return output, nil - case "InstallLicense": - output = InstallLicense(mml, omcMmlVar, outputJson) - return output, nil - case "RunShellCommand": - output = RunShellCommand(mml, omcMmlVar, outputJson) - return output, nil - default: - } - - requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml) - log.Debugf("method: Put requestURI: %s", requestURI) - body := ParseInputBody(inputJson, mml) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: omcMmlVar.Authorization}). - // SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}). - SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(*body). - Put(requestURI) - if err != nil { - log.Error("Failed to Put:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(omcMmlVar, outputJson, response) - } - case "delete": - requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml) - log.Debugf("method: Delete requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: omcMmlVar.Authorization}). - // SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}). - SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Delete(requestURI) - if err != nil { - log.Error("Failed to Delete:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(omcMmlVar, outputJson, response) - } - case "patch": - requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml) - log.Debugf("method: patch requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{constants.HEADER_KEY: omcMmlVar.Authorization}). - // SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}). - SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Patch(requestURI) - if err != nil { - log.Error("Failed to Patch:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(omcMmlVar, outputJson, response) - } - default: - err := errors.New("not found mml command") - log.Error(err) - output = ParseErrorOutput(err) - } - return output, nil -} - -const ( - MaxMmlOutputBufferSize = 1000000 - FormatTypeJson = "json" - FormatTypeTable = "table" - DefaultFormatType = FormatTypeTable -) - -const ( - RetCodeSucceeded = 0 - RetCodeFailed = 0 -) - -func ParseInputBody(inputJson *dborm.MmlInput, mml *MmlCommand) *[]byte { - inputBody := make(map[string]interface{}) - log.Trace("mml.NaMap:", mml.NaMap) - log.Trace("mml.AaMap:", mml.AaMap) - if strings.ToLower(inputJson.BodyFmt) == "putdb" { - for _, icol := range inputJson.Cols { - log.Trace("icol:", icol) - mml.NaMap[icol.Name] = icol.Value - } - inputBody[inputJson.BodyKey] = mml.NaMap - } else { - inputParams := make([]map[string]interface{}, 0) - inputParams = append(inputParams, mml.NaMap) - inputBody[inputJson.BodyKey] = inputParams - } - - body, err := json.Marshal(inputBody) - if err != nil { - log.Error("Failed to marshal:", err) - } - - log.Trace("inputBody:", inputBody) - log.Trace("body:", string(body)) - return &body -} - -func ParseOutputResponse(omcMmlVar *MmlVar, outputJson *dborm.MmlOutput, response *resty.Response) *[]byte { - var output []byte - var str bytes.Buffer - - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - if omcMmlVar.Output == FormatTypeJson { - code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status()) - title := formatTitle(outputJson.Title) - - json.Indent(&str, response.Body(), "", " ") - log.Trace(str.String()) - - output = global.BytesCombine1([]byte(code), []byte(title), str.Bytes(), []byte("\n")) - } else { - log.Trace("Body:", string(response.Body())) - mapDatas := make(map[string]interface{}, 0) - - err := json.Unmarshal(response.Body(), &mapDatas) - if err != nil { - log.Error("Failed to json.Unmarshal:", err) - //output = *ParseErrorOutput(err) - output = *ParseErrorOutput(string(response.Body())) - return &output - } - log.Trace("mapDatas:", mapDatas) - switch strings.ToLower(outputJson.RetFmt) { - case "getdb": - if len(mapDatas) > 0 { - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - if len(data.([]interface{})) > 0 { - table := (data.([]interface{}))[0] - log.Trace("table:", table) - - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - title := formatTitle(outputJson.Title) - fmtResults := ParseTableOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults)) - } - } - case "deletedb": - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - - if len(data.(map[string]interface{})) > 0 { - table := data.(map[string]interface{}) - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - fmtResults := ParseDBOperOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(fmtResults)) - } - case "postdb": - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - - if len(data.(map[string]interface{})) > 0 { - table := data.(map[string]interface{}) - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - fmtResults := ParseDBOperOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(fmtResults)) - } - case "putdb": - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - if len(data.(map[string]interface{})) > 0 { - table := data.(map[string]interface{}) - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - fmtResults := ParseDBOperOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(fmtResults)) - } - case "getnf": - if len(mapDatas) > 0 { - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - if len(data.([]interface{})) > 0 { - //table := (data.([]interface{}))[0] - //log.Trace("table:", table) - - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - title := formatTitle(outputJson.Title) - fmtResults := ParseNFTableOutput(outputJson, data) - output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults)) - } - } - default: - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - output = global.BytesCombine1([]byte(code)) - } - - } - default: - if omcMmlVar.Output == FormatTypeJson { - code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status()) - //title := formatTitle("Network Element Information") - - json.Indent(&str, response.Body(), "", " ") - log.Trace(str.String()) - - output = global.BytesCombine1([]byte(code), str.Bytes(), []byte("\n")) - } else { - log.Trace("Body:", string(response.Body())) - mapResults := make(map[string]interface{}, 0) - - err := json.Unmarshal(response.Body(), &mapResults) - if err != nil { - log.Error("Failed to json.Unmarshal:", err) - output = *ParseErrorOutput(string(response.Body())) - } else { - log.Trace("mapResults:", mapResults) - if v, ok := mapResults["error"]; ok { - vMap := v.(map[string]interface{}) - if len(vMap) > 0 { - errCode, _ := strconv.Atoi(fmt.Sprintf("%v", vMap["errorCode"])) - errorInfo := vMap["errorInfo"] - output = []byte(fmt.Sprintf(outputJson.ErrMsg, errCode, errorInfo)) - } - } else if v, ok := mapResults["code"]; ok { - errCode, _ := strconv.Atoi(fmt.Sprintf("%v", v)) - errorInfo := mapResults["msg"] - output = []byte(fmt.Sprintf(outputJson.ErrMsg, errCode, errorInfo)) - } else { - output = []byte(fmt.Sprintf("%v", mapResults)) - } - } - } - } - return &output -} - -func ParseDBOperOutput(outputJson *dborm.MmlOutput, cols any) string { - var colOutput []dborm.ColOutput = outputJson.Cols - var value, retFmtCols string - if len(cols.(map[string]interface{})) > 0 { - if len(colOutput) > 0 { - coln := colOutput[0].Name - value = fmt.Sprintf("%v", cols.(map[string]interface{})[coln]) - log.Tracef("coln:%s value:%s", coln, value) - retFmtCols = colOutput[0].Display + " = " + value + "\n\n" - } - } - - return retFmtCols -} - -func ParseNFTableOutput(outputJson *dborm.MmlOutput, cols any) string { - var colOutput []dborm.ColOutput - var fmtColName string - var colName []string - var spaceNum int = 1 - var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left" - - if outputJson.SepSpaceNum != 0 { - spaceNum = outputJson.SepSpaceNum - } - if outputJson.AlignmentM != "" { - alignmentM = outputJson.AlignmentM - } - if outputJson.AlignmentSN != "" { - alignmentSN = outputJson.AlignmentSN - } - if outputJson.AlignmentSV != "" { - alignmentSV = outputJson.AlignmentSV - } - - maxLength := math.MinInt64 - for _, coln := range outputJson.Cols { - log.Trace("coln:", coln) - - if len(coln.Display) > maxLength { - maxLength = len(coln.Display) - } - if coln.Length < len(coln.Display) { - coln.Length = len(coln.Display) - } - - colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display)) - colOutput = append(colOutput, coln) - } - fmtColName = formatLineBySpace(&colName, spaceNum) - log.Trace("fmtColName:", fmtColName) - - var retFmtCols string - var fmtColValues []string - var numberResult int - // for _, colnvs := range cols.([]interface{}) { - // log.Trace("colnvs:", colnvs) - // if colnvs == nil { - // break - // } - numberResult = len(cols.([]interface{})) - - if numberResult == 1 && outputJson.SingleList == true { - colnv := cols.([]interface{})[0] - log.Trace("colnv:", colnv) - - var fmtNV []string - for _, coln := range colOutput { - fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display) - log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName) - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value) - fmtNV = append(fmtNV, fmtName+": "+fmtValue) - } - - fmtResults := strings.Join(fmtNV, "\n") - log.Tracef("fmtResults:\n%s", fmtResults) - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtResults + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } else { - for i := 0; i < numberResult; i++ { - colnv := cols.([]interface{})[i] - log.Trace("colnv:", colnv) - var colValues []string - var newVal []string - for _, coln := range colOutput { - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - if len(coln.Alias) != 0 { - enumVal, _ := strconv.Atoi(value) - value = parseEnumAlias(&(coln.Alias), enumVal) - } - newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value)) - } - colValues = append(colValues, formatLineBySpace(&newVal, spaceNum)) - log.Trace("colValues:", colValues) - fmtColValues = append(fmtColValues, strings.Join(colValues, "\n")) - log.Trace("fmtColValues:", fmtColValues) - } - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } -} - -func ParseTableOutput(outputJson *dborm.MmlOutput, cols any) string { - var colOutput []dborm.ColOutput - var fmtColName string - var colName []string - var spaceNum int = 1 - var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left" - - if outputJson.SepSpaceNum != 0 { - spaceNum = outputJson.SepSpaceNum - } - if outputJson.AlignmentM != "" { - alignmentM = outputJson.AlignmentM - } - if outputJson.AlignmentSN != "" { - alignmentSN = outputJson.AlignmentSN - } - if outputJson.AlignmentSV != "" { - alignmentSV = outputJson.AlignmentSV - } - - maxLength := math.MinInt64 - for _, coln := range outputJson.Cols { - log.Trace("coln:", coln) - - if len(coln.Display) > maxLength { - maxLength = len(coln.Display) - } - if coln.Length < len(coln.Display) { - coln.Length = len(coln.Display) - } - - colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display)) - colOutput = append(colOutput, coln) - } - fmtColName = formatLineBySpace(&colName, spaceNum) - log.Trace("fmtColName:", fmtColName) - - var retFmtCols string - var fmtColValues []string - var numberResult int - for _, colnvs := range cols.(map[string]interface{}) { - log.Trace("colnvs:", colnvs) - if colnvs == nil { - break - } - numberResult = len(colnvs.([]interface{})) - - if numberResult == 1 && outputJson.SingleList == true { - colnv := colnvs.([]interface{})[0] - log.Trace("colnv:", colnv) - - var fmtNV []string - for _, coln := range colOutput { - fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display) - log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName) - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value) - fmtNV = append(fmtNV, fmtName+": "+fmtValue) - } - - fmtResults := strings.Join(fmtNV, "\n") - log.Tracef("fmtResults:\n%s", fmtResults) - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtResults + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } else { - for i := 0; i < numberResult; i++ { - colnv := colnvs.([]interface{})[i] - log.Trace("colnv:", colnv) - var colValues []string - var newVal []string - for _, coln := range colOutput { - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - if len(coln.Alias) != 0 { - enumVal, _ := strconv.Atoi(value) - value = parseEnumAlias(&(coln.Alias), enumVal) - } - newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value)) - } - colValues = append(colValues, formatLineBySpace(&newVal, spaceNum)) - log.Trace("colValues:", colValues) - fmtColValues = append(fmtColValues, strings.Join(colValues, "\n")) - log.Trace("fmtColValues:", fmtColValues) - } - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } - } - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtColName + "\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols -} - -func parseEnumAlias(alias *[]string, enumVal int) string { - return (*alias)[enumVal] -} - -func formatLineBySpace(strArray *[]string, spaceNum int) string { - space := strings.Repeat(" ", spaceNum) - return strings.Join(*strArray, space) -} - -func ParseAlignmentOutput(length int, alignment string, str string) string { - spaceLen := length - len(str) - if spaceLen < 0 { - log.Warnf("len(str=%s)=%d more length=%d", str, len(str), length) - spaceLen = 0 - } - var retStr string - switch alignment { - case "Left": - suffix := strings.Repeat(" ", spaceLen) - retStr = str + suffix - case "Right": - prefix := strings.Repeat(" ", spaceLen) - retStr = prefix + str - log.Tracef("retStr:%s", retStr) - case "Middle": - prefix := strings.Repeat(" ", int(math.Ceil(float64(spaceLen)/2))) - suffix := strings.Repeat(" ", int(math.Floor(float64(spaceLen)/2))) - retStr = prefix + str + suffix - } - log.Tracef("length=%d, spaceLne=%d, alignment=%s, str=%s, retStr=%s", length, spaceLen, alignment, str, retStr) - return retStr -} - -func ParseErrorOutput(err any) *[]byte { - var output []byte - - var formatType string = DefaultFormatType - if formatType == FormatTypeJson { - output = []byte(fmt.Sprintf("ErrorCode = 1 Error message: %v\n\n", err)) - } else { - output = []byte(fmt.Sprintf("RetCode = -1 operation failed: %v\n\n", err)) - } - - return &output -} - -func formatTitle(title string) string { - var builder strings.Builder - builder.WriteString(title) - builder.WriteString("\n") - for i := 0; i < len(title); i++ { - builder.WriteString("-") - } - builder.WriteString("\n") - return builder.String() -} - -func formatTableOutput() { - -} diff --git a/lib/oauth/oauth.go b/lib/oauth/oauth.go deleted file mode 100644 index b261f35f..00000000 --- a/lib/oauth/oauth.go +++ /dev/null @@ -1,157 +0,0 @@ -package oauth - -import ( - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "math/rand" - "net/http" - "strings" - "time" - - "be.ems/lib/log" - - "golang.org/x/crypto/bcrypt" -) - -func RandAccessToken(n int) (ret string) { - allString := "52661fbd-6b84-4fc2-aa1e-17879a5c6c9b" - ret = "" - for i := 0; i < n; i++ { - r := rand.Intn(len(allString)) - ret = ret + allString[r:r+1] - } - return ret -} - -const letterBytes = "abcdef0123456789" -const ( - letterIdxBits = 6 // 6 bits to represent a letter index - letterIdxMask = 1<= 0; { - if remain == 0 { - cache, remain = src.Int63(), letterIdxMax - } - if idx := int(cache & letterIdxMask); idx < len(letterBytes) { - b[i] = letterBytes[idx] - i-- - } - cache >>= letterIdxBits - remain-- - } - - return string(b) -} - -func GenRandToken(prefix string) string { - if prefix == "" { - return RandStringBytes(8) + "-" + RandStringBytes(4) + "-" + - RandStringBytes(4) + "-" + RandStringBytes(4) + "-" + RandStringBytes(12) - } else { - return prefix + "-" + RandStringBytes(8) + "-" + RandStringBytes(4) + "-" + - RandStringBytes(4) + "-" + RandStringBytes(4) + "-" + RandStringBytes(12) - } -} - -type OAuthBody struct { - GrantType string - UserName string - Value string -} - -/* -func IsValidOAuthInfo(oAuthBody OAuthBody) bool { - log.Debug("IsValidOAuthInfo processing... ") - - conf := config.GetYamlConfig() - for _, o := range conf.Auth { - if oAuthBody.GrantType == o.Type && oAuthBody.UserName == o.User && oAuthBody.Value == o.Password { - return true - } - } - - return false -} -*/ - -func IsWrongOAuthInfo(oAuthBody OAuthBody) bool { - log.Debug("IsWrongOAuthInfo processing... ") - - if oAuthBody.GrantType == "" || strings.ToLower(oAuthBody.GrantType) != "password" || - oAuthBody.UserName == "" || oAuthBody.Value == "" { - return true - } - - return false -} - -func GetTokenFromHttpRequest(r *http.Request) string { - for k, v := range r.Header { - log.Tracef("k:%s, v:%s", k, v) - if strings.ToLower(k) == "accesstoken" && len(v) != 0 { - log.Trace("AccessToken:", v[0]) - return v[0] - } - } - - return "" -} - -// IsCarriedToken check token is carried -func IsCarriedToken(r *http.Request) (string, bool) { - - token := GetTokenFromHttpRequest(r) - if token == "" { - return "", false - } - return token, true -} - -// Bcrypt Encrypt 加密明文密码 -func BcryptEncrypt(password string) (string, error) { - hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - return string(hashedBytes), err -} - -// Bcrypt Compare 密文校验 -func BcryptCompare(hashedPassword, password string) error { - return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) -} - -// sha256 crypt -func GetSHA256HashCode(stringMessage string) string { - message := []byte(stringMessage) //字符串转化字节数组 - //创建一个基于SHA256算法的hash.Hash接口的对象 - hash := sha256.New() //sha-256加密 - //输入数据 - hash.Write(message) - //计算哈希值 - bytes := hash.Sum(nil) - //将字符串编码为16进制格式,返回字符串 - hashCode := hex.EncodeToString(bytes) - //返回哈希值 - return hashCode -} - -// sha512 crypt -func GetSHA512HashCode(stringMessage string) string { - message := []byte(stringMessage) //字符串转化字节数组 - //创建一个基于SHA256算法的hash.Hash接口的对象 - hash := sha512.New() //SHA-512加密 - //输入数据 - hash.Write(message) - //计算哈希值 - bytes := hash.Sum(nil) - //将字符串编码为16进制格式,返回字符串 - hashCode := hex.EncodeToString(bytes) - //返回哈希值 - return hashCode -} diff --git a/lib/pair/pair.go b/lib/pair/pair.go deleted file mode 100644 index f779424f..00000000 --- a/lib/pair/pair.go +++ /dev/null @@ -1,37 +0,0 @@ -package pair - -type Pair struct { - Key int - Value int -} - -type PairList []Pair - -type Interface interface { - // Len is the number of elements in the collection. - Len() int - - // Less reports whether the element with index i - // must sort before the element with index j. - // - // If both Less(i, j) and Less(j, i) are false, - // then the elements at index i and j are considered equal. - // Sort may place equal elements in any order in the final result, - // while Stable preserves the original input order of equal elements. - // - // Less must describe a transitive ordering: - // - if both Less(i, j) and Less(j, k) are true, then Less(i, k) must be true as well. - // - if both Less(i, j) and Less(j, k) are false, then Less(i, k) must be false as well. - // - // Note that floating-point comparison (the < operator on float32 or float64 values) - // is not a transitive ordering when not-a-number (NaN) values are involved. - // See Float64Slice.Less for a correct implementation for floating-point values. - Less(i, j int) bool - - // Swap swaps the elements with indexes i and j. - Swap(i, j int) -} - -func (p PairList) Len() int { return len(p) } -func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value } -func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/lib/routes/routes.go b/lib/routes/routes.go deleted file mode 100644 index e276ef18..00000000 --- a/lib/routes/routes.go +++ /dev/null @@ -1,318 +0,0 @@ -package routes - -import ( - "net/http" - - // "log" - - "be.ems/features/aaaa" - "be.ems/features/cdr" - "be.ems/features/cm" - "be.ems/features/dbrest" - "be.ems/features/event" - "be.ems/features/file" - "be.ems/features/fm" - "be.ems/features/lm" - "be.ems/features/mml" - "be.ems/features/pm" - "be.ems/features/security" - "be.ems/features/sm" - "be.ems/features/state" - "be.ems/features/ue" - "be.ems/lib/midware" - "be.ems/lib/services" - "be.ems/src/framework/middleware/collectlogs" - - "github.com/gorilla/mux" -) - -type Router struct { - Method string - Pattern string - Handler http.HandlerFunc - Middleware mux.MiddlewareFunc -} - -var routers []Router - -func init() { - Register("POST", security.UriOauthToken, security.LoginFromOMC, nil) - Register("POST", security.UriOauthHandshake, security.HandshakeFromOMC, nil) - Register("DELETE", security.UriOauthToken, security.LogoutFromOMC, nil) - - Register("POST", security.CustomUriOauthToken, security.LoginFromOMC, nil) - Register("DELETE", security.CustomUriOauthToken, security.LogoutFromOMC, nil) - Register("POST", security.CustomUriOauthHandshake, security.HandshakeFromOMC, nil) - - // System state - Register("GET", state.UriSysState, state.GetStateFromNF, nil) - Register("GET", state.UriSysState2, state.GetStateFromNF, nil) - Register("GET", state.UriSysInfoAll, state.GetAllSysinfoFromNF, nil) - Register("GET", state.UriSysInfoOne, state.GetOneSysinfoFromNF, nil) - Register("GET", state.UriLicenseInfoAll, state.GetAllLicenseInfoFromNF, nil) - Register("GET", state.UriLicenseInfoOne, state.GetOneLicenseInfoFromNF, nil) - - Register("GET", state.CustomUriSysState, state.GetStateFromNF, nil) - Register("GET", state.CustomUriSysState2, state.GetStateFromNF, nil) - Register("GET", state.CustomUriSysInfoAll, state.GetAllSysinfoFromNF, nil) - Register("GET", state.CustomUriSysInfoOne, state.GetOneSysinfoFromNF, nil) - Register("GET", state.CustomUriLicenseInfoAll, state.GetAllLicenseInfoFromNF, nil) - Register("GET", state.CustomUriLicenseInfoOne, state.GetOneLicenseInfoFromNF, nil) - - Register("GET", sm.UriOMCLocalTime, sm.GetOMCLocalTime, nil) - Register("GET", sm.CustomUriOMCLocalTime, sm.GetOMCLocalTime, nil) - - // database management - Register("GET", dbrest.XormGetDataUri, dbrest.DatabaseGetData, nil) - Register("GET", dbrest.XormSelectDataUri, dbrest.DatabaseGetData, nil) - Register("POST", dbrest.XormInsertDataUri, dbrest.DatabaseInsertData, nil) - Register("PUT", dbrest.XormUpdateDataUri, dbrest.DatabaseUpdateData, nil) - Register("DELETE", dbrest.XormDeleteDataUri, dbrest.DatabaseDeleteData, nil) - - Register("GET", dbrest.CustomXormGetDataUri, dbrest.DatabaseGetData, nil) - Register("GET", dbrest.CustomXormSelectDataUri, dbrest.DatabaseGetData, nil) - Register("POST", dbrest.CustomXormInsertDataUri, dbrest.DatabaseInsertData, nil) - Register("PUT", dbrest.CustomXormUpdateDataUri, dbrest.DatabaseUpdateData, nil) - Register("DELETE", dbrest.CustomXormDeleteDataUri, dbrest.DatabaseDeleteData, nil) - - Register("GET", dbrest.XormCommonUri, dbrest.DatabaseGetData, nil) - Register("POST", dbrest.XormCommonUri, dbrest.DatabaseInsertData, nil) - Register("PUT", dbrest.XormCommonUri, dbrest.DatabaseUpdateData, nil) - Register("DELETE", dbrest.XormCommonUri, dbrest.DatabaseDeleteData, nil) - - Register("GET", dbrest.XormDatabaseUri, dbrest.TaskDatabaseGetData, nil) - Register("POST", dbrest.XormDatabaseUri, dbrest.TaskDatabaseInsertData, nil) - Register("PUT", dbrest.XormDatabaseUri, dbrest.TaskDatabaseUpdateData, nil) - Register("DELETE", dbrest.XormDatabaseUri, dbrest.TaskDatabaseDeleteData, nil) - - Register("GET", dbrest.CustomXormCommonUri, dbrest.DatabaseGetData, nil) - Register("POST", dbrest.CustomXormCommonUri, dbrest.DatabaseInsertData, nil) - Register("PUT", dbrest.CustomXormCommonUri, dbrest.DatabaseUpdateData, nil) - Register("DELETE", dbrest.CustomXormCommonUri, dbrest.DatabaseDeleteData, nil) - - Register("GET", dbrest.XormDataRestUri, dbrest.ExtDatabaseGetData, nil) - Register("POST", dbrest.XormDataRestUri, dbrest.ExtDatabaseInsertData, nil) - Register("PUT", dbrest.XormDataRestUri, dbrest.ExtDatabaseUpdateData, nil) - Register("DELETE", dbrest.XormDataRestUri, dbrest.ExtDatabaseDeleteData, nil) - - Register("GET", dbrest.XormExtDataUri, dbrest.ExtDatabaseGetData, nil) - Register("POST", dbrest.XormExtDataUri, dbrest.ExtDatabaseInsertData, nil) - Register("PUT", dbrest.XormExtDataUri, dbrest.ExtDatabaseUpdateData, nil) - Register("DELETE", dbrest.XormExtDataUri, dbrest.ExtDatabaseDeleteData, nil) - - Register("GET", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseGetData, nil) - Register("POST", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseInsertData, nil) - Register("PUT", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseUpdateData, nil) - Register("DELETE", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseDeleteData, nil) - - // alarm restful Register - Register("POST", fm.UriAlarms, fm.PostAlarmFromNF, nil) - Register("Get", fm.UriAlarms, fm.GetAlarmFromNF, nil) - - Register("POST", fm.CustomUriAlarms, fm.PostAlarmFromNF, nil) - Register("Get", fm.CustomUriAlarms, fm.GetAlarmFromNF, nil) - - // performance restful Register - Register("POST", pm.PerformanceUri, pm.PostKPIReportFromNF, nil) - Register("POST", pm.MeasureTaskUri, pm.PostMeasureTaskToNF, midware.LogOperate(collectlogs.OptionNew("MeasureTask", collectlogs.BUSINESS_TYPE_INSERT))) - Register("PUT", pm.MeasureTaskUri, pm.PutMeasureTaskToNF, midware.LogOperate(collectlogs.OptionNew("MeasureTask", collectlogs.BUSINESS_TYPE_UPDATE))) - Register("DELETE", pm.MeasureTaskUri, pm.DeleteMeasureTaskToNF, midware.LogOperate(collectlogs.OptionNew("MeasureTask", collectlogs.BUSINESS_TYPE_DELETE))) - Register("PATCH", pm.MeasureTaskUri, pm.PatchMeasureTaskToNF, midware.LogOperate(collectlogs.OptionNew("MeasureTask", collectlogs.BUSINESS_TYPE_UPDATE))) - Register("POST", pm.MeasureReportUri, pm.PostMeasureReportFromNF, midware.LogOperate(collectlogs.OptionNew("MeasureTask", collectlogs.BUSINESS_TYPE_UPDATE))) - - Register("POST", pm.MeasurementUri, pm.PostMeasurementFromNF, nil) - Register("GET", pm.MeasurementUri, pm.GetMeasurementFromNF, nil) - - Register("POST", pm.CustomPerformanceUri, pm.PostKPIReportFromNF, nil) - Register("POST", pm.CustomMeasureTaskUri, pm.PostMeasureTaskToNF, nil) - Register("PUT", pm.CustomMeasureTaskUri, pm.PutMeasureTaskToNF, nil) - Register("DELETE", pm.CustomMeasureTaskUri, pm.DeleteMeasureTaskToNF, nil) - Register("PATCH", pm.CustomMeasureTaskUri, pm.PatchMeasureTaskToNF, nil) - Register("POST", pm.CustomMeasureReportUri, pm.PostMeasureReportFromNF, nil) - - Register("POST", pm.CustomMeasurementUri, pm.PostMeasurementFromNF, nil) - Register("GET", pm.CustomMeasurementUri, pm.GetMeasurementFromNF, nil) - - // parameter config management - Register("GET", cm.ParamConfigUri, cm.GetParamConfigFromNF, nil) - Register("POST", cm.ParamConfigUri, cm.PostParamConfigToNF, midware.LogOperate(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_INSERT))) - Register("PUT", cm.ParamConfigUri, cm.PutParamConfigToNF, midware.LogOperate(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_UPDATE))) - Register("DELETE", cm.ParamConfigUri, cm.DeleteParamConfigToNF, midware.LogOperate(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_INSERT))) - - Register("GET", cm.CustomParamConfigUri, cm.GetParamConfigFromNF, nil) - Register("POST", cm.CustomParamConfigUri, cm.PostParamConfigToNF, nil) - Register("PUT", cm.CustomParamConfigUri, cm.PutParamConfigToNF, nil) - Register("DELETE", cm.CustomParamConfigUri, cm.DeleteParamConfigToNF, nil) - - // Get/Create/Modify/Delete NE info - Register("GET", cm.UriNeInfo, cm.GetNeInfo, nil) - Register("POST", cm.UriNeInfo, cm.PostNeInfo, midware.LogOperate(collectlogs.OptionNew("NE Info", collectlogs.BUSINESS_TYPE_INSERT))) - Register("PUT", cm.UriNeInfo, cm.PutNeInfo, midware.LogOperate(collectlogs.OptionNew("NE Info", collectlogs.BUSINESS_TYPE_UPDATE))) - Register("DELETE", cm.UriNeInfo, cm.DeleteNeInfo, midware.LogOperate(collectlogs.OptionNew("NE Info", collectlogs.BUSINESS_TYPE_DELETE))) - - // Get/Create/Modify/Delete NE info - Register("GET", cm.CustomUriNeInfo, cm.GetNeInfo, nil) - Register("POST", cm.CustomUriNeInfo, cm.PostNeInfo, nil) - Register("PUT", cm.CustomUriNeInfo, cm.PutNeInfo, nil) - Register("DELETE", cm.CustomUriNeInfo, cm.DeleteNeInfo, nil) - - //ne service action handle - Register("POST", cm.UriNeService, cm.PostNeServiceAction, nil) - //ne service action handle - Register("POST", cm.UriNeInstance, cm.PostNeInstanceAction, nil) - // Post MML command to NF - Register("POST", mml.UriMML, mml.PostMMLToNF, midware.LogMML) - Register("POST", mml.UriMMLDiscard, mml.PostMMLToNF, nil) - Register("POST", mml.UriOmMmlExt, mml.PostMMLToOMC, midware.LogMML) - Register("POST", mml.CustomUriMML, mml.PostMMLToNF, nil) - Register("POST", mml.CustomUriOmMmlExt, mml.PostMMLToOMC, nil) - // post mml2 (standard upf port=5002) - Register("POST", mml.UriMML2, mml.PostMML2ToNF, midware.LogMML) - Register("POST", mml.CustomUriMML2, mml.PostMML2ToNF, nil) - - // Northbound Get NRM - // Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil) - - // Register("GET", nbi.CustomGetNRMUri, nbi.NBIGetNRMFromNF, nil) - - // Import/Export NF CM - Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil) - Register("POST", cm.NeCmUri, cm.ImportCmToNF, midware.LogOperate(collectlogs.OptionNew("Import NF", collectlogs.BUSINESS_TYPE_INSERT))) - - Register("GET", cm.UriNeCmFile, cm.DownloadNeBackupFile, nil) - Register("DELETE", cm.UriNeCmFile, cm.DeleteNeBackupFile, midware.LogOperate(collectlogs.OptionNew("Delete NF Backup", collectlogs.BUSINESS_TYPE_DELETE))) - - Register("GET", cm.CustomNeCmUri, cm.ExportCmFromNF, nil) - Register("POST", cm.CustomNeCmUri, cm.ImportCmToNF, nil) - - Register("GET", cm.CustomUriNeCmFile, cm.DownloadNeBackupFile, nil) - Register("DELETE", cm.CustomUriNeCmFile, cm.DeleteNeBackupFile, nil) - - // Software management - Register("GET", cm.UriSoftware, cm.DownloadSoftwareFile, nil) - //Register("POST", cm.UriSoftware, cm.UploadSoftwareFile, nil) - Register("POST", cm.UriSoftware, cm.UploadSoftwareMultiFile, midware.LogOperate(collectlogs.OptionNew("Software", collectlogs.BUSINESS_TYPE_UPDATE))) - Register("DELETE", cm.UriSoftware, cm.DeleteSoftwareFile, midware.LogOperate(collectlogs.OptionNew("Software", collectlogs.BUSINESS_TYPE_DELETE))) - - Register("POST", cm.UriSoftwareNE, cm.DistributeSoftwareToNF, midware.LogOperate(collectlogs.OptionNew("Software", collectlogs.BUSINESS_TYPE_OTHER))) - Register("PUT", cm.UriSoftwareNE, cm.ActiveSoftwareToNF, midware.LogOperate(collectlogs.OptionNew("Software", collectlogs.BUSINESS_TYPE_OTHER))) - Register("PATCH", cm.UriSoftwareNE, cm.RollBackSoftwareToNF, midware.LogOperate(collectlogs.OptionNew("Software", collectlogs.BUSINESS_TYPE_OTHER))) - - Register("GET", cm.CustomUriSoftware, cm.DownloadSoftwareFile, nil) - Register("POST", cm.CustomUriSoftware, cm.UploadSoftwareFile, nil) - Register("DELETE", cm.CustomUriSoftware, cm.DeleteSoftwareFile, nil) - - Register("POST", cm.CustomUriSoftwareNE, cm.DistributeSoftwareToNF, nil) - Register("PUT", cm.CustomUriSoftwareNE, cm.ActiveSoftwareToNF, nil) - Register("PATCH", cm.CustomUriSoftwareNE, cm.RollBackSoftwareToNF, nil) - - // file management - Register("POST", file.UriFile, file.UploadFile, midware.LogOperate(collectlogs.OptionNew("File", collectlogs.BUSINESS_TYPE_INSERT))) - Register("GET", file.UriFile, file.DownloadFile, midware.LogOperate(collectlogs.OptionNew("File", collectlogs.BUSINESS_TYPE_OTHER))) - Register("DELETE", file.UriFile, file.DeleteFile, midware.LogOperate(collectlogs.OptionNew("File", collectlogs.BUSINESS_TYPE_DELETE))) - - Register("POST", file.CustomUriFile, file.UploadFile, nil) - Register("GET", file.CustomUriFile, file.DownloadFile, nil) - Register("DELETE", file.CustomUriFile, file.DeleteFile, nil) - - // AAAA - Register("GET", aaaa.UriAAAASSO, aaaa.GetSSOFromAAAA, nil) - // AAAA - Register("GET", aaaa.CustomUriAAAASSO, aaaa.GetSSOFromAAAA, nil) - - // UEInfo: SMF - Register("GET", ue.UriUEInfo, ue.GetUEInfoFromNF, nil) - Register("GET", ue.CustomUriUEInfo, ue.GetUEInfoFromNF, nil) - - // UEInfo: PCF - Register("GET", ue.UriPCFUser, ue.GetUEInfoFromNF, nil) - Register("GET", ue.CustomUriPCFUser, ue.GetUEInfoFromNF, nil) - Register("POST", ue.UriPCFUser, ue.PostPCFUserInfo, nil) - Register("POST", ue.CustomUriPCFUser, ue.PostPCFUserInfo, nil) - Register("PUT", ue.UriPCFUser, ue.PutPCFUserInfo, nil) - Register("PUT", ue.CustomUriPCFUser, ue.PutPCFUserInfo, nil) - Register("DELETE", ue.UriPCFUser, ue.DeletePCFUserInfo, nil) - Register("DELETE", ue.CustomUriPCFUser, ue.DeletePCFUserInfo, nil) - - // PCFUEInfo: batch add/modify/delete - Register("POST", ue.UriPCFUserM, ue.PostPCFUserInfo, nil) - Register("POST", ue.CustomUriPCFUserM, ue.PostPCFUserInfo, nil) - Register("PUT", ue.UriPCFUserM, ue.PutPCFUserInfo, nil) - Register("PUT", ue.CustomUriPCFUserM, ue.PutPCFUserInfo, nil) - Register("DELETE", ue.UriPCFUserM, ue.DeletePCFUserInfo, nil) - Register("DELETE", ue.CustomUriPCFUserM, ue.DeletePCFUserInfo, nil) - //PCF User file - Register("GET", ue.UriPCFUserFileExport, ue.GetUEInfoFileExportNF, nil) - Register("PUT", ue.UriPCFUserFileImport, ue.PutPCFUserInfo, nil) - - // UE Number - Register("GET", ue.UriUENum, ue.GetUENumFromNF, nil) - Register("GET", ue.CustomUriUENum, ue.GetUENumFromNF, nil) - - // NBInfo - Register("GET", ue.UriNBInfo, ue.GetNBInfoFromNF, nil) - Register("GET", ue.CustomUriNBInfo, ue.GetNBInfoFromNF, nil) - Register("POST", ue.UriNBState, ue.PostNBInfoFromNF, nil) - Register("POST", ue.CustomUriNBState, ue.PostNBInfoFromNF, nil) - - // NSSF AvailableAMFs - Register("GET", ue.UriNSSFAvailableAMFs, ue.GetAvailableAMFsFromNSSF, nil) - Register("GET", ue.CustomUriNSSFAvailableAMFs, ue.GetAvailableAMFsFromNSSF, nil) - - // NSSF Subscriptions - Register("GET", ue.UriNSSFSubscriptions, ue.GetSubscriptionsFromNSSF, nil) - Register("GET", ue.CustomUriNSSFSubscriptions, ue.GetSubscriptionsFromNSSF, nil) - - // cdr event - Register("POST", cdr.UriCDREvent, cdr.PostCDREventFrom, nil) - Register("POST", cdr.CustomUriCDREvent, cdr.PostCDREventFrom, nil) - - // UE event 上报的UE事件 - Register("POST", event.UriUEEvent, event.PostUEEvent, nil) - // UE event AMF上报的UE事件, 无前缀给到Gin处理 - //Register("POST", event.UriUEEvent, event.PostUEEventFromAMF, nil) - - // 数据库连接情况 - Register("GET", dbrest.UriDbConnection, dbrest.DbConnection, nil) - Register("GET", dbrest.CustomUriDbConnection, dbrest.DbConnection, nil) - Register("POST", dbrest.UriDbStop, dbrest.DbStop, nil) - Register("POST", dbrest.CustomUriDbStop, dbrest.DbStop, nil) - - // 日志表备份 - Register("POST", lm.ExtBackupDataUri, lm.ExtDatabaseBackupData, nil) - Register("POST", lm.CustomExtBackupDataUri, lm.ExtDatabaseBackupData, nil) - -} - -// To resolv rest POST/PUT/DELETE/PATCH cross domain -func OptionsProc(w http.ResponseWriter, r *http.Request) { - services.ResponseStatusOK204NoContent(w) -} - -func NewRouter() *mux.Router { - r := mux.NewRouter() - - // set custom handle for status 404/405 - // r.NotFoundHandler = services.CustomResponseNotFound404Handler() - // r.MethodNotAllowedHandler = services.CustomResponseMethodNotAllowed405Handler() - - r.Use(midware.LoggerTrace) - // r.Use(midware.Cors) - // r.Use(midware.OptionProcess) - // r.Use(midware.ArrowIPAddr) - - for _, router := range routers { - rt := r.Methods(router.Method).Subrouter() - rt.HandleFunc(router.Pattern, router.Handler) - if router.Middleware != nil { - rt.Use(router.Middleware) - } - - } - - return r -} - -func Register(method, pattern string, handler http.HandlerFunc, middleware mux.MiddlewareFunc) { - routers = append(routers, Router{method, pattern, handler, middleware}) -} diff --git a/lib/run/exec_linux.go b/lib/run/exec_linux.go deleted file mode 100644 index e36f89ee..00000000 --- a/lib/run/exec_linux.go +++ /dev/null @@ -1,56 +0,0 @@ -//go:build linux -// +build linux - -package run - -import ( - "bytes" - "os/exec" - - "be.ems/lib/log" -) - -func ExecCmd(command, path string) ([]byte, error) { - log.Debug("Exec command:", command) - - cmd := exec.Command("/bin/bash", "-c", command) - cmd.Dir = path - out, err := cmd.CombinedOutput() - if err != nil { - return out, err - } - - return out, nil -} - -func ExecShell(command string) error { - in := bytes.NewBuffer(nil) - cmd := exec.Command("sh") - cmd.Stdin = in - in.WriteString(command) - in.WriteString("exit\n") - if err := cmd.Start(); err != nil { - return err - } - return nil -} - -func ExecOsCmd(command, os string) error { - log.Debugf("Exec %s command:%s", os, command) - - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - return nil -} diff --git a/lib/run/exec_wasm.go b/lib/run/exec_wasm.go deleted file mode 100644 index 9633073d..00000000 --- a/lib/run/exec_wasm.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build wasm -// +build wasm - -package run - -import ( - "os/exec" - - "be.ems/lib/log" -) - -func ExecCmd(command, path string) ([]byte, error) { - log.Debug("Exec command:", command) - - cmd := exec.Command("cmd", "/C", command) - cmd.Dir = path - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return out, err - } - - return out, nil -} - -func ExecOsCmd(command, os string) error { - log.Debugf("Exec %s command:%s", os, command) - - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - return nil -} diff --git a/lib/run/exec_windows.go b/lib/run/exec_windows.go deleted file mode 100644 index 1af2b979..00000000 --- a/lib/run/exec_windows.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build windows -// +build windows - -package run - -import ( - "os/exec" - - "be.ems/lib/log" -) - -func ExecCmd(command, path string) ([]byte, error) { - log.Debug("Exec command:", command) - - cmd := exec.Command("cmd", "/C", command) - cmd.Dir = path - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return out, err - } - - return out, nil -} - -func ExecOsCmd(command, os string) error { - log.Debugf("Exec %s command:%s", os, command) - - var cmd *exec.Cmd - switch os { - case "Linux": - cmd = exec.Command(command) - case "Windows": - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - log.Tracef("Exec output: %v", string(out)) - if err != nil { - log.Error("exe cmd error: ", err) - return err - } - return nil -} diff --git a/lib/services/file.go b/lib/services/file.go deleted file mode 100644 index 4243cda6..00000000 --- a/lib/services/file.go +++ /dev/null @@ -1,426 +0,0 @@ -package services - -import ( - "bufio" - "bytes" - "fmt" - "io" - "mime/multipart" - "net/http" - "os" - "strconv" - "strings" - - "be.ems/lib/log" -) - -const ( - RootPath = "uploads/" - ChunkRootPath = "uploads_tmp/" -) - -var ( - // FilesMax 限制上传文件的大小为7 MB - FilesMax int64 = 32 << 20 - // ValuesMax 限制POST字段内容的大小 - ValuesMax int64 = 512 -) - -func GetPostFile(w http.ResponseWriter, r *http.Request) { - //获取文件流,第三个返回值是错误对象 - file, header, _ := r.FormFile("file") - //读取文件流为[]byte - b, err := io.ReadAll(file) - if err != nil { - log.Error("Failed to ReadAll:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - //把文件保存到指定位置 - err = os.WriteFile("./upload/test.zip", b, 0644) - if err != nil { - log.Error("Failed to WriteFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - //输出上传时文件名 - log.Debug("filename:", header.Filename) -} - -func GetUploadFile(w http.ResponseWriter, r *http.Request) { - log.Debug("GetUploadFile processing...") - - file, err := os.Create("./test.zip") - if err != nil { - log.Error("Failed to Create:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - _, err = io.Copy(file, r.Body) - if err != nil { - log.Error("Failed to Copy:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } -} - -func GetUploadFormFile(w http.ResponseWriter, r *http.Request) { - // 设置最大的内存限制为32MB - r.ParseMultipartForm(32 << 20) - file, handler, err := r.FormFile("file") - if err != nil { - log.Error("Failed to FormFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - defer file.Close() - log.Debug("Header:%v", handler.Header) - f, err := os.OpenFile("./"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666) - if err != nil { - log.Error("Failed to OpenFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - defer f.Close() - _, err = io.Copy(f, file) - if err != nil { - log.Error("Failed to Copy:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - log.Debug("File uploaded successfully:", handler.Filename) -} - -func HandleUploadFile(r *http.Request, path, newFileName string) (string, error) { - var filePath, fileName string - reader, err := r.MultipartReader() - if err != nil { - log.Error("Failed to MultipartReader:", err) - return "", err - } - - for { - part, err := reader.NextPart() - if err == io.EOF { - break - } else if err != nil { - log.Error("Failed to NextPart:", err) - return "", err - } - - log.Debugf("FileName=[%s], FormName=[%s]", part.FileName(), part.FormName()) - if part.FileName() == "" { // this is FormData - data, _ := io.ReadAll(part) - log.Debugf("FormData=[%s]", string(data)) - } else { // This is FileData - - if newFileName != "" { - fileName = newFileName - } else { - fileName = part.FileName() - } - - err := os.MkdirAll(path, os.ModePerm) - if err != nil { - log.Error("Failed to Mkdir:", err) - return "", err - } - - filePath = path + "/" + fileName - - file, err := os.Create(filePath) - if err != nil { - log.Error("Failed to Create:", err) - return "", err - } - defer file.Close() - _, err = io.Copy(file, part) - if err != nil { - log.Error("Failed to Copy:", err) - return "", err - } - } - } - return fileName, nil -} - -type UploadMultiFileData struct { - SoftwareFileName string `json:"softwareFileName"` - CmsFileName string `json:"cmsFileName"` - Datas map[string][]string `json:"datas"` -} - -func HandleUploadMultiFile(r *http.Request, path, newFileName string) (*UploadMultiFileData, error) { - fileData := new(UploadMultiFileData) - // 解析multipart/form-data请求 - err := r.ParseMultipartForm(100 << 20) // 100MB - if err != nil { - return fileData, err - } - - // 获取文件和数据 - softwareFile := r.MultipartForm.File["file"] - cmsFile := r.MultipartForm.File["cms"] - fileData.Datas = r.MultipartForm.Value - - // 处理文件 - if len(softwareFile) > 0 { - file := softwareFile[0] - // 打开文件 - f, err := file.Open() - if err != nil { - return fileData, err - } - defer f.Close() - - // 创建本地文件 - dst, err := os.Create(path + "/" + file.Filename) - if err != nil { - return fileData, err - } - defer dst.Close() - - fileData.SoftwareFileName = file.Filename - // 将文件内容拷贝到本地文件 - _, err = io.Copy(dst, f) - if err != nil { - return fileData, err - } - } - // 处理文件 - if len(cmsFile) > 0 { - file := cmsFile[0] - // 打开文件 - f, err := file.Open() - if err != nil { - return fileData, err - } - defer f.Close() - - // 创建本地文件 - dst, err := os.Create(path + "/" + file.Filename) - if err != nil { - return fileData, err - } - defer dst.Close() - - fileData.CmsFileName = file.Filename - // 将文件内容拷贝到本地文件 - _, err = io.Copy(dst, f) - if err != nil { - return fileData, err - } - } - - return fileData, nil -} - -func HandleUploadFormFile(w http.ResponseWriter, r *http.Request) { - r.ParseMultipartForm(32 << 20) - //mForm := r.MultipartForm - - for k := range r.MultipartForm.File { - // k is the key of file part - file, fileHeader, err := r.FormFile(k) - if err != nil { - fmt.Println("inovke FormFile error:", err) - return - } - defer file.Close() - fmt.Printf("the uploaded file: name[%s], size[%d], header[%#v]\n", - fileHeader.Filename, fileHeader.Size, fileHeader.Header) - - // store uploaded file into local path - localFileName := "./upload/" + fileHeader.Filename - out, err := os.Create(localFileName) - if err != nil { - fmt.Printf("failed to open the file %s for writing", localFileName) - return - } - defer out.Close() - _, err = io.Copy(out, file) - if err != nil { - fmt.Printf("copy file err:%s\n", err) - return - } - fmt.Printf("file %s uploaded ok\n", fileHeader.Filename) - } -} - -func PostFileHandler(w http.ResponseWriter, r *http.Request) { - fmt.Println("PostFileHandler processing... ") - if !strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") { - // 不支持的 Content-Type 类型 - fmt.Println("Invalid Content-Type: ", r.Header.Get("Content-Type")) - http.Error(w, " Unsupported Content-Type Types", http.StatusBadRequest) - return - } - - // 整个请求的主体大小设置为7.5Mb - r.Body = http.MaxBytesReader(w, r.Body, FilesMax+ValuesMax) - reader, err := r.MultipartReader() - if err != nil { - fmt.Println(err) - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - for { - // A Part represents a single part in a multipart body. - part, err := reader.NextPart() - if err != nil { - if err == io.EOF { - - break - } - - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - fileName := part.FileName() - formName := part.FormName() - var buf = &bytes.Buffer{} - // 非文件字段部分大小限制验证(非文件字段,go中filename会是空) - if fileName == "" { - // "请求主体中非文件字段" + formName + "超出大小限制" - var limitError = fmt.Sprintf("Non-file field %s in request body exceeds size limit", formName) - err = uploadSizeLimit(buf, part, ValuesMax, limitError) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - continue - } - - // 文件字段部分大小限制验证 - // "请求主体中文件字段" + fileName + "超出大小限制" - var limitError = fmt.Sprintf("File field %s in request body exceeds size limit", fileName) - err = uploadSizeLimit(buf, part, FilesMax, limitError) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // 文件创建部分 - if err := uploadFileHandle(r.Header, fileName, buf); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // 非逻辑内容,仅为测试使用 - var chunkNumber = r.Header.Get("chunk-number") - if chunkNumber == "" { - // "文件"+fileName+"上传成功" - http.Error(w, fmt.Sprintf("File %s uploaded successfully", fileName), http.StatusOK) - } else { - // "分片文件 %s %s 上传成功" - http.Error(w, fmt.Sprintf("Sliced file %s %s uploaded successfully.", fileName, chunkNumber), http.StatusOK) - } - } -} - -// 上传内容大小限制 -func uploadSizeLimit(buf *bytes.Buffer, part *multipart.Part, maxLimit int64, limitError string) error { - n, err := io.CopyN(buf, part, maxLimit+1) - if err != nil && err != io.EOF { - fmt.Println("PostFileHandler:", err) - return err - } - maxLimit -= n - if maxLimit < 0 { - return fmt.Errorf("%s", limitError) - } - return nil -} - -// uploadFileHandle handle upload file -func uploadFileHandle(header http.Header, fileName string, buf *bytes.Buffer) error { - var chunkNumberStr = header.Get("chunk-number") - // 1.普通文件上传处理 - if chunkNumberStr == "" { - //创建文件并写入文件内容 - return createFile(RootPath+fileName, buf.Bytes()) - } - // 2.分片文件上传处理 - //2.1读取分片编号 - chunkNumber, err := strconv.Atoi(chunkNumberStr) - if err != nil { - return err - } - //2.2创建分片文件并写入分片内容 - if err := createFile(fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", chunkNumber), buf.Bytes()); err != nil { - return err - } - //2.3确认是否上传完毕 - if header.Get("chunk-final") == "true" { - //2.4合并文件 - if err := mergeChunkFiles(fileName); err != nil { - return err - } - //2.5删除分片 - for i := 0; ; i++ { - chunFileName := fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", i) - err := os.Remove(chunFileName) - if err != nil { - if os.IsNotExist(err) { - break - } - return err - } - } - } - return nil -} - -// 创建文件并写入内容 -func createFile(fileName string, res []byte) error { - newFile, err := os.Create(fileName) - if err != nil { - return err - } - defer func() { - _ = newFile.Close() - }() - bufferedWriter := bufio.NewWriter(newFile) - _, err = bufferedWriter.Write(res) - if err != nil && err != io.EOF { - return err - } - return bufferedWriter.Flush() -} - -// 合并分片文件 -func mergeChunkFiles(fileName string) error { - var ( - n int64 - err error - ) - finalFile, err := os.Create(RootPath + fileName) - if err != nil { - return err - } - defer finalFile.Close() - // 将分片内容写入最终文件 - for i := 0; ; i++ { - chunFile, err := os.Open(fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", i)) - if err != nil { - if os.IsNotExist(err) { - break - } - return err - } - n, err = io.Copy(finalFile, chunFile) - if err != nil { - return err - } - err = chunFile.Close() - if err != nil { - return err - } - if n < 1 { - break - } - } - return nil -} diff --git a/lib/services/response.go b/lib/services/response.go deleted file mode 100644 index 2bdacf1a..00000000 --- a/lib/services/response.go +++ /dev/null @@ -1,39 +0,0 @@ -package services - -import "be.ems/src/framework/resp" - -const ( - CODE_FAIL = resp.CODE_ERROR - CODE_SUCC = resp.CODE_SUCCESS -) - -func ErrResp(msg string) map[string]any { - return map[string]any{"code": CODE_FAIL, "msg": msg} -} - -func DataResp(data any) map[string]any { - return map[string]any{"code": CODE_SUCC, "data": data} -} - -func SuccMessageResp() map[string]any { - return map[string]any{"code": CODE_SUCC, "msg": "success"} -} - -func TotalResp(total int64) map[string]any { - return map[string]any{"code": CODE_SUCC, "total": total} -} - -func TotalDataResp(data any, total any) map[string]any { - return map[string]any{"code": CODE_SUCC, "data": map[string]any{ - "rows": data, "total": total, - }, "msg": "success"} -} - -func SuccResp(va map[string]any) map[string]any { - resp := make(map[string]any) - resp["code"] = CODE_SUCC - for k, v := range va { - resp[k] = v - } - return resp -} diff --git a/lib/services/services.go b/lib/services/services.go deleted file mode 100644 index 22b128ce..00000000 --- a/lib/services/services.go +++ /dev/null @@ -1,983 +0,0 @@ -package services - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "mime/multipart" - "os" - "path/filepath" - - // "log" - "net/http" - "net/url" - "strconv" - "strings" - - "be.ems/lib/config" - "be.ems/lib/dborm" - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/oauth" - "github.com/gorilla/mux" -) - -type NameValue struct { - Name string - Value string -} - -type NameOid struct { - Name string - Oid string -} - -type DataResponse struct { - Data interface{} `json:"data"` -} - -type MapResponse map[string]any - -type NullResponse struct { - nil interface{} -} - -type ErrorResponse struct { - Error interface{} `json:"error"` -} - -type ErrorMessage struct { - ErrorCode string `json:"errorCode"` - ErrorInfo string `json:"errorInfo"` -} - -type SucceedOAuthResponse struct { - AccessToken string `json:"accessToken"` - Expires string `json:"expires"` - // Enum: "0": 不需要修改密码, "1": "FirstLogin",首次登录, "2": PasswordAboutToExpire, 密码即将过期 - ChangePasswordFlag int `json:"changePasswordFlag"` - GroupName string `json:"groupName"` - Roles []string `json:"roles"` - Perms []string `json:"perms"` -} - -type ServiceResponse struct { -} - -func GetUriParamString(r *http.Request, paramName string, sep string, brackets bool, apostr bool) string { - vars := r.URL.Query() - s, ok := vars[paramName] - if !ok { - log.Infof("Parameter Name is not exist, %s", paramName) - return "" - } - if apostr { - for i := 0; i < len(s); i++ { - s[i] = "'" + s[i] + "'" - } - } - pn := strings.Join(s, sep) - if brackets { - pn = fmt.Sprintf("(%s)", pn) - } - - return pn -} - -func GetUriWhereString(r *http.Request) string { - return GetUriParamString(r, "WHERE", " and ", false, false) -} - -func GetUriLocString(r *http.Request) string { - return GetUriParamString(r, "loc", " and ", false, false) -} - -func GetUriPageLimitString(r *http.Request) string { - vars := r.URL.Query() - p, ok := vars["PAGE"] - if !ok { - log.Info("page param is not exist") - return "" - } - - l, ok := vars["LIMIT"] - if !ok { - log.Info("limit param is not exist") - return "" - } - li, _ := strconv.Atoi(l[0]) - pi, _ := strconv.Atoi(p[0]) - ls := fmt.Sprintf("limit %d, %d", li*(pi-1), li) - - log.Debug("Limit array:", ls) - return ls -} - -func ExtGetUriPageLimitString(r *http.Request) string { - vars := r.URL.Query() - p, ok := vars["page"] - if !ok { - log.Info("page param is not exist") - p = append(p, "1") - } - - l, ok := vars["limit"] - if !ok { - log.Info("limit param is not exist") - l = append(l, strconv.Itoa(global.MaxLimitData)) - } - limit, _ := strconv.Atoi(l[0]) - if limit > global.MaxLimitData { - limit = global.MaxLimitData - } - page, _ := strconv.Atoi(p[0]) - limitStr := fmt.Sprintf("limit %d, %d", limit*(page-1), limit) - - log.Debug("limitStr:", limitStr) - return limitStr -} - -func IsJsonContentType(r *http.Request) bool { - hType := r.Header.Get("Content-Type") - return strings.Contains(hType, "application/json") -} - -func IsValidOAuthUri(r *http.Request) bool { - vars := mux.Vars(r) - apiVer := vars["apiVersion"] // 获取Uri - return apiVer == "v1" -} - -func IsVallidContentType(r *http.Request, checkFlag bool) bool { - log.Debug("IsVallidContentType processing ...") - /* - ctype := r.Header["Content-Type"] - log.Debug("ctype:", ctype) - if len(ctype) != 0 && !strings.Contains(ctype[0], "application/json") { - return false - } - */ - if strings.Contains(r.Header.Get("Content-Type"), "application/json") || !checkFlag { - return true - } - return false -} - -func CheckParameterName(r *http.Request) []string { - var errorParams []string - vars := r.URL.Query() - for k, v := range vars { - log.Debug("vars:", k, v) - if k != "rmUIDs" && k != "fields" { - errorParams = append(errorParams, k) - } - } - - return errorParams -} - -func GetRmUIDArr(r *http.Request) []string { - vars := r.URL.Query() - rmUIDs, ok := vars["rmUIDs"] - if !ok { - log.Info("rmUIDs is not exist") - return nil - } - - var rmUIDValues []string - for _, r := range rmUIDs { - if r != "" { - rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`)) - } - } - - return rmUIDValues -} - -func GetAttrNameArr(r *http.Request) []string { - vars := r.URL.Query() - fields, ok := vars["fields"] - if !ok { - log.Info("attributeNames does not exist") - return nil - } - var attrNames []string - for _, a := range fields { - if a != "" { - attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`)) - } - } - - return attrNames -} - -func CheckValidRmUID(rmUIDs []string) []string { - log.Debug("CheckValidRmUID processing... ") - - var invalidRmUIDs []string - for _, r := range rmUIDs { - if !global.MatchRmUID(config.GetRmUIDRegexpFromConfig(), r) { - invalidRmUIDs = append(invalidRmUIDs, r) - } - } - - return invalidRmUIDs -} - -func CheckLocalRmUID(rmUIDs []string) string { - log.Debug("GetLocalRmUID processing... ") - - rmUID := config.GetRmUIDFromConfig() - for _, r := range rmUIDs { - if r == rmUID { - return rmUID - } - } - - return "" -} - -func GetParamsArrByName(paramName string, r *http.Request) []string { - vars := r.URL.Query() - pns, ok := vars[paramName] - if !ok { - log.Infof("%s is not exist", paramName) - return nil - } - - var pnArr []string - for _, pn := range pns { - if pn != "" { - pnArr = global.MergeStringArr(pnArr, strings.Split(pn, `,`)) - } - } - - return pnArr -} - -func GetOperationTypeFromHttpRequest(r *http.Request) string { - for k, v := range r.Header { - log.Tracef("k:%s, v:%s", k, v) - if strings.ToLower(k) == "operationtype" && len(v) != 0 { - log.Trace("OperationType:", v[0]) - return v[0] - } - } - - return "" -} - -func CheckNorthboundValidRequest(w http.ResponseWriter, r *http.Request) (string, error) { - log.Debug("CheckNorthboundValidRequest processing... ") - - var token string = "" - var err error - var ret bool - // response 414-4 uri too long ? (optional) - // todo ... ? - if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() { - log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig()) - ResponseRequestURITooLong414UriTooLong(w) - return token, err - } - - // check media type(content type) only support "application/json" - // response 415-1 - if !IsJsonContentType(r) { - log.Error("invalid Content-Type") - ResponseUnsupportedMediaType415(w) - return token, err - } - - // error processing ... - // 401-1 response - token, ret = oauth.IsCarriedToken(r) - if !ret { - log.Error("accessToken is not carried") - ResponseUnauthorized401AccessTokenNotCarried(w) - return token, err - } - - // 401-2 response - if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) { - log.Error("accessToken fails or does not exist") - ResponseUnauthorized401AccessTokenNotExist(w) - return token, err - } - - if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" { - _, err = dborm.XormUpdateSessionShakeTime(token) - if err != nil { - log.Error("Failed to update session table:", err) - ResponseUnauthorized401AccessTokenNotExist(w) - return token, err - } - } - - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - log.Error("Uri is invalid") - ResponseNotFound404UriNotExist(w, r) - return token, err - } - - // response 406-1 - rmUIDValues := GetRmUIDArr(r) - if rmUIDValues == nil { - log.Error("missing parameter: rmUIDs") - ResponseNotAcceptable406MissingParam(w) - return token, err - } - - // response 406-2 - errorParams := CheckParameterName(r) - if errorParams != nil { - log.Error("parameter name error: ", errorParams) - ResponseNotAcceptable406ParamError(w, errorParams) - return token, err - } - - // response 400-5 - if len(rmUIDValues) == 0 { - log.Error("rmUIDs is wrong or NULL") - ResponseBadRequest400WrongParamValue(w) - return token, err - } - - // response 414-1 - if len(rmUIDValues) > config.GetYamlConfig().Params.RmUIDMaxNum { - log.Error("rmUID greater than", config.GetYamlConfig().Params.RmUIDMaxNum) - ResponseRequestURITooLong414NRMNumExceed(w, config.GetYamlConfig().Params.RmUIDMaxNum) - return token, err - } - - return token, nil -} - -func CheckCommonValidRequest(w http.ResponseWriter, r *http.Request) (string, error) { - log.Debug("CheckCommonValidRequest processing... ") - - var token string = "" - var err error - var ret bool - // response 414-4 uri too long ? (optional) - // todo ... ? - if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() { - log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig()) - ResponseRequestURITooLong414UriTooLong(w) - return token, err - } - - // check media type(content type) only support "application/json" - // response 415-1 - if !IsJsonContentType(r) { - log.Error("Invalid Content-Type") - ResponseUnsupportedMediaType415(w) - return token, err - } - - // error processing ... - // 401-1 response - token, ret = oauth.IsCarriedToken(r) - if !ret { - log.Error("accessToken is not carried") - ResponseUnauthorized401AccessTokenNotCarried(w) - return token, err - } - - // 401-2 response - if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) { - log.Error("accessToken fails or does not exist") - ResponseUnauthorized401AccessTokenNotExist(w) - return token, err - } - - if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" { - _, err = dborm.XormUpdateSessionShakeTime(token) - if err != nil { - log.Error("Failed to update session table:", err) - ResponseUnauthorized401AccessTokenNotExist(w) - return token, err - } - } - - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - log.Error("Uri is invalid") - ResponseNotFound404UriNotExist(w, r) - return token, err - } - - return token, nil -} - -func CheckUserPermission(token, method, module, dbname, tbname, pack string) (bool, error) { - if config.GetYamlConfig().OMC.RBACMode { - if module == "" { - module = "*" - } - if dbname == "" { - dbname = "*" - } - if tbname == "" { - tbname = "*" - } - exist, err := dborm.IsPermissionAllowed(token, method, module, dbname, tbname, pack) - if err != nil { - return false, err - } - if !exist { - return false, nil - } - } - - return true, nil -} - -func IsLocalhost(host string) bool { - if strings.Contains(host, "127.0.0.1") || strings.Contains(host, "::1") { - return true - } - return false -} - -func CheckFrontValidRequest(w http.ResponseWriter, r *http.Request) (string, error) { - log.Debug("CheckFrontValidRequest processing... ") - - var token string = "" - // var err error - // var ret bool - // // response 414-4 uri too long ? (optional) - // // todo ... ? - // if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() { - // err = errors.New("request Uri too long") - // log.Errorf("Request Uri too long: bytes=%d, MaxLen=%d", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig()) - // ResponseRequestURITooLong414UriTooLong(w) - // return token, err - // } - - // /* - // // check media type(content type) only support "application/json" - // // response 415-1 - // if !IsVallidContentType(r) { - // err := errors.New("Invalid Content-Type") - // log.Error(err) - // ResponseUnsupportedMediaType415(w) - // return err - // } - // */ - - // // error processing ... - // // 401-1 response - // if config.GetYamlConfig().Auth.Token && !IsLocalhost(r.RemoteAddr) { - // token, ret = oauth.IsCarriedToken(r) - // if !ret { - // err = errors.New("accessToken is not carried") - // log.Error(err) - // ResponseUnauthorized401AccessTokenNotCarried(w) - // return token, err - // } - - // // 401-2 response - // if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) { - // err = errors.New("accessToken fails or does not exist") - // log.Error(err) - // ResponseUnauthorized401AccessTokenNotExist(w) - // return token, err - // } - - // if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" { - // _, err = dborm.XormUpdateSessionShakeTime(token) - // if err != nil { - // log.Error("Failed to update session table:", err) - // ResponseUnauthorized401AccessTokenNotExist(w) - // return token, err - // } - // } - - // } - - // vars := mux.Vars(r) - // apiVer := vars["apiVersion"] - // if apiVer != global.ApiVersionV1 { - // err = errors.New("uri is invalid") - // log.Error(err) - // ResponseNotFound404UriNotExist(w, r) - // return token, err - // } - - return token, nil -} - -func CheckExtValidRequest(w http.ResponseWriter, r *http.Request) (string, error) { - log.Debug("CheckExtValidRequest processing... ") - - var token string = "" - var err error - var ret bool - // error processing ... - // 401-1 response - if config.GetYamlConfig().Auth.Token { - token, ret = oauth.IsCarriedToken(r) - if !ret { - err = errors.New("accessToken is not carried") - log.Error(err) - ResponseUnauthorized401AccessTokenNotCarried(w) - return token, err - } - - // 401-2 response - if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) { - err = errors.New("accessToken fails or does not exist") - log.Error(err) - ResponseUnauthorized401AccessTokenNotExist(w) - return token, err - } - - if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" { - _, err = dborm.XormUpdateSessionShakeTime(token) - if err != nil { - log.Error("Failed to update session table:", err) - ResponseUnauthorized401AccessTokenNotExist(w) - return token, err - } - } - } - - vars := mux.Vars(r) - apiVer := vars["apiVersion"] - if apiVer != global.ApiVersionV1 { - err = errors.New("uri is invalid") - log.Error(err) - ResponseNotFound404UriNotExist(w, r) - return token, err - } - - return token, nil -} - -func ResponseStatusOK200Login(w http.ResponseWriter, token string) { - var oAuthResponse SucceedOAuthResponse - oAuthResponse.AccessToken = token - oAuthResponse.Expires = strconv.Itoa((int)(config.GetExpiresFromConfig())) - ResponseWithJson(w, http.StatusOK, oAuthResponse) -} - -func ResponseStatusOK200Null(w http.ResponseWriter) { - response := NullResponse{""} - ResponseWithJson(w, http.StatusOK, response) -} - -func ResponseStatusOK204NoContent(w http.ResponseWriter) { - ResponseWithJson(w, http.StatusNoContent, "") -} - -func ResponseStatusOK201Accepted(w http.ResponseWriter) { - ResponseWithJson(w, http.StatusAccepted, "") -} - -type SSORedirect struct { - User string `json:"user"` - Token string `json:"token"` -} - -func ResponseRedirect(w http.ResponseWriter, redirectUrl, user, token string) { - w.Header().Set("Cache-Control", "must-revalidate, no-store") - w.Header().Set("Content-Type", " text/html;charset=UTF-8") - w.Header().Set("Location", redirectUrl) //跳转地址设置 - //w.WriteHeader(http.StatusTemporaryRedirect) //重定向! - ssoRedirect := &SSORedirect{user, token} - ResponseWithJson(w, http.StatusTemporaryRedirect, *ssoRedirect) -} - -func ResponseBadRequest400RmUIDsIsInvalid(w http.ResponseWriter, rmUIDs []string) { - errorMessage := ErrorMessage{"1", "rmUIDs is invalid:" + strings.Join(rmUIDs, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusBadRequest, errorResponse) -} - -func ResponseBadRequest400DuplicateSubId(w http.ResponseWriter, SubIds string) { - errorMessage := ErrorMessage{"2", "Duplicate with resource subscription id:" + SubIds} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusBadRequest, errorResponse) -} - -func ResponseBadRequest400DuplicateAlarmId(w http.ResponseWriter, AlarmIds string) { - errorMessage := ErrorMessage{"3", "Duplicate with alarm subscription id: " + AlarmIds} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusBadRequest, errorResponse) -} - -func ResponseBadRequest400IncorrectLogin(w http.ResponseWriter) { - errorMessage := ErrorMessage{"4", "incorrect username and password"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusBadRequest, errorResponse) -} - -func ResponseBadRequest400WrongParamValue(w http.ResponseWriter) { - errorMessage := ErrorMessage{"5", "wrong parameter value"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusBadRequest, errorResponse) -} - -func ResponseBadRequest400CMCALoginError(w http.ResponseWriter) { - errorMessage := ErrorMessage{"6", "CMCA centralized authentication login error"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusBadRequest, errorResponse) -} - -func ResponseBadRequest400InvalidJson(w http.ResponseWriter) { - errorMessage := ErrorMessage{"7", "invalid json format"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusUnauthorized, errorResponse) -} - -func ResponseUnauthorized401AccessTokenNotCarried(w http.ResponseWriter) { - errorMessage := ErrorMessage{"1", "accessToken is not carried"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusUnauthorized, errorResponse) -} - -func ResponseUnauthorized401AccessTokenNotExist(w http.ResponseWriter) { - errorMessage := ErrorMessage{"2", "accessToken fails or does not exist"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusUnauthorized, errorResponse) -} - -func ResponseForbidden403NotPermission(w http.ResponseWriter) { - errorMessage := ErrorMessage{"1", "do not have the operation permissions"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusForbidden, errorResponse) -} - -func ResponseForbidden403MultiLoginNotAllowed(w http.ResponseWriter) { - errorMessage := ErrorMessage{"2", "multiple logins are not allowed"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusForbidden, errorResponse) -} - -func ResponseNotFound404UriNotExist(w http.ResponseWriter, r *http.Request) { - if r.Method == "OPTIONS" { - ResponseStatusOK204NoContent(w) - return - } - errorMessage := ErrorMessage{"1", "the requested URI does not exist"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404UriNotExistExt(w http.ResponseWriter) { - errorMessage := ErrorMessage{"1", "the requested URI does not exist"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func CustomResponseNotFound404Handler() http.Handler { - return http.HandlerFunc(ResponseNotFound404UriNotExist) -} - -func ResponseNotFound404NRMNotExist(w http.ResponseWriter, rmUIDs []string) { - errorMessage := ErrorMessage{"2", "rmUIDs does not exist: " + strings.Join(rmUIDs, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404PMNotExist(w http.ResponseWriter, rmUIDs []string) { - errorMessage := ErrorMessage{"3", "rmUIDs does not exist: " + strings.Join(rmUIDs, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404AlarmNotExist(w http.ResponseWriter, AlarmIds []string) { - errorMessage := ErrorMessage{"4", "alarmIds does not exist: " + strings.Join(AlarmIds, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404GetSubscriptionNotExist(w http.ResponseWriter, SubIds []string) { - errorMessage := ErrorMessage{"5", "subscription id does not exist: " + strings.Join(SubIds, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404DeleteSubscriptionNotExist(w http.ResponseWriter, SubIds []string) { - errorMessage := ErrorMessage{"6", "subscription id does not exist: " + strings.Join(SubIds, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404GetAlarmSubscriptionNotExist(w http.ResponseWriter, SubIds []string) { - errorMessage := ErrorMessage{"7", "subscription id does not exist: " + strings.Join(SubIds, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseNotFound404DeleteAlarmSubscriptionNotExist(w http.ResponseWriter, SubIds []string) { - errorMessage := ErrorMessage{"8", "subscription id does not exist: " + strings.Join(SubIds, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotFound, errorResponse) -} - -func ResponseMethodNotAllowed405(w http.ResponseWriter, r *http.Request) { - if r.Method == "OPTIONS" { - ResponseStatusOK204NoContent(w) - return - } - errorMessage := ErrorMessage{"1", "method not allowed"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusMethodNotAllowed, errorResponse) -} - -func CustomResponseMethodNotAllowed405Handler() http.Handler { - return http.HandlerFunc(ResponseMethodNotAllowed405) -} - -func ResponseNotAcceptable406MissingParam(w http.ResponseWriter) { - errorMessage := ErrorMessage{"1", "missing parameter: rmUIDs"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotAcceptable, errorResponse) -} - -func ResponseNotAcceptable406ParamError(w http.ResponseWriter, errorParamsName []string) { - errorMessage := ErrorMessage{"2", "parameter name error: " + strings.Join(errorParamsName, ",")} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotAcceptable, errorResponse) -} - -func ResponseNotAcceptable406QuerySQLError(w http.ResponseWriter) { - errorMessage := ErrorMessage{"3", "wrong or non-query SQL statement"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusNotAcceptable, errorResponse) -} - -func ResponseRequestEntityTooLarge413SubscriptionExceed(w http.ResponseWriter, num int) { - errorMessage := ErrorMessage{"1", "the number of subscriptions greater than " + strconv.Itoa(num)} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusRequestEntityTooLarge, errorResponse) -} - -func ResponseRequestEntityTooLarge413BodyToLarge(w http.ResponseWriter) { - errorMessage := ErrorMessage{"2", "the request entity too large"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusRequestEntityTooLarge, errorResponse) -} - -func ResponseRequestURITooLong414NRMNumExceed(w http.ResponseWriter, num int) { - errorMessage := ErrorMessage{"1", "the number of NRM rmUIDs greater than " + strconv.Itoa(num)} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse) -} - -func ResponseRequestURITooLong414AlarmNumExceed(w http.ResponseWriter, num int) { - errorMessage := ErrorMessage{"2", "the number of alarmIds greater than " + strconv.Itoa(num)} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse) -} - -func ResponseRequestURITooLong414PMNumExceed(w http.ResponseWriter, num int) { - errorMessage := ErrorMessage{"3", "the number of PM rmUIDs greater than " + strconv.Itoa(num)} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse) -} - -func ResponseRequestURITooLong414UriTooLong(w http.ResponseWriter) { - errorMessage := ErrorMessage{"3", "request URI too long"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse) -} - -func ResponseUnsupportedMediaType415(w http.ResponseWriter) { - errorMessage := ErrorMessage{"1", "unsupported media type"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusUnsupportedMediaType, errorResponse) -} - -func ResponseInternalServerError500NFConnectRefused(w http.ResponseWriter) { - errorMessage := ErrorMessage{"1", "internal server error, NF connnect refused"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusInternalServerError, errorResponse) -} - -func ResponseInternalServerError500DatabaseOperationFailed(w http.ResponseWriter) { - errorMessage := ErrorMessage{"2", "internal server error, database opration failed"} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusInternalServerError, errorResponse) -} - -func ResponseInternalServerError500ProcessError(w http.ResponseWriter, err error) { - em := fmt.Sprintf("internal server error: %v", err) - errorMessage := ErrorMessage{"3", em} - errorResponse := ErrorResponse{errorMessage} - ResponseWithJson(w, http.StatusInternalServerError, errorResponse) -} - -func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) { - log.Trace("payload: ", payload) - - response, _ := json.Marshal(payload) - SetResponseHeader(w) - w.WriteHeader(code) - w.Write(response) - log.Trace("Response Code:", code) - log.Trace("Response Body:", string(response)) -} - -func ResponseWithZip(w http.ResponseWriter, payload interface{}) { - response, _ := json.Marshal(payload) - SetResponseHeader(w) - w.WriteHeader(http.StatusOK) - w.Write(response) - log.Trace("Response Body:", string(response)) -} - -func TransportResponse(w http.ResponseWriter, code int, payload []byte) { - var tempBody, transBody interface{} - switch code { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - json.Unmarshal(payload, &tempBody) - transBody = DataResponse{tempBody} - default: - json.Unmarshal(payload, &tempBody) - transBody = ErrorResponse{tempBody} - } - response, _ := json.Marshal(transBody) - log.Trace("transBody: ", transBody) - SetResponseHeader(w) - w.WriteHeader(code) - w.Write(response) - log.Trace("response: ", string(response)) -} - -func ResponseWithUnsortJson(w http.ResponseWriter, code int, payload map[string]interface{}) { - var om global.OrderedMap - om.Map = payload - response, _ := om.MarshalJson() - log.Trace("payload: ", payload) - SetResponseHeader(w) - w.WriteHeader(code) - w.Write(response) - log.Trace("response: ", string(response)) -} - -func ResponseErrorWithJson(w http.ResponseWriter, code int, nameValue interface{}) { - response := make(map[string]interface{}) - response["error"] = nameValue - ResponseWithJson(w, code, response) -} - -func SetCommonResponseHeader(w http.ResponseWriter) { - // 设置Vary头部 - w.Header().Set("Vary", "Origin") - w.Header().Set("Keep-Alive", "timeout=5") - // To solve cross domain issue - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "*") - w.Header().Set("Access-Control-Allow-Headers", "*") - w.Header().Set("Access-Control-Allow-Credentials", "true") - // 响应最大时间值 - w.Header().Set("Access-Control-Max-Age", "31536000") -} - -func SetResponseHeader(w http.ResponseWriter) { - w.Header().Set("Content-Type", "application/json;charset=UTF-8") - SetCommonResponseHeader(w) -} - -// Creates a new file upload http request with optional extra params -func ResponseUploadFile(w http.ResponseWriter, code int, params map[string]string, paramName, path string) { - file, err := os.Open(path) - if err != nil { - log.Errorf("Failed to open: %v", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - defer file.Close() - - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - part, err := writer.CreateFormFile(paramName, filepath.Base(path)) - if err != nil { - log.Error("Failed to CreateFormFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - _, err = io.Copy(part, file) - if err != nil { - log.Error("Failed to Copy:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - - for key, val := range params { - _ = writer.WriteField(key, val) - } - - err = writer.Close() - if err != nil { - log.Error("Failed to Close:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - - SetCommonResponseHeader(w) - w.Header().Set("Content-Type", writer.FormDataContentType()) - w.WriteHeader(code) - w.Write(body.Bytes()) -} - -func ResponseFile(w http.ResponseWriter, code int, filePath string) { - fileBytes, err := os.ReadFile(filePath) - if err != nil { - log.Error("Failed to ReadFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - SetCommonResponseHeader(w) - w.Header().Set("Content-Type", "application/octet-stream") - w.WriteHeader(code) - w.Write(fileBytes) -} - -func ResponseFileWithNameAndMD5(w http.ResponseWriter, code int, fileName, path, md5Sum string) { - filePath := path + "/" + fileName - fileBytes, err := os.ReadFile(filePath) - if err != nil { - log.Error("Failed to ReadFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - SetCommonResponseHeader(w) - encodedFileName := url.PathEscape(fileName) - w.Header().Set("Content-Disposition", `attachment; filename="`+encodedFileName+`"`) - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("User-File", fileName) - w.Header().Set("MD5-Sum", md5Sum) - w.WriteHeader(code) - w.Write(fileBytes) -} - -func ResponseHtmlContent(w http.ResponseWriter, code int, filePath string) { - htmlContent, err := os.ReadFile(filePath) - if err != nil { - log.Error("Failed to ReadFile:", err) - ResponseInternalServerError500ProcessError(w, err) - return - } - - SetCommonResponseHeader(w) - w.Header().Set("Content-Type", "text/html") - w.WriteHeader(code) - w.Write(htmlContent) -} - -// RouterItem 路由项 -type RouterItem struct { - Method string - Pattern string - Handler http.HandlerFunc - Middleware mux.MiddlewareFunc -} diff --git a/lib/session/session.go b/lib/session/session.go deleted file mode 100644 index 0e3156e0..00000000 --- a/lib/session/session.go +++ /dev/null @@ -1,168 +0,0 @@ -package session - -import ( - "crypto/rand" - "encoding/base64" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "sync" - "time" - - "be.ems/lib/config" - "be.ems/lib/log" - "be.ems/lib/oauth" -) - -// SessionMgr session manager -type SessManager struct { - name string - expires int64 - lock sync.RWMutex - sessions map[string]*Session -} - -// Session -type Session struct { - token string - time time.Time - permission []bool - values map[interface{}]interface{} -} - -// NewSessionMgr create session manager -func NewSessManager(name string) *SessManager { - smgr := &SessManager{name: name, expires: (int64)(config.GetExpiresFromConfig()), sessions: make(map[string]*Session)} - go smgr.SessionGC() - return smgr -} - -// NewSession create session -func (smgr *SessManager) NewSession(w http.ResponseWriter, r *http.Request, plist []bool) string { - smgr.lock.Lock() - defer smgr.lock.Unlock() - token := oauth.GenRandToken("omc") // Generate new token to session ID - session := &Session{token: token, time: time.Now(), permission: plist, values: make(map[interface{}]interface{})} - smgr.sessions[token] = session - - return token -} - -// EndSession -func (smgr *SessManager) EndSession(w http.ResponseWriter, r *http.Request) { - token := smgr.GetTokenFromHttpRequest(r) - - smgr.lock.Lock() - defer smgr.lock.Unlock() - delete(smgr.sessions, token) -} - -// Handshake session, restart session -func (smgr *SessManager) ShakeSession(token string) bool { - - smgr.lock.Lock() - defer smgr.lock.Unlock() - for _, s := range smgr.sessions { - if token == s.token { - log.Debug("session time:", s.time) - s.time = time.Now() - return true - } - } - return false -} - -// EndSessionByID end the session by session ID -func (smgr *SessManager) DeleteSession(token string) { - smgr.lock.Lock() - defer smgr.lock.Unlock() - delete(smgr.sessions, token) -} - -// SetSessionValue set value fo session -func (smgr *SessManager) SetSessionValue(token string, key interface{}, value interface{}) error { - smgr.lock.Lock() - defer smgr.lock.Unlock() - if session, ok := smgr.sessions[token]; ok { - session.values[key] = value - return nil - } - return fmt.Errorf("invalid session ID") -} - -// GetSessionValue get value fo session -func (smgr *SessManager) GetSessionValue(token string, key interface{}) (interface{}, error) { - smgr.lock.RLock() - defer smgr.lock.RUnlock() - if session, ok := smgr.sessions[token]; ok { - if val, ok := session.values[key]; ok { - return val, nil - } - } - return nil, fmt.Errorf("invalid session ID") -} - -func (smgr *SessManager) GetTokenFromHttpRequest(r *http.Request) string { - for k, v := range r.Header { - if strings.ToLower(k) == "accesstoken" && len(v) != 0 { - log.Debug("AccessToken:", v[0]) - return v[0] - } - } - return "" -} - -// IsValidToken check token is valid or not -func (smgr *SessManager) IsValidToken(token string) bool { - - smgr.lock.Lock() - defer smgr.lock.Unlock() - if _, ok := smgr.sessions[token]; ok { - return true - } - return false -} - -// IsCarriedToken check token is carried -func (smgr *SessManager) IsCarriedToken(r *http.Request) (string, bool) { - - token := smgr.GetTokenFromHttpRequest(r) - if token == "" { - return "", false - } - return token, true -} - -// GetPermissionFromSession get permission from session by token -func (smgr *SessManager) GetPermissionFromSession(token string) []bool { - - if s, ok := smgr.sessions[token]; ok { - return s.permission - } - return nil -} - -// SessionGC maintain session -func (smgr *SessManager) SessionGC() { - smgr.lock.Lock() - defer smgr.lock.Unlock() - for token, session := range smgr.sessions { - if session.time.Unix()+smgr.expires < time.Now().Unix() { - delete(smgr.sessions, token) - } - } - - time.AfterFunc(time.Duration(smgr.expires)*time.Second, func() { smgr.SessionGC() }) -} - -// NewSessionID generate unique ID -func (smgr *SessManager) NewSessionID() string { - b := make([]byte, 32) - if _, err := io.ReadFull(rand.Reader, b); err != nil { - nano := time.Now().UnixNano() - return strconv.FormatInt(nano, 10) - } - return base64.URLEncoding.EncodeToString(b) -} diff --git a/sshsvc/.ssh/id_rsa b/sshsvc/.ssh/id_rsa deleted file mode 100644 index b9e6a0e2..00000000 --- a/sshsvc/.ssh/id_rsa +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -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 ------END OPENSSH PRIVATE KEY----- diff --git a/sshsvc/.ssh/id_rsa.pub b/sshsvc/.ssh/id_rsa.pub deleted file mode 100644 index 93e845fa..00000000 --- a/sshsvc/.ssh/id_rsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCjzE0MHy0P2sQmG1OKvArwLEzR77BwxPp+4N9NKBz8lEyNch4zoHvoLDaUJKPBMwTrScZnxhvRJNde6hz5Z0QVxZolVKV95fMfgb9YICzDfPF3Bphae5q/PBYUJNfrC9SAjQeHV4CCO6xk6LV8O/Nfw8uaXwtuN3yfpUWd5mRWKMc3GHV4vxerfKoIQZN6etLhIEYibAhCJ21P0uoWzZl7ceLmkG+6qrRSbyC0bCnrN3+wjN4bwtflrEFJk3XQGuRbVsYLzux+mMm9p22+CLPRl/FUPF3x4/wKCsqr7JDSxx80HSPhk4g/1nCTpDR9hAfF6A9ww2va/k8jMeYPBO8Owe7erLEZzvg5WQAR3Wj05eJpJD99BeC91S5KW6AFQDfDHxWWprSibd/Jj9dtct2pK2ZxW0ph9OJ49ftRhzT1iVi4UnJwnG5/qLfwl6Tnx+qnQ1If/9lY/99erCTATzFTMSImKrRz7CnuPlcw8WkzCYpWKKe0kJLkL2cRD5Qi4yk= simon@simonzhangsz diff --git a/sshsvc/.ssh/private_key.pem b/sshsvc/.ssh/private_key.pem deleted file mode 100644 index b9e6a0e2..00000000 --- a/sshsvc/.ssh/private_key.pem +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -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 ------END OPENSSH PRIVATE KEY----- diff --git a/sshsvc/config/config.go b/sshsvc/config/config.go deleted file mode 100644 index fcf978a4..00000000 --- a/sshsvc/config/config.go +++ /dev/null @@ -1,185 +0,0 @@ -package config - -import ( - "flag" - "fmt" - "os" - "strings" - - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/sshsvc/logmml" - - "gopkg.in/yaml.v3" -) - -type DbConfig struct { - Type string `yaml:"type"` - User string `yaml:"user"` - Password string `yaml:"password"` - Host string `yaml:"host"` - Port string `yaml:"port"` - Name string `yaml:"name"` - ConnParam string `yaml:"connParam,omitempty"` - Backup string `yaml:"backup"` -} - -// Yaml struct of config -type YamlConfig struct { - Logger struct { - File string `yaml:"file"` - Level string `yaml:"level"` - Duration int `yaml:"duration"` - Count int `yaml:"count"` - } `yaml:"logger"` - - Logmml struct { - File string `yaml:"file"` - Duration int `yaml:"duration"` - Count int `yaml:"count"` - Level string `yaml:"level"` - } `yaml:"logmml"` - - Sshd struct { - ListenAddr string `yaml:"listenAddr"` - ListenPort uint16 `yaml:"listenPort"` - PrivateKey string `yaml:"privateKey"` - MaxConnNum int `yaml:"maxConnNum"` - Timeout uint16 `yaml:"timeout"` - Session string `yaml:"session"` - MmlHome string `yaml:"mmlHome"` - UserName string `yaml:"userName"` - Password string `yaml:"password"` - AuthType string `yaml:"authType"` - TagNE string `yaml:"tagNE"` - } `yaml:"sshd"` - - TelnetServer struct { - ListenAddr string `yaml:"listenAddr"` - ListenPort uint16 `yaml:"listenPort"` - MaxConnNum int `yaml:"maxConnNum"` - Timeout uint16 `yaml:"timeout"` - Session string `yaml:"session"` - MmlHome string `yaml:"mmlHome"` - UserName string `yaml:"userName"` - Password string `yaml:"password"` - AuthType string `yaml:"authType"` - TagNE string `yaml:"tagNE"` - } `yaml:"telnetServer"` - - SNMPServer struct { - ListenAddr string `yaml:"listenAddr"` - ListenPort uint16 `yaml:"listenPort"` - UserName string `yaml:"userName"` - AuthPass string `yaml:"authPass"` - AuthProto string `yaml:"authProto"` - PrivPass string `yaml:"privPass"` - PrivProto string `yaml:"privProto"` - EngineID string `yaml:"engineID"` - TrapPort uint16 `yaml:"trapPort"` - TrapListen bool `yaml:"trapListen"` - TrapBool bool `yaml:"trapBool"` - TrapTick uint16 `yaml:"trapTick"` - TimeOut uint16 `yaml:"timeOut"` - TrapTarget string `yaml:"trapTarget"` - } `yaml:"snmpServer"` - - Database DbConfig `yaml:"database"` - - OMC struct { - HttpUri string `yaml:"httpUri"` - UserCrypt string `yaml:"userCrypt"` - } `yaml:"omc"` -} - -var yamlConfig YamlConfig = NewYamlConfig() - -// set default value for yaml config -func NewYamlConfig() YamlConfig { - return YamlConfig{ - Database: DbConfig{ - Type: "mysql", - ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True", - }, - } -} - -func ReadConfig(configFile string) { - yamlFile, err := os.ReadFile(configFile) - if err != nil { - fmt.Println("Read yaml config file error:", err) - os.Exit(2) - } - - err = yaml.Unmarshal(yamlFile, &yamlConfig) - if err != nil { - fmt.Println("Unmarshal error:", err) - os.Exit(3) - } -} - -func GetYamlConfig() *YamlConfig { - return &yamlConfig -} - -func GetLogLevel() log.LogLevel { - var logLevel log.LogLevel - switch strings.ToLower(yamlConfig.Logger.Level) { - case "trace": - logLevel = log.LOG_TRACE - case "info": - logLevel = log.LOG_INFO - case "debug": - logLevel = log.LOG_DEBUG - case "warn": - logLevel = log.LOG_WARN - case "error": - logLevel = log.LOG_ERROR - case "fatal": - logLevel = log.LOG_FATAL - case "off": - logLevel = log.LOG_OFF - default: - logLevel = log.LOG_DEBUG - } - return logLevel -} - -func GetLogMmlLevel() logmml.LogLevel { - var logLevel logmml.LogLevel - switch strings.ToLower(yamlConfig.Logmml.Level) { - case "cmd", "command": - logLevel = logmml.LOG_CMD - case "ret", "result": - logLevel = logmml.LOG_RET - default: - logLevel = logmml.LOG_CMD - } - return logLevel -} - -func GetDefaultUserAgent() string { - return "OMC-sshsvc/" + global.Version -} - -const DefaultConfigFile = "./etc/sshsvc.yaml" - -func init() { - cfile := flag.String("c", DefaultConfigFile, "config file") - pv := flag.Bool("v", false, "print version") - pversion := flag.Bool("version", false, "print version") - ph := flag.Bool("h", false, "print help") - phelp := flag.Bool("help", false, "print help") - - flag.Parse() - if *pv || *pversion { - fmt.Printf("OMC sshsvc version: %s\n%s\n%s\n\n", global.Version, global.BuildTime, global.GoVer) - os.Exit(0) - } - if *ph || *phelp { - flag.Usage() - os.Exit(0) - } - - ReadConfig(*cfile) -} diff --git a/sshsvc/dborm/dborm.go b/sshsvc/dborm/dborm.go deleted file mode 100644 index 45449317..00000000 --- a/sshsvc/dborm/dborm.go +++ /dev/null @@ -1,161 +0,0 @@ -package dborm - -import ( - "database/sql" - "fmt" - "time" - - "be.ems/lib/log" - - _ "github.com/go-sql-driver/mysql" - "xorm.io/xorm" - "xorm.io/xorm/core" -) - -const ( - TableNameMeasureTask = "measure_task" - TableNameNeInfo = "ne_info" -) - -type Menu struct { - Id int `json:"id"` - Title string `json:"title"` - Icon string `json:"icon"` - Href string `json:"href"` - ParentId int `json:"parent_id"` - Remark int `json:"remark"` -} - -type DatabaseClient struct { - dbType string - dbUrl string - dbConnMaxLifetime time.Duration - dbMaxIdleConns int - dbMaxOpenConns int - IsShowSQL bool - - XEngine *xorm.Engine -} - -var DbClient DatabaseClient - -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", - dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) - DbClient.dbType = dbType - DbClient.dbConnMaxLifetime = 0 - DbClient.dbMaxIdleConns = 0 - DbClient.dbMaxOpenConns = 0 - if log.GetLevel() == log.LOG_TRACE { - DbClient.IsShowSQL = true - } - log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) - - var err error - DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) - if err != nil { - log.Error("Failed to connet database:", err) - return err - } - DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) - DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) - DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) - DbClient.XEngine.DatabaseTZ = time.Local // 必须 - DbClient.XEngine.TZLocation = time.Local // 必须 - if DbClient.IsShowSQL { - DbClient.XEngine.ShowSQL(true) - } - - xEngine = DbClient.XEngine - - return nil -} - -// func InitDbClient() error { -// db := config.GetYamlConfig().Database -// DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", db.User, db.Password, db.Host, db.Port, db.Name) -// DbClient.dbType = db.Type -// DbClient.dbConnMaxLifetime = 0 -// DbClient.dbMaxIdleConns = 0 -// DbClient.dbMaxOpenConns = 0 -// if log.GetLevel() == log.LOG_TRACE { -// DbClient.IsShowSQL = true -// } -// log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s", DbClient.dbType, db.User, db.Host, db.Port, db.Name) -// var err error -// DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) -// if err != nil { -// log.Error("Failed to connet database:", err) -// return err -// } -// DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) -// DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) -// DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) -// if DbClient.IsShowSQL { -// DbClient.XEngine.ShowSQL(true) -// } -// xEngine = DbClient.XEngine - -// return nil -// } - -var xEngine *xorm.Engine - -func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) { - sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) - log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) - var err error - xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine - if err != nil { - log.Error("Failed to connect database:", err) - return nil, err - } - if log.GetLevel() == log.LOG_TRACE { - xEngine.ShowSQL(true) - } - return xEngine, nil -} - -func XCoreDB() *core.DB { - return xEngine.DB() -} - -func XEngDB() *xorm.Engine { - return xEngine -} - -type Session struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - AccountId string `json:"accountId" xorm:"account_id"` - Name string `json:"name" xorm:"name"` - Host string `json:"host" xorm:"host"` - AccessToken string `json:"accessToken" xorm:"access_token"` - Expires uint32 `json:"expires" xorm:"expires"` - Status string `json:"status" xorm:"status"` - LoginTime string `json:"loginTime" xorm:"-"` - ShakeTime sql.NullTime `son:"shakeTime" xorm:"shake_time"` - LogoutTime sql.NullTime `json:"logoutTime" xorm:"logout_time"` -} - -// XormUpdateSession update session -func XormLogoutUpdateSession(token string) (Session, error) { - log.Info("XormLogoutUpdateSession processing... ") - - session := Session{Status: "offline", AccessToken: token} - session.LogoutTime.Valid = true - session.LogoutTime.Time = time.Now() - - xSession := xEngine.NewSession() - defer xSession.Close() - _, err := xSession.Table("session").Where("access_token = ?", token).Update(session) - xSession.Commit() - // 查询记录返回 - if err == nil { - session := Session{} - _, err = xSession.Table("session").Where("access_token = ?", token).Get(&session) - return session, err - } - return session, err -} diff --git a/sshsvc/etc/sshsvc.yaml b/sshsvc/etc/sshsvc.yaml deleted file mode 100644 index e9019c4f..00000000 --- a/sshsvc/etc/sshsvc.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# file: log file name -# level: /trace/debug/info/warn/error/fatal, default: debug -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation -logger: - file: d:/omc.git/be.ems/sshsvc/log/sshsvc.log - level: trace - duration: 24 - count: 30 - -# file: MML log file name -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation -# level: cmd/ret log cmd/log cmd & result -logmml: - file: d:/omc.git/be.ems/sshsvc/mmllog/omcmml.log - duration: 24 - count: 30 - level: ret - -# ssh service listen ipv4/v6 and port, support multiple routines -# ip: 0.0.0.0 or ::0, support IPv4/v6 -# session: single/multiple session for one user -# authType: local/radius -sshd: - listenAddr: 0.0.0.0 - listenPort: 32222 - privateKey: ./.ssh/id_rsa - maxConnNum: 2 - timeout: 1800 - session: multiple - mmlHome: ./mmlhome - userName: manager - password: pass123 - authType: local - tagNE: hlr - -# authType: local/omc -telnetServer: - listenAddr: 0.0.0.0 - listenPort: 32323 - maxConnNum: 2 - timeout: 1800 - session: multiple - mmlHome: ./mmlhome - userName: manager - password: pass123 - authType: local - tagNE: hlr - -# authproto: NoAuth/MD5/SHA -# privProto: NoPriv/DES/AES/AES192/AES256 -snmpServer: - listenAddr: '[::]' - listenPort: 34957 - userName: manager - authPass: pass123 - authproto: MD5 - privPass: "3F2A1B4C5D6E7F8A9B0C1D2E3F4A5B6C7D8E9F0A1B2C3D4E" - privProto: DES - #engineID: "800007db03360102101101" - engineID: "8000000004323030313a6462383a3a39313636" - trapPort: 34958 - trapListen: false - trapBool: false - trapTick: 60 - timeOut: 5 - trapTarget: "2001:db8::9219" - -database: - type: mysql - user: administrator - password: "*86#ROtartsinim" - host: 192.168.13.117 - port: 3306 - name: OMC_PUB - connParam: charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True - -omc: - httpUri: http://127.0.0.1:3040 - userCrypt: bcrypt - -ne: - port: 4100 - sleep: 200 - user: admin - password: admin - - diff --git a/sshsvc/logmml/logmml.go b/sshsvc/logmml/logmml.go deleted file mode 100644 index 70fa5172..00000000 --- a/sshsvc/logmml/logmml.go +++ /dev/null @@ -1,187 +0,0 @@ -// logger for omc/ems - -package logmml - -import ( - "fmt" - "io" - "log" -) - -// LogLevel defines a log level -type LogLevel int - -// enum all LogLevels -const ( - // following level also match syslog.Priority value - LOG_RET LogLevel = iota - LOG_CMD - LOG_OFF - LOG_NODEF -) - -// default log options -const ( - DEFAULT_LOG_PREFIX = "omc:mml" - DEFAULT_LOG_FLAG = log.Ldate | log.Ltime | log.Lmsgprefix - DEFAULT_LOG_LEVEL = LOG_CMD - DEFAULT_CALL_DEPTH = 0 -) - -// Logger is a logger interface -type Logger interface { - Ret(v ...interface{}) - Retf(format string, v ...interface{}) - Cmd(v ...interface{}) - Cmdf(format string, v ...interface{}) - - Level() LogLevel - LevelString() string - SetLevel(l LogLevel) -} - -var _ Logger = DiscardLogger{} - -// DiscardLogger don't log implementation for ILogger -type DiscardLogger struct{} - -// Trace empty implementation -func (DiscardLogger) Ret(v ...interface{}) {} - -// Tracef empty implementation -func (DiscardLogger) Retf(format string, v ...interface{}) {} - -// Debug empty implementation -func (DiscardLogger) Cmd(v ...interface{}) {} - -// Debugf empty implementation -func (DiscardLogger) Cmdf(format string, v ...interface{}) {} - -// Level empty implementation -func (DiscardLogger) Level() LogLevel { - return LOG_NODEF -} - -// Level empty implementation -func (DiscardLogger) LevelString() string { - return "" -} - -// SetLevel empty implementation -func (DiscardLogger) SetLevel(l LogLevel) {} - -// EmsLogger is the default implment of ILogger -type MMLLogger struct { - RET *log.Logger - CMD *log.Logger - level LogLevel - levelString []string - //depth int -} - -var _ Logger = &MMLLogger{} - -// NewEmsLogger2 let you customrize your logger prefix and flag -func NewMmlLogger2(out io.Writer, prefix string, flag int) *MMLLogger { - return NewMmlLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL) -} - -// NewEmsLogger3 let you customrize your logger prefix and flag and logLevel -func NewMmlLogger3(out io.Writer, prefix string, flag int, l LogLevel) *MMLLogger { - return &MMLLogger{ - RET: log.New(out, fmt.Sprintf("[%s] [ret]: ", prefix), flag), - CMD: log.New(out, fmt.Sprintf("[%s] [cmd]: ", prefix), flag), - level: l, - levelString: []string{"ret", "cmd"}, - //depth: DEFAULT_CALL_DEPTH, - } -} - -// Trace implement ILogger -func (s *MMLLogger) Ret(v ...interface{}) { - if s.level <= LOG_RET { - //_ = s.RET.Output(s.depth, fmt.Sprintln(v...)) - _ = s.RET.Output(0, fmt.Sprintln(v...)) - } -} - -// Tracef implement ILogger -func (s *MMLLogger) Retf(format string, v ...interface{}) { - if s.level <= LOG_RET { - _ = s.RET.Output(0, fmt.Sprintf(format, v...)) - } -} - -// Debug implement ILogger -func (s *MMLLogger) Cmd(v ...interface{}) { - if s.level <= LOG_CMD { - _ = s.CMD.Output(0, fmt.Sprintln(v...)) - } -} - -// Debugf implement ILogger -func (s *MMLLogger) Cmdf(format string, v ...interface{}) { - if s.level <= LOG_CMD { - _ = s.CMD.Output(0, fmt.Sprintf(format, v...)) - } -} - -// Info implement ILogger - -// Level implement ILogger -func (s *MMLLogger) Level() LogLevel { - return s.level -} - -// Level implement ILogger -func (s *MMLLogger) LevelString() string { - return s.levelString[s.level] -} - -// SetLevel implement ILogger -func (s *MMLLogger) SetLevel(l LogLevel) { - s.level = l -} - -var Elogger Logger - -func InitMmlLogger(logFile string, period int, count int, prefix string, logLevel LogLevel) { - logWriter := getLogWriter(logFile, period, count) - Elogger = NewMmlLogger3(logWriter, prefix, DEFAULT_LOG_FLAG, logLevel) - fmt.Printf("logFile=%s, period=%d, count=%d, prefix=%s, logLevel=%s\n", logFile, period, count, prefix, GetLevelString()) -} - -// Trace implement ILogger -func Ret(v ...interface{}) { - Elogger.Ret(v...) -} - -// Tracef implement ILogger -func Retf(format string, v ...interface{}) { - Elogger.Retf(format, v...) -} - -// Debug implement ILogger -func Cmd(v ...interface{}) { - Elogger.Cmd(v...) -} - -// Debugf implement ILogger -func Cmdf(format string, v ...interface{}) { - Elogger.Cmdf(format, v...) -} - -// Level implement ILogger -func GetLevel() LogLevel { - return Elogger.Level() -} - -// Level implement ILogger -func GetLevelString() string { - return Elogger.LevelString() -} - -// SetLevel implement ILogger -func SetLevel(l LogLevel) { - Elogger.SetLevel(l) -} diff --git a/sshsvc/logmml/partition.go b/sshsvc/logmml/partition.go deleted file mode 100644 index 23380dcb..00000000 --- a/sshsvc/logmml/partition.go +++ /dev/null @@ -1,71 +0,0 @@ -package logmml - -import ( - "io" - "time" - - rotatelogs "github.com/lestrrat/go-file-rotatelogs" -) - -type WriteSyncer interface { - io.Writer - Sync() error -} - -// 得到LogWriter -func getLogWriter(filePath string, period, count int) WriteSyncer { - warnIoWriter := getWriter(filePath, period, count) - return addSync(warnIoWriter) -} - -// 日志文件切割 -func getWriter(filename string, period, count int) io.Writer { - // 保存日志count天,每period小时分割一次日志 - duration := time.Hour * time.Duration(period) - var logfile string - if period >= 24 { - logfile = filename + "-%Y%m%d" - } else { - logfile = filename + "-%Y%m%d%H" - } - hook, err := rotatelogs.New( - - logfile, - rotatelogs.WithLinkName(filename), - // rotatelogs.WithMaxAge(duration), - rotatelogs.WithRotationCount(count), - rotatelogs.WithRotationTime(duration), - rotatelogs.WithLocation(time.Local), - ) - - //保存日志30天,每1分钟分割一次日志 - /* - hook, err := rotatelogs.New( - filename+"_%Y%m%d%H%M.log", - rotatelogs.WithLinkName(filename), - rotatelogs.WithMaxAge(time.Hour*24*30), - rotatelogs.WithRotationTime(time.Minute*1), - ) - */ - if err != nil { - panic(err) - } - return hook -} - -func addSync(w io.Writer) WriteSyncer { - switch w := w.(type) { - case WriteSyncer: - return w - default: - return writerWrapper{w} - } -} - -type writerWrapper struct { - io.Writer -} - -func (w writerWrapper) Sync() error { - return nil -} diff --git a/sshsvc/makefile b/sshsvc/makefile deleted file mode 100644 index 43f4fe68..00000000 --- a/sshsvc/makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile for OMC-OMC-crontask project - -PROJECT = OMC -VERSION = 2.2503.2 -LIBDIR = be.ems/lib -BINNAME = sshsvc - -.PHONY: build $(BINNAME) -build $(BINNAME): - go build -o $(BINNAME) -v -ldflags "-s -w -X '$(LIBDIR)/global.Version=$(VERSION)' \ - -X '$(LIBDIR)/global.BuildTime=`date`' \ - -X '$(LIBDIR)/global.GoVer=`go version`'" - -run: $(BINNAME) - ./$(BINNAME) - -clean: - rm ./$(BINNAME) diff --git a/sshsvc/mibs/CINTEL-HLR-MIB.my b/sshsvc/mibs/CINTEL-HLR-MIB.my deleted file mode 100644 index 7fcb47e9..00000000 --- a/sshsvc/mibs/CINTEL-HLR-MIB.my +++ /dev/null @@ -1,7567 +0,0 @@ --- --- CINTEL-SS-HLR-MIB.my --- MIB generated by MG-SOFT Visual MIB Builder Version 7.0 Build 209 --- Monday, September 13, 2010 at 17:22:53 --- - - CINTEL-HLR-MIB DEFINITIONS ::= BEGIN - - IMPORTS - cintelSS, RowStatus - FROM CINTEL-MIB - Opaque, OBJECT-TYPE, MODULE-IDENTITY - FROM SNMPv2-SMI; - - - -- 1.3.6.1.4.1.1379.2.3.3.3 - hlr MODULE-IDENTITY - LAST-UPDATED "201706291606Z" -- June 29, 2007 at 16:06 GMT - ORGANIZATION - "CINTEL" - CONTACT-INFO - "cintel - support@cintel.com.cn" - DESCRIPTION - "Description." - REVISION "201706051219Z" -- June 05, 2007 at 12:19 GMT - DESCRIPTION - "This is the first release version of the HLR MIB" - ::= { application 3 } - - - --- --- Type definitions --- - - AvailStateChoices ::= INTEGER - { - inTest(0), - failed(1), - powerOff(2), - offLine(3), - onLine(4), - dependency(5), - degraded(6), - notInstalled(7) - } - - --- --- Node definitions --- - --- Node definitions --- --- The MIB module for ctcn. --- 1.3.6.1.4.1.1379.1.3 - -- 1.3.6.1.4.1.1379.2.3 - ctcn OBJECT IDENTIFIER ::= { cintelSS 3 } - - --- 1.3.6.1.4.1.1379.1.3.3 - -- 1.3.6.1.4.1.1379.2.3.3 - application OBJECT IDENTIFIER ::= { ctcn 3 } - - --- 1.3.6.1.4.1.1379.1.3.3.2.2 - -- 1.3.6.1.4.1.1379.2.3.3.3.1 - management OBJECT IDENTIFIER ::= { hlr 1 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.1.1 - instance OBJECT IDENTIFIER ::= { management 1 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.1 - instName OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..4)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:instName - Remark:Instance Name" - ::= { instance 1 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.2 - instStatus OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..16)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:instStatus - Remark:System status: Normal, Abnormal" - ::= { instance 2 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.3 - instDesc OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..64)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:instDesc - Remark:Instance Description" - ::= { instance 3 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.4 - instLocation OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..12)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:instLocation - Remark: Instance location" - ::= { instance 4 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.5 - instContact OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:instContact - Remark:Instance contact." - ::= { instance 5 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.7 - instOpTime OBJECT-TYPE - SYNTAX TimeStamp - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:instOpTime - The value of instOpTime at the time of the most recent - change in state." - ::= { instance 7 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.1.9 - instService OBJECT-TYPE - SYNTAX INTEGER - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:instService - The instance service event state, 0: Normal, 1: Link Down, 2: Link Up, 3: Authentication Failure." - ::= { instance 9 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2 - parameter OBJECT IDENTIFIER ::= { hlr 2 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2 - system OBJECT IDENTIFIER ::= { parameter 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1 - cC OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..4)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:CC - Remark:Country Code" - ::= { system 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.2 - nDC OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..6)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:NDC - Remark:National Destination Code" - ::= { system 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.3 - startSN OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..12)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:SN Start - Remark:The beginning of the VLR SN range." - ::= { system 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.4 - endSN OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..12)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:SN End - Remark:The end of the VLR SN range." - ::= { system 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.5 - maxLicenses OBJECT-TYPE - SYNTAX INTEGER - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Max License - Remark:(Read Only) The maximum subscriber capacity of HLR determined by License Control." - ::= { system 5 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.6 - usedLicenses OBJECT-TYPE - SYNTAX INTEGER - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Used License - Remark:(Read Only) The number of registered HLR subscribers." - ::= { system 6 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.7 - provisionedSubs OBJECT-TYPE - SYNTAX INTEGER - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Provisioned Users - Remark:(Read Only) The number of service enabled HLR subscribers." - ::= { system 7 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.8 - registeredSubs OBJECT-TYPE - SYNTAX INTEGER - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Registered Users - Remark:(Read Only) The number of registered (both service enabled and disabled) HLR subscribers." - ::= { system 8 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.9 - roamingSubs OBJECT-TYPE - SYNTAX INTEGER - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Roaming Users - Remark:(Read Only) The number of provisioned HLR subscribers currently roaming to VPLMNs." - ::= { system 9 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.10 - softwareVersion OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Software Version - Remark:(Read Only) Version of HLR software." - ::= { system 10 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.11 - dataVersion OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Name:Data Version - Remark:(Read Only) Version of HLR subscriber data structure." - ::= { system 11 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.12 - cDRFlag OBJECT-TYPE - SYNTAX INTEGER - { - off(0), - on(1) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:CDR Flag - Remark:Enable or disable CDR generation of HLR." - ::= { system 12 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.13 - reloadState OBJECT-TYPE - SYNTAX INTEGER - { - idle(0), - reload(1) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:Reload State - Remark:Select reload to load backup HLR subscriber data from HLR server hard disk." - ::= { system 13 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.14 - saveParamCommand OBJECT-TYPE - SYNTAX INTEGER { saveParameter(1) } - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Remark:Save the HLR parameters residing in memory to harddisk." - ::= { system 14 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.15 - saveDataCommand OBJECT-TYPE - SYNTAX INTEGER { saveData(1) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Remark:Save the HLR subscriber data to both HLR
harddisk and EMS database." - ::= { system 15 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.16 - saveUSSDParamCommand OBJECT-TYPE - SYNTAX INTEGER { saveUSSDParam(1) } - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Remark:Save the USSD parameters residing
in memory to harddisk." - ::= { system 16 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.17 - resetUSSDParamCommand OBJECT-TYPE - SYNTAX INTEGER { resetUSSDParam(1) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Remark:Reload and activate all USSD
parameters to default values." - ::= { system 17 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.18 - importSubs OBJECT-TYPE - SYNTAX Opaque (SIZE (7)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Hidden Flag:Yes - OPAQUE DECODE RULE: - [unit]Command[u]00.0-00.7[u]select - [v]0[opt]Idle - [v]1[opt]Sending Command - [v]2[opt]In Processing - [v]3[opt]Succeeded - [v]4[opt]Failed - [unit]Total Numbers[u]01.0-03.7[u]input - [v]toDec-high-0 - [unit]Success Numbers[u]04.0-06.7[u]input - [v]toDec-high-0" - ::= { system 18 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2 - vPLMN OBJECT IDENTIFIER ::= { parameter 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1 - vPLMNTable OBJECT-TYPE - SYNTAX SEQUENCE OF VPLMNEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - ::= { vPLMN 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1 - vPLMNEntry OBJECT-TYPE - SYNTAX VPLMNEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - INDEX { vplmnIndex } - ::= { vPLMNTable 1 } - - - VPLMNEntry ::= - SEQUENCE { - vplmnIndex - INTEGER, - vplmnCC - OCTET STRING, - vplmnNDC - OCTET STRING, - vplmnStartSN - OCTET STRING, - vplmnEndSN - OCTET STRING, - vplmnRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1.1 - vplmnIndex OBJECT-TYPE - SYNTAX INTEGER (0..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index - Remark:VPLMN index number ranges from 0 to 255." - ::= { vPLMNEntry 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1.2 - vplmnCC OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..4)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:CC - Remark:The Country Code of the VPLMN." - ::= { vPLMNEntry 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1.3 - vplmnNDC OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..6)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:NDC - Remark:The National Destination Code of the VPLMN." - ::= { vPLMNEntry 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1.4 - vplmnStartSN OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..12)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:SN Start - Remark:The beginning of the VLR range in the VPLMN." - ::= { vPLMNEntry 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1.5 - vplmnEndSN OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..12)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:SN End - Remark:The end of the VLR range in the VPLMN." - ::= { vPLMNEntry 5 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.2.1.1.6 - vplmnRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { vPLMNEntry 6 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3 - cSRRList OBJECT IDENTIFIER ::= { parameter 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.1 - cSRR0 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 0(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.2 - cSRR1 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 1(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.3 - cSRR2 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 2(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.4 - cSRR3 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 3(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.5 - cSRR4 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 4(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 5 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.6 - cSRR5 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 5(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 6 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.7 - cSRR6 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 6(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 7 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.3.8 - cSRR7 OBJECT-TYPE - SYNTAX Opaque (SIZE (32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "OPAQUE DECODE RULE: - [unit]VPLMN0[u]00.0-00.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN1[u]00.1-00.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN2[u]00.2-00.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN3[u]00.3-00.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN4[u]00.4-00.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN5[u]00.5-00.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN6[u]00.6-00.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN7[u]00.7-00.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN8[u]01.0-01.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN9[u]01.1-01.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN10[u]01.2-01.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN11[u]01.3-01.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN12[u]01.4-01.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN13[u]01.5-01.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN14[u]01.6-01.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN15[u]01.7-01.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN16[u]02.0-02.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN17[u]02.1-02.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN18[u]02.2-02.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN19[u]02.3-02.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN20[u]02.4-02.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN21[u]02.5-02.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN22[u]02.6-02.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN23[u]02.7-02.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN24[u]03.0-03.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN25[u]03.1-03.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN26[u]03.2-03.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN27[u]03.3-03.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN28[u]03.4-03.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN29[u]03.5-03.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN30[u]03.6-03.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN31[u]03.7-03.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN32[u]04.0-04.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN33[u]04.1-04.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN34[u]04.2-04.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN35[u]04.3-04.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN36[u]04.4-04.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN37[u]04.5-04.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN38[u]04.6-04.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN39[u]04.7-04.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN40[u]05.0-05.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN41[u]05.1-05.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN42[u]05.2-05.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN43[u]05.3-05.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN44[u]05.4-05.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN45[u]05.5-05.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN46[u]05.6-05.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN47[u]05.7-05.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN48[u]06.0-06.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN49[u]06.1-06.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN50[u]06.2-06.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN51[u]06.3-06.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN52[u]06.4-06.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN53[u]06.5-06.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN54[u]06.6-06.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN55[u]06.7-06.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN56[u]07.0-07.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN57[u]07.1-07.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN58[u]07.2-07.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN59[u]07.3-07.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN60[u]07.4-07.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN61[u]07.5-07.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN62[u]07.6-07.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN63[u]07.7-07.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN64[u]08.0-08.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN65[u]08.1-08.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN66[u]08.2-08.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN67[u]08.3-08.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN68[u]08.4-08.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN69[u]08.5-08.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN70[u]08.6-08.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN71[u]08.7-08.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN72[u]09.0-09.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN73[u]09.1-09.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN74[u]09.2-09.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN75[u]09.3-09.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN76[u]09.4-09.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN77[u]09.5-09.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN78[u]09.6-09.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN79[u]09.7-09.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN80[u]10.0-10.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN81[u]10.1-10.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN82[u]10.2-10.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN83[u]10.3-10.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN84[u]10.4-10.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN85[u]10.5-10.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN86[u]10.6-10.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN87[u]10.7-10.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN88[u]11.0-11.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN89[u]11.1-11.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN90[u]11.2-11.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN91[u]11.3-11.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN92[u]11.4-11.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN93[u]11.5-11.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN94[u]11.6-11.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN95[u]11.7-11.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN96[u]12.0-12.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN97[u]12.1-12.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN98[u]12.2-12.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN99[u]12.3-12.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN100[u]12.4-12.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN101[u]12.5-12.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN102[u]12.6-12.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN103[u]12.7-12.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN104[u]13.0-13.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN105[u]13.1-13.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN106[u]13.2-13.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN107[u]13.3-13.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN108[u]13.4-13.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN109[u]13.5-13.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN110[u]13.6-13.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN111[u]13.7-13.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN112[u]14.0-14.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN113[u]14.1-14.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN114[u]14.2-14.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN115[u]14.3-14.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN116[u]14.4-14.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN117[u]14.5-14.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN118[u]14.6-14.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN119[u]14.7-14.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN120[u]15.0-15.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN121[u]15.1-15.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN122[u]15.2-15.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN123[u]15.3-15.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN124[u]15.4-15.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN125[u]15.5-15.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN126[u]15.6-15.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN127[u]15.7-15.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN128[u]16.0-16.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN129[u]16.1-16.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN130[u]16.2-16.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN131[u]16.3-16.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN132[u]16.4-16.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN133[u]16.5-16.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN134[u]16.6-16.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN135[u]16.7-16.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN136[u]17.0-17.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN137[u]17.1-17.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN138[u]17.2-17.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN139[u]17.3-17.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN140[u]17.4-17.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN141[u]17.5-17.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN142[u]17.6-17.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN143[u]17.7-17.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN144[u]18.0-18.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN145[u]18.1-18.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN146[u]18.2-18.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN147[u]18.3-18.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN148[u]18.4-18.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN149[u]18.5-18.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN150[u]18.6-18.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN151[u]18.7-18.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN152[u]19.0-19.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN153[u]19.1-19.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN154[u]19.2-19.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN155[u]19.3-19.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN156[u]19.4-19.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN157[u]19.5-19.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN158[u]19.6-19.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN159[u]19.7-19.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN160[u]20.0-20.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN161[u]20.1-20.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN162[u]20.2-20.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN163[u]20.3-20.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN164[u]20.4-20.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN165[u]20.5-20.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN166[u]20.6-20.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN167[u]20.7-20.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN168[u]21.0-21.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN169[u]21.1-21.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN170[u]21.2-21.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN171[u]21.3-21.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN172[u]21.4-21.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN173[u]21.5-21.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN174[u]21.6-21.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN175[u]21.7-21.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN176[u]22.0-22.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN177[u]22.1-22.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN178[u]22.2-22.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN179[u]22.3-22.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN180[u]22.4-22.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN181[u]22.5-22.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN182[u]22.6-22.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN183[u]22.7-22.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN184[u]23.0-23.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN185[u]23.1-23.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN186[u]23.2-23.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN187[u]23.3-23.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN188[u]23.4-23.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN189[u]23.5-23.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN190[u]23.6-23.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN191[u]23.7-23.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN192[u]24.0-24.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN193[u]24.1-24.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN194[u]24.2-24.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN195[u]24.3-24.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN196[u]24.4-24.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN197[u]24.5-24.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN198[u]24.6-24.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN199[u]24.7-24.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN200[u]25.0-25.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN201[u]25.1-25.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN202[u]25.2-25.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN203[u]25.3-25.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN204[u]25.4-25.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN205[u]25.5-25.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN206[u]25.6-25.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN207[u]25.7-25.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN208[u]26.0-26.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN209[u]26.1-26.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN210[u]26.2-26.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN211[u]26.3-26.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN212[u]26.4-26.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN213[u]26.5-26.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN214[u]26.6-26.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN215[u]26.7-26.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN216[u]27.0-27.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN217[u]27.1-27.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN218[u]27.2-27.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN219[u]27.3-27.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN220[u]27.4-27.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN221[u]27.5-27.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN222[u]27.6-27.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN223[u]27.7-27.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN224[u]28.0-28.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN225[u]28.1-28.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN226[u]28.2-28.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN227[u]28.3-28.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN228[u]28.4-28.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN229[u]28.5-28.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN230[u]28.6-28.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN231[u]28.7-28.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN232[u]29.0-29.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN233[u]29.1-29.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN234[u]29.2-29.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN235[u]29.3-29.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN236[u]29.4-29.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN237[u]29.5-29.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN238[u]29.6-29.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN239[u]29.7-29.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN240[u]30.0-30.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN241[u]30.1-30.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN242[u]30.2-30.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN243[u]30.3-30.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN244[u]30.4-30.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN245[u]30.5-30.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN246[u]30.6-30.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN247[u]30.7-30.7[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN248[u]31.0-31.0[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN249[u]31.1-31.1[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN250[u]31.2-31.2[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN251[u]31.3-31.3[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN252[u]31.4-31.4[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN253[u]31.5-31.5[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN254[u]31.6-31.6[u]select - [v]0[opt]N - [v]1[opt]Y - [unit]VPLMN255[u]31.7-31.7[u]select - [v]0[opt]N - [v]1[opt]Y - [remark]
Define CSRR 7(country specific roaming restriction) lists to confine the roaming range of a subscriber.
The CSRR list defines the roaming restriction for 256 VPLMN ranges.
" - ::= { cSRRList 8 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4 - rSZIList OBJECT IDENTIFIER ::= { parameter 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1 - rSZITable OBJECT-TYPE - SYNTAX SEQUENCE OF RSZIEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - ::= { rSZIList 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1.1 - rSZIEntry OBJECT-TYPE - SYNTAX RSZIEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - INDEX { rsziIndex } - ::= { rSZITable 1 } - - - RSZIEntry ::= - SEQUENCE { - rsziIndex - INTEGER, - rsziCC - OCTET STRING, - rsziNDC - OCTET STRING, - rsziZoneCode - INTEGER, - rsziRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1.1.1 - rsziIndex OBJECT-TYPE - SYNTAX INTEGER (0..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index - Remark:RSZI (Regional Subscription Zone Identity) index number ranges from 0 to 255." - ::= { rSZIEntry 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1.1.2 - rsziCC OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..4)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:CC - Remark:The Country Code of the regional subscription zone." - ::= { rSZIEntry 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1.1.3 - rsziNDC OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..6)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:NDC - Remark:The National Destination Code of the regional subscription zone." - ::= { rSZIEntry 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1.1.4 - rsziZoneCode OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Zone Code - Remark:The regional subscription zone code." - ::= { rSZIEntry 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.4.1.1.5 - rsziRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { rSZIEntry 5 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.5 - faxGSMBC OBJECT IDENTIFIER ::= { parameter 5 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.5.1 - faxGSMBCTable OBJECT-TYPE - SYNTAX SEQUENCE OF FaxGSMBCEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - ::= { faxGSMBC 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.5.1.1 - faxGSMBCEntry OBJECT-TYPE - SYNTAX FaxGSMBCEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - INDEX { fgIndex } - ::= { faxGSMBCTable 1 } - - - FaxGSMBCEntry ::= - SEQUENCE { - fgIndex - INTEGER, - fgBearerCapability - OCTET STRING, - fgRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.5.1.1.1 - fgIndex OBJECT-TYPE - SYNTAX INTEGER (0..15) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index - Remark:Index number of this Fax GSM Bearer Capability entry." - ::= { faxGSMBCEntry 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.5.1.1.2 - fgBearerCapability OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..14)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Bearer Capability - Remark:Define the GSM Bearer Capability for fax service.
- Default = A3B88120156380" - ::= { faxGSMBCEntry 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.5.1.1.3 - fgRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { faxGSMBCEntry 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.6 - dataGSMBC OBJECT IDENTIFIER ::= { parameter 6 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.6.1 - dataGSMBCTable OBJECT-TYPE - SYNTAX SEQUENCE OF DataGSMBCEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - ::= { dataGSMBC 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.6.1.1 - dataGSMBCEntry OBJECT-TYPE - SYNTAX DataGSMBCEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Description." - INDEX { dgIndex } - ::= { dataGSMBCTable 1 } - - - DataGSMBCEntry ::= - SEQUENCE { - dgIndex - INTEGER, - dgBearerCapability - OCTET STRING, - dgRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.6.1.1.1 - dgIndex OBJECT-TYPE - SYNTAX INTEGER (0..15) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index - Remark:Index number of this Data GSM Bearer Capability entry." - ::= { dataGSMBCEntry 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.6.1.1.2 - dgBearerCapability OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..14)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Bearer Capability - Remark:Define the GSM Bearer Capability for data service.
- Default = A28881211563A8" - ::= { dataGSMBCEntry 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.6.1.1.3 - dgRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { dataGSMBCEntry 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8 - uSSD OBJECT IDENTIFIER ::= { parameter 8 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.1 - uSSDFormatString OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..64)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:USSD Format - Remark:The access code of USSD service. Start with 2-3 digits of '*' or '#' . End with '#'. Separate sections by '*'.
Contents can be added:

- C/c = Service Code
- R/r = Router Indicator
- B = Blank
- S = Supplement Info

For example: **C3B*S#" - ::= { uSSD 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.2 - uGCsiServiceCode0 OBJECT-TYPE - SYNTAX INTEGER (0..9999) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI Service Code 0 - Remark:Service code for UG-CSI (USSD General - CAMEL Subscription Information). Prepaid subscriber dials service code to apply different prepaid services.
For example: Service Code = 111, prepaid user dials **1215111*# to enquire account info." - ::= { uSSD 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.3 - uGCsiGSMSCFAddr0 OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..18)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI SCF Address 0 - Remark:SCP address for UG-CSI (USSD General - CAMEL Subscription Information). The E.164 number of the SCP-MAP.
- Format = 91+CC+NDC+SN" - ::= { uSSD 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.4 - uGCsiServiceCode1 OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI Service Code 1 - Remark:Service code for UG-CSI (USSD General - CAMEL Subscription Information). Prepaid subscriber dials service code to apply different prepaid services." - ::= { uSSD 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.5 - uGCsiGSMSCFAddr1 OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..18)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI SCF Address 1 - Remark:SCP address for UG-CSI (USSD General - CAMEL Subscription Information). The E.164 number of the SCP-MAP.
- Format = 91+CC+NDC+SN" - ::= { uSSD 5 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.6 - uGCsiServiceCode2 OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI Service Code 2 - Remark:Service code for UG-CSI (USSD General - CAMEL Subscription Information). Prepaid subscriber dials service code to apply different prepaid services." - ::= { uSSD 6 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.7 - uGCsiGSMSCFAddr2 OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..18)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI SCF Address 2 - Remark:SCP address for UG-CSI (USSD General - CAMEL Subscription Information). The E.164 number of the SCP-MAP.
- Format = 91+CC+NDC+SN" - ::= { uSSD 7 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.8 - uGCsiServiceCode3 OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI Service Code 3 - Remark:Service code for UG-CSI (USSD General - CAMEL Subscription Information). Prepaid subscriber dials service code to apply different prepaid services." - ::= { uSSD 8 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.8.9 - uGCsiGSMSCFAddr3 OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..18)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Name:UG-CSI SCF Address 3 - Remark:SCP address for UG-CSI (USSD General - CAMEL Subscription Information). The E.164 number of the SCP-MAP.
- Format = 91+CC+NDC+SN" - ::= { uSSD 9 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20 - ussdEAE OBJECT IDENTIFIER ::= { parameter 10 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20.1 - ussdEAETable OBJECT-TYPE - SYNTAX SEQUENCE OF UssdEAEEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Name:USSD EAE" - ::= { ussdEAE 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20.1.1 - ussdEAEEntry OBJECT-TYPE - SYNTAX UssdEAEEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "level:1 Name:USSD EAE" - INDEX { ueIndex } - ::= { ussdEAETable 1 } - - - UssdEAEEntry ::= - SEQUENCE { - ueIndex - INTEGER, - ueServiceCode - INTEGER, - ueServiceNum - OCTET STRING, - ueRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20.1.1.1 - ueIndex OBJECT-TYPE - SYNTAX INTEGER (0..127) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index - Remark:USSD EAE (Extended Application Entity) index number ranges from 0 to 127." - ::= { ussdEAEEntry 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20.1.1.2 - ueServiceCode OBJECT-TYPE - SYNTAX INTEGER (0..9999) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Service Code - Remark:Subscriber dials service code to access different USSD services." - ::= { ussdEAEEntry 2 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20.1.1.3 - ueServiceNum OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..9)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Service Number - Remark:Enter the identical Service Number as that set in SMPP configuration to connect with the third party USSD server." - ::= { ussdEAEEntry 3 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.20.1.1.4 - ueRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { ussdEAEEntry 4 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21 - epsAPN OBJECT IDENTIFIER ::= { parameter 11 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1 - epsAPNTable OBJECT-TYPE - SYNTAX SEQUENCE OF EpsAPNEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Name:EPS APN" - ::= { epsAPN 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1 - epsAPNEntry OBJECT-TYPE - SYNTAX EpsAPNEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "level:1 Name:EPS APN" - INDEX { apnIndex } - ::= { epsAPNTable 1 } - - - EpsAPNEntry ::= - SEQUENCE { - apnIndex - INTEGER, - apnContextId - INTEGER, - apnPDNType - INTEGER, - apnQOSClassId - INTEGER, - apnVPLMNAllowed - INTEGER, - apnVisitedNetworkId - OCTET STRING, - apnPDNGWAllocationType - INTEGER, - apnPDNGWIdentity - OCTET STRING, - apnAMBRUL - INTEGER, - apnAMBRDL - INTEGER, - apnChargingCharacteristics - OCTET STRING, - apnServiceSelection - OCTET STRING, - apnOIReplacement - OCTET STRING, - apnRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.1 - apnIndex OBJECT-TYPE - SYNTAX INTEGER (0..15) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index" - ::= { epsAPNEntry 1 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.2 - apnContextId OBJECT-TYPE - SYNTAX INTEGER (0..127) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Context Id" - ::= { epsAPNEntry 2 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.3 - apnPDNType OBJECT-TYPE - SYNTAX INTEGER - { - IPv4(0), - IPv6(1), - IPv4v6(2), - IPv4orIPv6(3) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:PDN Type" - DEFVAL { IPv4 } - ::= { epsAPNEntry 3 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.4 - apnQOSClassId OBJECT-TYPE - SYNTAX INTEGER (0..16) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Qos Class Id" - ::= { epsAPNEntry 4 } - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.5 - apnVPLMNAllowed OBJECT-TYPE - SYNTAX INTEGER - { - NOTALLOWED(0), - ALLOWED(1) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter" - DEFVAL { ALLOWED } - ::= { epsAPNEntry 5 } - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.6 - apnVisitedNetworkId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..128)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter" - ::= { epsAPNEntry 6 } - - apnPDNGWAllocationType OBJECT-TYPE - SYNTAX INTEGER - { - STATIC(0), - DYNAMIC(1) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter" - DEFVAL { DYNAMIC } - ::= { epsAPNEntry 7 } - - apnPDNGWIdentity OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter" - ::= { epsAPNEntry 8 } - - apnAMBRUL OBJECT-TYPE - SYNTAX INTEGER (0..2147483647) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:AMBR UL" - ::= { epsAPNEntry 9 } - - apnAMBRDL OBJECT-TYPE - SYNTAX INTEGER (0..2147483647) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:AMBR DL" - ::= { epsAPNEntry 10 } - - apnChargingCharacteristics OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter" - ::= { epsAPNEntry 11 } - - apnServiceSelection OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Service Selection" - ::= { epsAPNEntry 12 } - - apnOIReplacement OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..128)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter" - ::= { epsAPNEntry 13 } - - apnRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { epsAPNEntry 14 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.22 - epsQOS OBJECT IDENTIFIER ::= { parameter 12 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.22.1 - epsQOSTable OBJECT-TYPE - SYNTAX SEQUENCE OF EpsQOSEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Name:EPS QOS" - ::= { epsQOS 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.22.1.1 - epsQOSEntry OBJECT-TYPE - SYNTAX EpsQOSEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "level:1 Name:EPS QOS" - INDEX { qosIndex } - ::= { epsQOSTable 1 } - - - EpsQOSEntry ::= - SEQUENCE { - qosIndex - INTEGER, - qosQosClassId - INTEGER, - qosPriorityLevel - INTEGER, - qosPreEmptionCapability - INTEGER, - qosPreEmptionVulnerability - INTEGER, - qosRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.22.1.1.1 - qosIndex OBJECT-TYPE - SYNTAX INTEGER (0..15) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index" - ::= { epsQOSEntry 1 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.21.1.1.2 - qosQosClassId OBJECT-TYPE - SYNTAX INTEGER (0..32) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Qos Class Id" - ::= { epsQOSEntry 2 } - - qosPriorityLevel OBJECT-TYPE - SYNTAX INTEGER (0..32) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Priority Level" - ::= { epsQOSEntry 3 } - - qosPreEmptionCapability OBJECT-TYPE - SYNTAX INTEGER - { - Disable(0), - Enable(1) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:PreEmptionCapability" - DEFVAL { Disable } - ::= { epsQOSEntry 4 } - - qosPreEmptionVulnerability OBJECT-TYPE - SYNTAX INTEGER - { - Disable(0), - Enable(1) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:PreEmptionVulnerability" - DEFVAL { Disable } - ::= { epsQOSEntry 5 } - - qosRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { epsQOSEntry 6 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.23 - epsTPL OBJECT IDENTIFIER ::= { parameter 13 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.23.1 - epsTPLTable OBJECT-TYPE - SYNTAX SEQUENCE OF EpsTPLEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Name:EPS TPL" - ::= { epsTPL 1 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.23.1.1 - epsTPLEntry OBJECT-TYPE - SYNTAX EpsTPLEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "level:1 Name:EPS TPL" - INDEX { tplIndex } - ::= { epsTPLTable 1 } - - - EpsTPLEntry ::= - SEQUENCE { - tplIndex - INTEGER, - tplName - OCTET STRING, - tplUeAmbrUL - INTEGER, - tplUeAmbrDL - INTEGER, - tplUeApnOiReplacement - OCTET STRING, - tplRfsp - INTEGER, - tplRauTauTimer - INTEGER, - tplChargingCharacteristic - OCTET STRING, - tplRowStatus - RowStatus - } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.23.1.1.1 - tplIndex OBJECT-TYPE - SYNTAX INTEGER (0..15) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Index" - ::= { epsTPLEntry 1 } - - -- 1.3.6.1.4.1.1379.2.3.3.3.2.23.1.1.2 - tplName OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..32)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:Template name" - ::= { epsTPLEntry 2 } - - tplUeAmbrUL OBJECT-TYPE - SYNTAX INTEGER (0..2147483647) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:UE AMBR UL" - ::= { epsTPLEntry 3 } - - tplUeAmbrDL OBJECT-TYPE - SYNTAX INTEGER (0..2147483647) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes Name:UE AMBR DL" - ::= { epsTPLEntry 4 } - - tplUeApnOiReplacement OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..128)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Description." - ::= { epsTPLEntry 5 } - - tplRfsp OBJECT-TYPE - SYNTAX INTEGER (0..127) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Description." - ::= { epsTPLEntry 6 } - - tplRauTauTimer OBJECT-TYPE - SYNTAX INTEGER (0..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Description." - ::= { epsTPLEntry 7 } - - tplChargingCharacteristic OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (0..128)) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Description." - ::= { epsTPLEntry 8 } - - tplRowStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Key Parameter:Yes" - ::= { epsTPLEntry 9 } - - - -- 1.3.6.1.4.1.1379.2.3.3.3.3 - hlrtraps OBJECT IDENTIFIER ::= { hlr 3 } - - -- Severity Object Definition - severity OBJECT-TYPE - SYNTAX INTEGER { - critical(1), - major(2), - minor(3), - warning(4), - event(5) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION "The severity level of the trap." - ::= { hlr 4 } - - linkDown NOTIFICATION-TYPE - OBJECTS { severity } - STATUS current - DESCRIPTION - "A trap indicating that a link is down." - ::= { hlrtraps 1 } - - linkUp NOTIFICATION-TYPE - OBJECTS { severity } - STATUS current - DESCRIPTION - "A trap indicating that a link is up." - ::= { hlrtraps 2 } - - authenticationFailure NOTIFICATION-TYPE - OBJECTS { severity } - STATUS current - DESCRIPTION - "A trap indicating an authentication failure." - ::= { hlrtraps 3 } - -END --- --- CINTEL-HLR-MIB.my --- diff --git a/sshsvc/mibs/CINTEL-HLR-MIB.smidb b/sshsvc/mibs/CINTEL-HLR-MIB.smidb deleted file mode 100644 index 411ce61acb5e793186ab93a5ffdd57f906d661b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214132 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 diff --git a/sshsvc/mibs/CINTEL-MIB.my b/sshsvc/mibs/CINTEL-MIB.my deleted file mode 100644 index 378eedd3..00000000 --- a/sshsvc/mibs/CINTEL-MIB.my +++ /dev/null @@ -1,656 +0,0 @@ --- --- CINTEL-MIB.my --- MIB generated by MG-SOFT Visual MIB Builder Version 7.0 Build 209 --- Friday, December 16, 2011 at 15:52:13 --- - - CINTEL-MIB DEFINITIONS ::= BEGIN - - IMPORTS - enterprises, TimeTicks, MODULE-IDENTITY - FROM SNMPv2-SMI - TEXTUAL-CONVENTION - FROM SNMPv2-TC; - - - -- 1.3.6.1.4.1.1379.2 - cintelSS MODULE-IDENTITY - LAST-UPDATED "201706041222Z" -- June 04, 2017 at 12:22 GMT - ORGANIZATION - "CINTEL" - CONTACT-INFO - "cintel - support@cintel.com.cn" - DESCRIPTION - "The MIB module for cintel's Softswitch products." - REVISION "201706041223Z" -- June 04, 2017 at 12:23 GMT - DESCRIPTION - "This is the first release version of the MIB" - ::= { cintelNS 2 } - - - --- --- Type definitions --- - - AdminStateChoices ::= INTEGER - { - locked(0), - unlocked(1), - shutDown(2) - } - - OperStateChoices ::= INTEGER - { - disable(0), - enable(1) - } - - AvailStateChoices ::= INTEGER - { - inTest(0), - failed(1), - powerOff(2), - offLine(3), - onLine(4), - dependency(5), - degraded(6), - notInstalled(7) - } - - --- --- Textual conventions --- - --- TEXTUAL-CONVENTION MACRO ::= --- BEGIN --- TYPE NOTATION ::= --- DisplayPart --- "STATUS" Status --- "DESCRIPTION" Text --- ReferPart --- "SYNTAX" Syntax --- --- VALUE NOTATION ::= --- value(VALUE Syntax) --- --- DisplayPart ::= --- "DISPLAY-HINT" Text --- | empty --- --- Status ::= --- "current" --- | "deprecated" --- | "obsolete" --- --- ReferPart ::= --- "REFERENCE" Text --- | empty --- --- -- -- uses the NVT ASCII character set --- Text ::= """" string """" --- --- Syntax ::= --- type(ObjectSyntax) --- | "BITS" "{" Kibbles "}" --- Kibbles ::= --- Kibble --- | Kibbles "," Kibble --- Kibble ::= --- identifier "(" nonNegativeNumber ")" --- END - DisplayString8 ::= TEXTUAL-CONVENTION - DISPLAY-HINT - "8a" - STATUS current - DESCRIPTION - "Represents textual information taken from the NVT ASCII - character set, as defined in pages 4, 10-11 of RFC 854. - - To summarize RFC 854, the NVT ASCII repertoire specifies: - - - the use of character codes 0-127 (decimal) - - - the graphics characters (32-126) are interpreted as - US ASCII - - - NUL, LF, CR, BEL, BS, HT, VT and FF have the special - meanings specified in RFC 854 - - - the other 25 codes have no standard interpretation - - - the sequence 'CR LF' means newline - - - the sequence 'CR NUL' means carriage-return - - - an 'LF' not preceded by a 'CR' means moving to the - same column on the next line. - - - the sequence 'CR x' for any x other than LF or NUL is - illegal. (Note that this also means that a string may - end with either 'CR LF' or 'CR NUL', but not with CR.) - - Any object defined using this syntax may not exceed 255 - characters in length." - SYNTAX OCTET STRING (SIZE (0..8)) - - DisplayString16 ::= TEXTUAL-CONVENTION - DISPLAY-HINT - "16a" - STATUS current - DESCRIPTION - "A version of DisplayString that contains only 16 characters most." - SYNTAX OCTET STRING (SIZE (0..16)) - - DisplayString32 ::= TEXTUAL-CONVENTION - DISPLAY-HINT - "32a" - STATUS current - DESCRIPTION - "A version of DisplayString that contains only 32 characters most." - SYNTAX OCTET STRING (SIZE (0..32)) - - DisplayString64 ::= TEXTUAL-CONVENTION - DISPLAY-HINT - "64a" - STATUS current - DESCRIPTION - "A version of DisplayString that contains only 64 characters most." - SYNTAX OCTET STRING (SIZE (0..64)) - - DisplayString ::= TEXTUAL-CONVENTION - DISPLAY-HINT - "255a" - STATUS current - DESCRIPTION - "A version of DisplayString that contains only 255 characters most." - SYNTAX OCTET STRING (SIZE (0..255)) - - RowStatus ::= TEXTUAL-CONVENTION - STATUS current - DESCRIPTION - "The RowStatus textual convention is used to manage the - creation and deletion of conceptual rows, and is used as the - value of the SYNTAX clause for the status column of a - conceptual row (as described in Section 7.7.1 of [2].) - - The status column has six defined values: - - - `active', which indicates that the conceptual row is - available for use by the managed device; - - - `notInService', which indicates that the conceptual - row exists in the agent, but is unavailable for use by - the managed device (see NOTE below); - - - `notReady', which indicates that the conceptual row - exists in the agent, but is missing information - necessary in order to be available for use by the - managed device; - - - `createAndGo', which is supplied by a management - station wishing to create a new instance of a - conceptual row and to have its status automatically set - to active, making it available for use by the managed - device; - - - `createAndWait', which is supplied by a management - station wishing to create a new instance of a - conceptual row (but not make it available for use by - the managed device); and, - - - `destroy', which is supplied by a management station - wishing to delete all of the instances associated with - an existing conceptual row. - - Whereas five of the six values (all except `notReady') may - be specified in a management protocol set operation, only - three values will be returned in response to a management - protocol retrieval operation: `notReady', `notInService' or - `active'. That is, when queried, an existing conceptual row - has only three states: it is either available for use by - the managed device (the status column has value `active'); - it is not available for use by the managed device, though - the agent has sufficient information to make it so (the - status column has value `notInService'); or, it is not - available for use by the managed device, and an attempt to - make it so would fail because the agent has insufficient - information (the state column has value `notReady'). - - NOTE WELL - - This textual convention may be used for a MIB table, - irrespective of whether the values of that table's - conceptual rows are able to be modified while it is - active, or whether its conceptual rows must be taken - out of service in order to be modified. That is, it is - the responsibility of the DESCRIPTION clause of the - status column to specify whether the status column must - not be `active' in order for the value of some other - column of the same conceptual row to be modified. If - such a specification is made, affected columns may be - changed by an SNMP set PDU if the RowStatus would not - be equal to `active' either immediately before or after - processing the PDU. In other words, if the PDU also - contained a varbind that would change the RowStatus - value, the column in question may be changed if the - RowStatus was not equal to `active' as the PDU was - received, or if the varbind sets the status to a value - other than 'active'. - - - Also note that whenever any elements of a row exist, the - RowStatus column must also exist. - - To summarize the effect of having a conceptual row with a - status column having a SYNTAX clause value of RowStatus, - consider the following state diagram: - - - STATE - +--------------+-----------+-------------+------------- - | A | B | C | D - | |status col.|status column| - |status column | is | is |status column - ACTION |does not exist| notReady | notInService| is active - --------------+--------------+-----------+-------------+------------- - set status |noError ->D|inconsist- |inconsistent-|inconsistent- - column to | or | entValue| Value| Value - createAndGo |inconsistent- | | | - | Value| | | - --------------+--------------+-----------+-------------+------------- - set status |noError see 1|inconsist- |inconsistent-|inconsistent- - column to | or | entValue| Value| Value - createAndWait |wrongValue | | | - --------------+--------------+-----------+-------------+------------- - set status |inconsistent- |inconsist- |noError |noError - column to | Value| entValue| | - active | | | | - | | or | | - | | | | - | |see 2 ->D| ->D| ->D - --------------+--------------+-----------+-------------+------------- - set status |inconsistent- |inconsist- |noError |noError ->C - column to | Value| entValue| | - notInService | | | | - | | or | | or - | | | | - | |see 3 ->C| ->C|wrongValue - --------------+--------------+-----------+-------------+------------- - set status |noError |noError |noError |noError - column to | | | | - destroy | ->A| ->A| ->A| ->A - --------------+--------------+-----------+-------------+------------- - set any other |see 4 |noError |noError |see 5 - column to some| | | | - value | | see 1| ->C| ->D - --------------+--------------+-----------+-------------+------------- - - (1) goto B or C, depending on information available to the - agent. - - (2) if other variable bindings included in the same PDU, - provide values for all columns which are missing but - required, then return noError and goto D. - - (3) if other variable bindings included in the same PDU, - provide values for all columns which are missing but - required, then return noError and goto C. - - (4) at the discretion of the agent, the return value may be - either: - - inconsistentName: because the agent does not choose to - create such an instance when the corresponding - RowStatus instance does not exist, or - - inconsistentValue: if the supplied value is - inconsistent with the state of some other MIB object's - value, or - - noError: because the agent chooses to create the - instance. - - If noError is returned, then the instance of the status - column must also be created, and the new state is B or C, - depending on the information available to the agent. If - inconsistentName or inconsistentValue is returned, the row - remains in state A. - - (5) depending on the MIB definition for the column/table, - either noError or inconsistentValue may be returned. - - NOTE: Other processing of the set request may result in a - response other than noError being returned, e.g., - wrongValue, noCreation, etc. - - - Conceptual Row Creation - - There are four potential interactions when creating a - conceptual row: selecting an instance-identifier which is - not in use; creating the conceptual row; initializing any - objects for which the agent does not supply a default; and, - making the conceptual row available for use by the managed - device. - - Interaction 1: Selecting an Instance-Identifier - - The algorithm used to select an instance-identifier varies - for each conceptual row. In some cases, the instance- - identifier is semantically significant, e.g., the - destination address of a route, and a management station - selects the instance-identifier according to the semantics. - - In other cases, the instance-identifier is used solely to - distinguish conceptual rows, and a management station - without specific knowledge of the conceptual row might - examine the instances present in order to determine an - unused instance-identifier. (This approach may be used, but - it is often highly sub-optimal; however, it is also a - questionable practice for a naive management station to - attempt conceptual row creation.) - - Alternately, the MIB module which defines the conceptual row - might provide one or more objects which provide assistance - in determining an unused instance-identifier. For example, - if the conceptual row is indexed by an integer-value, then - an object having an integer-valued SYNTAX clause might be - defined for such a purpose, allowing a management station to - issue a management protocol retrieval operation. In order - to avoid unnecessary collisions between competing management - stations, `adjacent' retrievals of this object should be - different. - - Finally, the management station could select a pseudo-random - number to use as the index. In the event that this index - was already in use and an inconsistentValue was returned in - response to the management protocol set operation, the - management station should simply select a new pseudo-random - number and retry the operation. - - A MIB designer should choose between the two latter - algorithms based on the size of the table (and therefore the - efficiency of each algorithm). For tables in which a large - number of entries are expected, it is recommended that a MIB - object be defined that returns an acceptable index for - creation. For tables with small numbers of entries, it is - recommended that the latter pseudo-random index mechanism be - used. - - - Interaction 2: Creating the Conceptual Row - - Once an unused instance-identifier has been selected, the - management station determines if it wishes to create and - activate the conceptual row in one transaction or in a - negotiated set of interactions. - - Interaction 2a: Creating and Activating the Conceptual Row - - The management station must first determine the column - requirements, i.e., it must determine those columns for - which it must or must not provide values. Depending on the - complexity of the table and the management station's - knowledge of the agent's capabilities, this determination - can be made locally by the management station. Alternately, - the management station issues a management protocol get - operation to examine all columns in the conceptual row that - it wishes to create. In response, for each column, there - are three possible outcomes: - - - a value is returned, indicating that some other - management station has already created this conceptual - row. We return to interaction 1. - - - the exception `noSuchInstance' is returned, - indicating that the agent implements the object-type - associated with this column, and that this column in at - least one conceptual row would be accessible in the MIB - view used by the retrieval were it to exist. For those - columns to which the agent provides read-create access, - the `noSuchInstance' exception tells the management - station that it should supply a value for this column - when the conceptual row is to be created. - - - the exception `noSuchObject' is returned, indicating - that the agent does not implement the object-type - associated with this column or that there is no - conceptual row for which this column would be - accessible in the MIB view used by the retrieval. As - such, the management station can not issue any - management protocol set operations to create an - instance of this column. - - Once the column requirements have been determined, a - management protocol set operation is accordingly issued. - This operation also sets the new instance of the status - column to `createAndGo'. - - When the agent processes the set operation, it verifies that - it has sufficient information to make the conceptual row - available for use by the managed device. The information - available to the agent is provided by two sources: the - management protocol set operation which creates the - conceptual row, and, implementation-specific defaults - supplied by the agent (note that an agent must provide - implementation-specific defaults for at least those objects - which it implements as read-only). If there is sufficient - information available, then the conceptual row is created, a - `noError' response is returned, the status column is set to - `active', and no further interactions are necessary (i.e., - interactions 3 and 4 are skipped). If there is insufficient - information, then the conceptual row is not created, and the - set operation fails with an error of `inconsistentValue'. - On this error, the management station can issue a management - protocol retrieval operation to determine if this was - because it failed to specify a value for a required column, - or, because the selected instance of the status column - already existed. In the latter case, we return to - interaction 1. In the former case, the management station - can re-issue the set operation with the additional - information, or begin interaction 2 again using - `createAndWait' in order to negotiate creation of the - conceptual row. - - NOTE WELL - - Regardless of the method used to determine the column - requirements, it is possible that the management - station might deem a column necessary when, in fact, - the agent will not allow that particular columnar - instance to be created or written. In this case, the - management protocol set operation will fail with an - error such as `noCreation' or `notWritable'. In this - case, the management station decides whether it needs - to be able to set a value for that particular columnar - instance. If not, the management station re-issues the - management protocol set operation, but without setting - a value for that particular columnar instance; - otherwise, the management station aborts the row - creation algorithm. - - Interaction 2b: Negotiating the Creation of the Conceptual - Row - - The management station issues a management protocol set - operation which sets the desired instance of the status - column to `createAndWait'. If the agent is unwilling to - process a request of this sort, the set operation fails with - an error of `wrongValue'. (As a consequence, such an agent - must be prepared to accept a single management protocol set - operation, i.e., interaction 2a above, containing all of the - columns indicated by its column requirements.) Otherwise, - the conceptual row is created, a `noError' response is - returned, and the status column is immediately set to either - `notInService' or `notReady', depending on whether it has - sufficient information to make the conceptual row available - for use by the managed device. If there is sufficient - information available, then the status column is set to - `notInService'; otherwise, if there is insufficient - information, then the status column is set to `notReady'. - Regardless, we proceed to interaction 3. - - Interaction 3: Initializing non-defaulted Objects - - The management station must now determine the column - requirements. It issues a management protocol get operation - to examine all columns in the created conceptual row. In - the response, for each column, there are three possible - outcomes: - - - a value is returned, indicating that the agent - implements the object-type associated with this column - and had sufficient information to provide a value. For - those columns to which the agent provides read-create - access (and for which the agent allows their values to - be changed after their creation), a value return tells - the management station that it may issue additional - management protocol set operations, if it desires, in - order to change the value associated with this column. - - - the exception `noSuchInstance' is returned, - indicating that the agent implements the object-type - associated with this column, and that this column in at - least one conceptual row would be accessible in the MIB - view used by the retrieval were it to exist. However, - the agent does not have sufficient information to - provide a value, and until a value is provided, the - conceptual row may not be made available for use by the - managed device. For those columns to which the agent - provides read-create access, the `noSuchInstance' - exception tells the management station that it must - issue additional management protocol set operations, in - order to provide a value associated with this column. - - - the exception `noSuchObject' is returned, indicating - that the agent does not implement the object-type - associated with this column or that there is no - conceptual row for which this column would be - accessible in the MIB view used by the retrieval. As - such, the management station can not issue any - management protocol set operations to create an - instance of this column. - - If the value associated with the status column is - `notReady', then the management station must first deal with - all `noSuchInstance' columns, if any. Having done so, the - value of the status column becomes `notInService', and we - proceed to interaction 4. - - Interaction 4: Making the Conceptual Row Available - - Once the management station is satisfied with the values - associated with the columns of the conceptual row, it issues - a management protocol set operation to set the status column - to `active'. If the agent has sufficient information to - make the conceptual row available for use by the managed - device, the management protocol set operation succeeds (a - `noError' response is returned). Otherwise, the management - protocol set operation fails with an error of - `inconsistentValue'. - - - NOTE WELL - - A conceptual row having a status column with value - `notInService' or `notReady' is unavailable to the - managed device. As such, it is possible for the - managed device to create its own instances during the - time between the management protocol set operation - which sets the status column to `createAndWait' and the - management protocol set operation which sets the status - column to `active'. In this case, when the management - protocol set operation is issued to set the status - column to `active', the values held in the agent - supersede those used by the managed device. - - If the management station is prevented from setting the - status column to `active' (e.g., due to management station - or network failure) the conceptual row will be left in the - `notInService' or `notReady' state, consuming resources - indefinitely. The agent must detect conceptual rows that - have been in either state for an abnormally long period of - time and remove them. It is the responsibility of the - DESCRIPTION clause of the status column to indicate what an - abnormally long period of time would be. This period of - time should be long enough to allow for human response time - (including `think time') between the creation of the - conceptual row and the setting of the status to `active'. - In the absense of such information in the DESCRIPTION - clause, it is suggested that this period be approximately 5 - minutes in length. This removal action applies not only to - newly-created rows, but also to previously active rows which - are set to, and left in, the notInService state for a - prolonged period exceeding that which is considered normal - for such a conceptual row. - - - Conceptual Row Suspension - - When a conceptual row is `active', the management station - may issue a management protocol set operation which sets the - instance of the status column to `notInService'. If the - agent is unwilling to do so, the set operation fails with an - error of `wrongValue'. Otherwise, the conceptual row is - taken out of service, and a `noError' response is returned. - It is the responsibility of the DESCRIPTION clause of the - status column to indicate under what circumstances the - status column should be taken out of service (e.g., in order - for the value of some other column of the same conceptual - row to be modified). - - - Conceptual Row Deletion - - For deletion of conceptual rows, a management protocol set - operation is issued which sets the instance of the status - column to `destroy'. This request may be made regardless of - the current value of the status column (e.g., it is possible - to delete conceptual rows which are either `notReady', - `notInService' or `active'.) If the operation succeeds, - then all instances associated with the conceptual row are - immediately removed." - SYNTAX INTEGER - { - active(1), - notInService(2), - notReady(3), - createAndGo(4), - createAndWait(5), - destroy(6) - } - --- the following two values are states: --- these values may be read or written --- the following value is a state: --- this value may be read, but not written --- the following three values are --- actions: these values may be written, --- but are never read - TimeStamp ::= TEXTUAL-CONVENTION - STATUS current - DESCRIPTION - "The value of the sysUpTime object at which a specific - occurrence happened. The specific occurrence must be - defined in the description of any object defined using this - type." - SYNTAX TimeTicks - - --- --- Node definitions --- - - -- 1.3.6.1.4.1.1379 - cintelNS OBJECT IDENTIFIER ::= { enterprises 1379 } - - - - END - --- --- CINTEL-MIB.my --- diff --git a/sshsvc/mibs/CINTEL-MIB.smidb b/sshsvc/mibs/CINTEL-MIB.smidb deleted file mode 100644 index 7ff6e9b4c032619429e0d8b5f5e77a727d6aa002..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29052 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 diff --git a/sshsvc/mml/parse.go.bak b/sshsvc/mml/parse.go.bak deleted file mode 100644 index 4828e543..00000000 --- a/sshsvc/mml/parse.go.bak +++ /dev/null @@ -1,901 +0,0 @@ -package mml - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "math" - "net/http" - "regexp" - "strconv" - "strings" - - "ems.agt/lib/dborm" - "ems.agt/lib/global" - "ems.agt/lib/log" - "github.com/go-resty/resty/v2" - "golang.org/x/crypto/ssh" -) - -type Param struct { - Name string `json:"name"` - Value string `json:"value"` -} - -type MmlCommand struct { - Operation string `json:"operation"` - Object string `json:"object"` - Params []Param `json:"params"` - PaList []string `json:"paList"` - AaList []string `json:"aaList"` - AaMap map[string]interface{} `json:"aaMap"` - NaMap map[string]interface{} `json:"naMap"` - AaUri []string `json:"aaUri"` - AaLoc []string `json:"aaLoc"` // for loc parameter -} - -type MmlVar struct { - Version string `json:"version"` - Output string `json:"output"` - Limit int `json:"limit"` - User string `json:"user"` - Token string `josn:"token"` -} - -var OmcMmlVar *MmlVar - -func init() { - OmcMmlVar = &MmlVar{ - Version: "16.1.1", - Output: DefaultFormatType, - Limit: 50, - } -} - -func SetOmcMmlVarOutput(output string) { - OmcMmlVar.Output = output -} - -func SetOmcMmlVarLimit(limit int) { - OmcMmlVar.Limit = limit -} - -func splitByColon(str string) []string { - return splitBy(str, ':') -} - -func splitByComma(str string) []string { - return splitBy(str, ',') -} - -func splitBy(str string, sep rune) []string { - var result []string - var stack []string - var current []rune - var quotes, apoFlag bool = false, false - - for _, c := range str { - if c == '{' || c == '[' || (c == '\'' && apoFlag == false) || (c == '"' && quotes == false) { // "'" - apoFlag = true - quotes = true - stack = append(stack, string(c)) - } else if c == '}' || c == ']' || (c == '\'' && apoFlag == true) || (c == '"' && quotes == true) { - apoFlag = false - quotes = false - if len(stack) > 0 { - stack = stack[:len(stack)-1] - } - } - - if c == sep && len(stack) == 0 { - result = append(result, string(current)) - current = []rune{} - } else { - current = append(current, c) - } - } - - result = append(result, string(current)) - return result -} - -func ParseMMLCommand(mmlStr string, mmlComms *[]MmlCommand) error { - log.Info("ParseMMLCommand processing ...") - log.Debug("mmlStr: ", mmlStr) - - mc := new(MmlCommand) - reg := regexp.MustCompile(`\s*;\s*`) - mmls := reg.Split(mmlStr, -1) - for _, mml := range mmls { - log.Trace("mml:", mml) - if len(mml) == 0 { - continue - } - //reg := regexp.MustCompile(`\s*:\s*`) - //ms := reg.Split(mml, -1) - ms := splitByColon(mml) - if len(ms) < 1 || len(ms) > 2 { - err := global.ErrMmlInvalidCommandFormat - log.Error(err) - return err - } - if len(ms) == 2 { - cmd := strings.Trim(ms[0], " ") - reg = regexp.MustCompile(`\s+`) - cs := reg.Split(cmd, -1) - //cs := strings.Split(cmd, " ") - if len(cs) == 2 { - mc.Operation = cs[0] - mc.Object = cs[1] - } else { - err := global.ErrMmlInvalidCommandFormat - log.Error(err) - return err - } - //reg = regexp.MustCompile(`\s*,\s*`) - //reg = regexp.MustCompile(`(?U)(? 0 { - extUri := strings.Join(mml.AaUri, "/") - requestURI = requestURI + fmt.Sprintf(mmlMap.ExtUri, extUri) - } - if mmlMap.Params != "" { - params := strings.Join(mml.AaLoc, "+and+") - params = strings.ReplaceAll(params, " ", "+") // replace " " to "+" - log.Trace("params:", params) - if mmlMap.ParamTag == "SQL" && strings.TrimSpace(params) != "" { - params = "+where+" + params - } - requestURI = fmt.Sprintf("%s%s%s", requestURI, mmlMap.Params, params) - } - return requestURI -} - -func TransMml2HttpReq(sshConn *ssh.ServerConn, httpUri, uerAgent string, mml *MmlCommand) (*[]byte, error) { - log.Info("TransMml2HttpReq processing ...") - log.Debug("mml: ", mml) - - where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object) - mmlMap, err := dborm.XormGetMmlHttpMap("mml_http_map", where) - if err != nil { - log.Error("Failed to XormGetMmlHttpMap: ", err) - return ParseErrorOutput(err), err - } - if mmlMap == nil { - err := errors.New("Not found mml map") - log.Error(err) - return ParseErrorOutput(err), err - } - log.Trace("mmlMap: ", mmlMap) - if mmlMap.Output == "" { - mmlMap.Output = "{}" - } - outputJson := new(dborm.MmlOutput) - err = json.Unmarshal([]byte(mmlMap.Output), outputJson) - if err != nil { - log.Error("Failed to Unmarshal:", err) - return ParseErrorOutput(err), err - } - log.Trace("outputJson: ", outputJson) - inputJson := new(dborm.MmlInput) - log.Trace("mmlMap.Input: ", mmlMap.Input) - if mmlMap.Input == "" { - mmlMap.Input = "{}" - } - err = json.Unmarshal([]byte(mmlMap.Input), inputJson) - if err != nil { - log.Error("Failed to Unmarshal:", err) - return ParseErrorOutput(err), err - } - log.Trace("inputJson: ", inputJson) - - var requestURI string - var output *[]byte - client := resty.New() - switch strings.ToLower(mmlMap.Method) { - case "get": - requestURI = parseRequestUri(httpUri, mmlMap, mml) - log.Debugf("method: Get requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"accessToken": fmt.Sprintf("%x", sshConn.SessionID())}). - SetHeaders(map[string]string{"User-Agent": uerAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI) - if err != nil { - log.Error("Failed to Get:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(outputJson, response) - } - case "post": - requestURI = parseRequestUri(httpUri, mmlMap, mml) - body := ParseInputBody(inputJson, mml) - log.Debugf("method: Post requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"accessToken": fmt.Sprintf("%x", sshConn.SessionID())}). - SetHeaders(map[string]string{"User-Agent": uerAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(*body). - Post(requestURI) - if err != nil { - log.Error("Failed to Post:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(outputJson, response) - } - case "put": - requestURI = parseRequestUri(httpUri, mmlMap, mml) - body := ParseInputBody(inputJson, mml) - log.Debugf("method: Put requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"accessToken": fmt.Sprintf("%x", sshConn.SessionID())}). - SetHeaders(map[string]string{"User-Agent": uerAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - SetBody(*body). - Put(requestURI) - if err != nil { - log.Error("Failed to Put:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(outputJson, response) - } - case "delete": - requestURI = parseRequestUri(httpUri, mmlMap, mml) - log.Debugf("method: Delete requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"accessToken": fmt.Sprintf("%x", sshConn.SessionID())}). - SetHeaders(map[string]string{"User-Agent": uerAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Delete(requestURI) - if err != nil { - log.Error("Failed to Delete:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(outputJson, response) - } - case "patch": - requestURI = parseRequestUri(httpUri, mmlMap, mml) - log.Debugf("method: patch requestURI: %s", requestURI) - response, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{"accessToken": fmt.Sprintf("%x", sshConn.SessionID())}). - SetHeaders(map[string]string{"User-Agent": uerAgent}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Patch(requestURI) - if err != nil { - log.Error("Failed to Patch:", err) - output = ParseErrorOutput(err) - } else { - output = ParseOutputResponse(outputJson, response) - } - default: - err := errors.New("not found mml command") - log.Error(err) - output = ParseErrorOutput(err) - } - return output, nil -} - -const ( - MaxMmlOutputBufferSize = 1000000 - FormatTypeJson = "json" - FormatTypeTable = "table" - DefaultFormatType = FormatTypeTable -) - -const ( - RetCodeSucceeded = 0 - RetCodeFailed = 0 -) - -func ParseInputBody(inputJson *dborm.MmlInput, mml *MmlCommand) *[]byte { - inputBody := make(map[string]interface{}) - log.Trace("mml.NaMap:", mml.NaMap) - log.Trace("mml.AaMap:", mml.AaMap) - if strings.ToLower(inputJson.BodyFmt) == "putdb" { - for _, icol := range inputJson.Cols { - log.Trace("icol:", icol) - mml.NaMap[icol.Name] = icol.Value - } - inputBody[inputJson.BodyKey] = mml.NaMap - } else { - inputParams := make([]map[string]interface{}, 0) - inputParams = append(inputParams, mml.NaMap) - inputBody[inputJson.BodyKey] = inputParams - } - - body, err := json.Marshal(inputBody) - if err != nil { - log.Error("Failed to marshal:", err) - } - - log.Trace("inputBody:", inputBody) - log.Trace("body:", string(body)) - return &body -} - -func ParseOutputResponse(outputJson *dborm.MmlOutput, response *resty.Response) *[]byte { - var output []byte - var str bytes.Buffer - - switch response.StatusCode() { - case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: - if OmcMmlVar.Output == FormatTypeJson { - code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status()) - title := formatTitle(outputJson.Title) - - json.Indent(&str, response.Body(), "", " ") - log.Trace(str.String()) - - output = global.BytesCombine1([]byte(code), []byte(title), str.Bytes(), []byte("\n")) - } else { - log.Trace("Body:", string(response.Body())) - mapDatas := make(map[string]interface{}, 0) - - err := json.Unmarshal(response.Body(), &mapDatas) - if err != nil { - log.Error("Failed to json.Unmarshal:", err) - //output = *ParseErrorOutput(err) - output = *ParseErrorOutput(string(response.Body())) - return &output - } - log.Trace("mapDatas:", mapDatas) - switch strings.ToLower(outputJson.RetFmt) { - case "getdb": - if len(mapDatas) > 0 { - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - if len(data.([]interface{})) > 0 { - table := (data.([]interface{}))[0] - log.Trace("table:", table) - - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - title := formatTitle(outputJson.Title) - fmtResults := ParseTableOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults)) - } - } - case "deletedb": - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - - if len(data.(map[string]interface{})) > 0 { - table := data.(map[string]interface{}) - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - fmtResults := ParseDBOperOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(fmtResults)) - } - case "postdb": - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - - if len(data.(map[string]interface{})) > 0 { - table := data.(map[string]interface{}) - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - fmtResults := ParseDBOperOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(fmtResults)) - } - case "putdb": - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - if len(data.(map[string]interface{})) > 0 { - table := data.(map[string]interface{}) - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - fmtResults := ParseDBOperOutput(outputJson, table) - output = global.BytesCombine1([]byte(code), []byte(fmtResults)) - } - case "getnf": - if len(mapDatas) > 0 { - var data interface{} - for _, data = range mapDatas { - log.Trace("data:", data) - break - } - if len(data.([]interface{})) > 0 { - //table := (data.([]interface{}))[0] - //log.Trace("table:", table) - - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - title := formatTitle(outputJson.Title) - fmtResults := ParseNFTableOutput(outputJson, data) - output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults)) - } - } - default: - code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded) - output = global.BytesCombine1([]byte(code)) - } - - } - default: - if OmcMmlVar.Output == FormatTypeJson { - code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status()) - //title := formatTitle("Network Element Information") - - json.Indent(&str, response.Body(), "", " ") - log.Trace(str.String()) - - output = global.BytesCombine1([]byte(code), str.Bytes(), []byte("\n")) - } else { - log.Trace("Body:", string(response.Body())) - mapResults := make(map[string]interface{}, 0) - - err := json.Unmarshal(response.Body(), &mapResults) - if err != nil { - log.Error("Failed to json.Unmarshal:", err) - output = *ParseErrorOutput(string(response.Body())) - } else { - log.Trace("mapResults:", mapResults) - errResult := mapResults["error"] - log.Trace("errResult:", errResult) - if len(errResult.(map[string]interface{})) > 0 { - errCode, _ := strconv.Atoi(fmt.Sprintf("%v", errResult.(map[string]interface{})["errorCode"])) - errorInfo := errResult.(map[string]interface{})["errorInfo"] - output = []byte(fmt.Sprintf(outputJson.ErrMsg, errCode, errorInfo)) - } - } - } - } - return &output -} - -func ParseDBOperOutput(outputJson *dborm.MmlOutput, cols any) string { - var colOutput []dborm.ColOutput = outputJson.Cols - var value, retFmtCols string - if len(cols.(map[string]interface{})) > 0 { - if len(colOutput) > 0 { - coln := colOutput[0].Name - value = fmt.Sprintf("%v", cols.(map[string]interface{})[coln]) - log.Tracef("coln:%s value:%s", coln, value) - retFmtCols = colOutput[0].Display + " = " + value + "\n\n" - } - } - - return retFmtCols -} - -func ParseNFTableOutput(outputJson *dborm.MmlOutput, cols any) string { - var colOutput []dborm.ColOutput - var fmtColName string - var colName []string - var spaceNum int = 1 - var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left" - - if outputJson.SepSpaceNum != 0 { - spaceNum = outputJson.SepSpaceNum - } - if outputJson.AlignmentM != "" { - alignmentM = outputJson.AlignmentM - } - if outputJson.AlignmentSN != "" { - alignmentSN = outputJson.AlignmentSN - } - if outputJson.AlignmentSV != "" { - alignmentSV = outputJson.AlignmentSV - } - - maxLength := math.MinInt64 - for _, coln := range outputJson.Cols { - log.Trace("coln:", coln) - - if len(coln.Display) > maxLength { - maxLength = len(coln.Display) - } - if coln.Length < len(coln.Display) { - coln.Length = len(coln.Display) - } - - colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display)) - colOutput = append(colOutput, coln) - } - fmtColName = formatLineBySpace(&colName, spaceNum) - log.Trace("fmtColName:", fmtColName) - - var retFmtCols string - var fmtColValues []string - var numberResult int - // for _, colnvs := range cols.([]interface{}) { - // log.Trace("colnvs:", colnvs) - // if colnvs == nil { - // break - // } - numberResult = len(cols.([]interface{})) - - if numberResult == 1 && outputJson.SingleList == true { - colnv := cols.([]interface{})[0] - log.Trace("colnv:", colnv) - - var fmtNV []string - for _, coln := range colOutput { - fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display) - log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName) - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value) - fmtNV = append(fmtNV, fmtName+": "+fmtValue) - } - - fmtResults := strings.Join(fmtNV, "\n") - log.Tracef("fmtResults:\n%s", fmtResults) - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtResults + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } else { - for i := 0; i < numberResult; i++ { - colnv := cols.([]interface{})[i] - log.Trace("colnv:", colnv) - var colValues []string - var newVal []string - for _, coln := range colOutput { - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - if len(coln.Alias) != 0 { - enumVal, _ := strconv.Atoi(value) - value = parseEnumAlias(&(coln.Alias), enumVal) - } - newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value)) - } - colValues = append(colValues, formatLineBySpace(&newVal, spaceNum)) - log.Trace("colValues:", colValues) - fmtColValues = append(fmtColValues, strings.Join(colValues, "\n")) - log.Trace("fmtColValues:", fmtColValues) - } - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } -} - -func ParseTableOutput(outputJson *dborm.MmlOutput, cols any) string { - var colOutput []dborm.ColOutput - var fmtColName string - var colName []string - var spaceNum int = 1 - var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left" - - if outputJson.SepSpaceNum != 0 { - spaceNum = outputJson.SepSpaceNum - } - if outputJson.AlignmentM != "" { - alignmentM = outputJson.AlignmentM - } - if outputJson.AlignmentSN != "" { - alignmentSN = outputJson.AlignmentSN - } - if outputJson.AlignmentSV != "" { - alignmentSV = outputJson.AlignmentSV - } - - maxLength := math.MinInt64 - for _, coln := range outputJson.Cols { - log.Trace("coln:", coln) - - if len(coln.Display) > maxLength { - maxLength = len(coln.Display) - } - if coln.Length < len(coln.Display) { - coln.Length = len(coln.Display) - } - - colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display)) - colOutput = append(colOutput, coln) - } - fmtColName = formatLineBySpace(&colName, spaceNum) - log.Trace("fmtColName:", fmtColName) - - var retFmtCols string - var fmtColValues []string - var numberResult int - for _, colnvs := range cols.(map[string]interface{}) { - log.Trace("colnvs:", colnvs) - if colnvs == nil { - break - } - numberResult = len(colnvs.([]interface{})) - - if numberResult == 1 && outputJson.SingleList == true { - colnv := colnvs.([]interface{})[0] - log.Trace("colnv:", colnv) - - var fmtNV []string - for _, coln := range colOutput { - fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display) - log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName) - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value) - fmtNV = append(fmtNV, fmtName+": "+fmtValue) - } - - fmtResults := strings.Join(fmtNV, "\n") - log.Tracef("fmtResults:\n%s", fmtResults) - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtResults + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } else { - for i := 0; i < numberResult; i++ { - colnv := colnvs.([]interface{})[i] - log.Trace("colnv:", colnv) - var colValues []string - var newVal []string - for _, coln := range colOutput { - value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name]) - if len(coln.Alias) != 0 { - enumVal, _ := strconv.Atoi(value) - value = parseEnumAlias(&(coln.Alias), enumVal) - } - newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value)) - } - colValues = append(colValues, formatLineBySpace(&newVal, spaceNum)) - log.Trace("colValues:", colValues) - fmtColValues = append(fmtColValues, strings.Join(colValues, "\n")) - log.Trace("fmtColValues:", fmtColValues) - } - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols - } - } - fmtEnd := fmt.Sprintf(outputJson.End, numberResult) - retFmtCols = fmtColName + "\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd - log.Tracef("retFmtCols:\n%s", retFmtCols) - return retFmtCols -} - -func parseEnumAlias(alias *[]string, enumVal int) string { - return (*alias)[enumVal] -} - -func formatLineBySpace(strArray *[]string, spaceNum int) string { - space := strings.Repeat(" ", spaceNum) - return strings.Join(*strArray, space) -} - -func ParseAlignmentOutput(length int, alignment string, str string) string { - spaceLen := length - len(str) - if spaceLen < 0 { - log.Warnf("len(str=%s)=%d more length=%d", str, len(str), length) - spaceLen = 0 - } - var retStr string - switch alignment { - case "Left": - suffix := strings.Repeat(" ", spaceLen) - retStr = str + suffix - case "Right": - prefix := strings.Repeat(" ", spaceLen) - retStr = prefix + str - log.Tracef("retStr:%s", retStr) - case "Middle": - prefix := strings.Repeat(" ", int(math.Ceil(float64(spaceLen)/2))) - suffix := strings.Repeat(" ", int(math.Floor(float64(spaceLen)/2))) - retStr = prefix + str + suffix - } - log.Tracef("length=%d, spaceLne=%d, alignment=%s, str=%s, retStr=%s", length, spaceLen, alignment, str, retStr) - return retStr -} - -func ParseErrorOutput(err any) *[]byte { - var output []byte - - var formatType string = DefaultFormatType - if formatType == FormatTypeJson { - output = []byte(fmt.Sprintf("ErrorCode = 1 Error message: %v\n\n", err)) - } else { - output = []byte(fmt.Sprintf("RetCode = -1 operation failed: %v\n\n", err)) - } - - return &output -} - -func formatTitle(title string) string { - var builder strings.Builder - builder.WriteString(title) - builder.WriteString("\n") - for i := 0; i < len(title); i++ { - builder.WriteString("-") - } - builder.WriteString("\n") - return builder.String() -} - -func formatTableOutput() { - -} diff --git a/sshsvc/setHLRServiceState b/sshsvc/setHLRServiceState deleted file mode 100644 index dee6e381..00000000 --- a/sshsvc/setHLRServiceState +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -TargetIP="[2001:db8::9166]" -PORT="34957" -OID=".1.3.6.1.4.1.1379.2.3.3.3.1.1.9.0" - -case "$1" in - 1) - echo -n "Set HLR state link down ... " - snmpset -v3 -l noAuthNoPriv -u manager ${TargetIP}:${PORT} ${OID} i 1 >/dev/null - echo "done" - ;; - 2) - echo -n "Set HLR state link up ... " - snmpset -v3 -l noAuthNoPriv -u manager ${TargetIP}:${PORT} ${OID} i 2 >/dev/null - echo "done" - ;; - 3) - echo -n "Set HLR state authentication failure ... " - snmpset -v3 -l noAuthNoPriv -u manager ${TargetIP}:${PORT} ${OID} i 3 >/dev/null - echo "done" - ;; - *) - echo "Unknown state ($1)" - ;; -esac \ No newline at end of file diff --git a/sshsvc/snmp/snmp.go b/sshsvc/snmp/snmp.go deleted file mode 100644 index 613dcd8e..00000000 --- a/sshsvc/snmp/snmp.go +++ /dev/null @@ -1,553 +0,0 @@ -package snmp - -import ( - "flag" - "fmt" - "log" - "net" - "os" - "path/filepath" - "strings" - "time" - - g "github.com/gosnmp/gosnmp" - "github.com/slayercat/GoSNMPServer" - "github.com/slayercat/GoSNMPServer/mibImps" -) - -type SNMPService struct { - ListenAddr string - ListenPort uint16 - UserName string - AuthPass string - AuthProto string - PrivPass string - PrivProto string - EngineID string - TrapPort uint16 - TrapListen bool - TrapBool bool - TrapTick uint16 - TimeOut uint16 - TrapTarget string - - ListenHost string - TrapHost string - - SysName string - SysDescr string - SysLocation string - SysContact string - SysStatus string - SysService int -} - -func (s *SNMPService) getAuthProto() g.SnmpV3AuthProtocol { - switch s.AuthProto { - case "NoAuth": - return g.NoAuth - case "MD5": - return g.MD5 - case "SHA": - return g.SHA - default: - } - return g.MD5 -} - -func (s *SNMPService) getPrivProto() g.SnmpV3PrivProtocol { - switch s.PrivProto { - case "NoPriv": - return g.NoPriv - case "DES": - return g.DES - case "AES": - return g.AES - case "AES192": - return g.AES192 - case "AES256": - return g.AES256 - default: - } - return g.DES -} - -func (s *SNMPService) setSecParamsList() []g.UsmSecurityParameters { - var secParamsList = []g.UsmSecurityParameters{ - { - UserName: s.UserName, - AuthenticationProtocol: s.getAuthProto(), - AuthenticationPassphrase: s.AuthPass, - PrivacyProtocol: s.getPrivProto(), - PrivacyPassphrase: s.PrivPass, - AuthoritativeEngineID: s.EngineID, - }, - // { - // UserName: "myuser2", - // AuthenticationProtocol: g.SHA, - // AuthenticationPassphrase: "mypassword2", - // PrivacyProtocol: g.DES, - // PrivacyPassphrase: "myprivacy2", - // AuthoritativeEngineID: s.EngineID, - // }, - // { - // UserName: "myuser2", - // AuthenticationProtocol: g.MD5, - // AuthenticationPassphrase: "mypassword2", - // PrivacyProtocol: g.AES, - // PrivacyPassphrase: "myprivacy2", - // AuthoritativeEngineID: s.EngineID, - // }, - } - return secParamsList -} - -func (s *SNMPService) StartSNMPServer() { - // 设置引擎启动次数和引varvar - var engineBoots uint32 = 1 - //var engineTime uint32 = uint32(time.Now().Unix() % 2147483647) // 使用当前时间初始化 - //var engineTime uint32 = 3600 // 使用当前时间初始化 - master := GoSNMPServer.MasterAgent{ - Logger: GoSNMPServer.NewDefaultLogger(), - SecurityConfig: GoSNMPServer.SecurityConfig{ - NoSecurity: true, - AuthoritativeEngineBoots: engineBoots, - // OnGetAuthoritativeEngineTime: func() uint32 { - // return engineTime - // }, - //AuthoritativeEngineID: GoSNMPServer.SNMPEngineID{EngineIDData: "0x800007DB03360102101100"}, - - Users: s.setSecParamsList(), - }, - SubAgents: []*GoSNMPServer.SubAgent{ - { - UserErrorMarkPacket: false, - CommunityIDs: []string{"public", "private"}, // SNMPv1 and SNMPv2c community strings - OIDs: s.handleOIDs(), - //OIDs: mibImps.All(), - }, - }, - } - - server := GoSNMPServer.NewSNMPServer(master) - err := server.ListenUDP("udp", s.ListenHost) - if err != nil { - log.Fatalf("Error in listen: %+v", err) - } - server.ServeForever() -} - -func (s *SNMPService) handleOIDs() []*GoSNMPServer.PDUValueControlItem { - customOIDs := []*GoSNMPServer.PDUValueControlItem{ - { - OID: "1.3.6.1.4.1.1379.2.3.3.3.1.1.1.0", - Type: g.OctetString, - OnGet: func() (value interface{}, err error) { - return s.SysName, nil - }, - OnSet: func(value interface{}) error { - // 将[]uint8转换为string - if v, ok := value.([]uint8); ok { - s.SysName = string(v) - log.Printf("Set request for OID 1.3.6.1.4.1.1379.2.3.3.3.1.1.1.0 with value %v", s.SysName) - return nil - } - return nil - }, - }, - { - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1.2.0", - Type: g.OctetString, - OnGet: func() (value interface{}, err error) { - return s.SysStatus, nil - }, - OnSet: func(value interface{}) error { - // 将[]uint8转换为string - if v, ok := value.([]uint8); ok { - s.SysStatus = string(v) - log.Printf("Set request for OID 1.3.6.1.4.1.1379.2.3.3.3.1.1.2.0 with value %v", s.SysStatus) - return nil - } - return nil - }, - }, - { - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1.3.0", - Type: g.OctetString, - OnGet: func() (value interface{}, err error) { - return s.SysDescr, nil - }, - OnSet: func(value interface{}) error { - // 将[]uint8转换为string - if v, ok := value.([]uint8); ok { - s.SysDescr = string(v) - log.Printf("Set request for OID .1.3.6.1.4.1.1379.2.3.3.3.1.1.3.0 with value %v", s.SysDescr) - return nil - } - return nil - }, - }, - { - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1.4.0", - Type: g.OctetString, - OnGet: func() (value interface{}, err error) { - return s.SysLocation, nil - }, - OnSet: func(value interface{}) error { - // 将[]uint8转换为string - if v, ok := value.([]uint8); ok { - s.SysLocation = string(v) - log.Printf("Set request for OID .1.3.6.1.4.1.1379.2.3.3.3.1.1.4.0 with value %v", s.SysLocation) - return nil - } - return nil - }, - }, - { - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1.5.0", - Type: g.OctetString, - OnGet: func() (value interface{}, err error) { - return s.SysContact, nil - }, - OnSet: func(value interface{}) error { - // 将[]uint8转换为string - if v, ok := value.([]uint8); ok { - s.SysContact = string(v) - log.Printf("Set request for OID .1.3.6.1.4.1.1379.2.3.3.3.1.1.5.0 with value %v", s.SysContact) - return nil - } - return nil - }, - }, - { - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1.7.0", - Type: g.TimeTicks, - OnGet: func() (value interface{}, err error) { - return uint32(time.Now().Unix()), nil - }, - }, - { - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1.9.0", - Type: g.Integer, - OnGet: func() (value interface{}, err error) { - return s.SysService, nil - }, - OnSet: func(value interface{}) error { - if v, ok := value.(int); ok { - s.SysService = v - log.Printf("Set request for OID .1.3.6.1.4.1.1379.2.3.3.3.1.1.9.0 with value %v", s.SysService) - return nil - } - return nil - }, - }, - } - // 为 GETBULK 新增处理 OIDs - bulkOIDs := &GoSNMPServer.PDUValueControlItem{ - OID: ".1.3.6.1.4.1.1379.2.3.3.3.1.1", // 这里是您想要支持 GETBULK 的 OID 前缀 - Type: g.OctetString, - OnGet: func() (value interface{}, err error) { - // 假设我们返回一百度值,您可以根据您的实现进行调整 - values := []interface{}{s.SysName, s.SysStatus, s.SysDescr, s.SysLocation, s.SysContact, uint32(time.Now().Unix()), s.SysService} // 可以从其他结构中获取真实值 - return values, nil - }, - } - - customOIDs = append(customOIDs, bulkOIDs) - - // 获取mibImps.All()返回的OID列表 - mibOIDs := mibImps.All() - - // 使用Map来检测并移除重复的OID - oidMap := make(map[string]*GoSNMPServer.PDUValueControlItem) - for _, oid := range customOIDs { - oidMap[oid.OID] = oid - } - for _, oid := range mibOIDs { - if _, exists := oidMap[oid.OID]; !exists { - oidMap[oid.OID] = oid - } else { - log.Printf("Duplicate OID found: %s", oid.OID) - } - } - - // 将Map转换为Slice - allOIDs := make([]*GoSNMPServer.PDUValueControlItem, 0, len(oidMap)) - for _, oid := range oidMap { - allOIDs = append(allOIDs, oid) - } - - return allOIDs -} - -func (s *SNMPService) StartTrapServer() { - flag.Usage = func() { - fmt.Printf("Usage:\n") - fmt.Printf(" %s\n", filepath.Base(os.Args[0])) - flag.PrintDefaults() - } - - tl := g.NewTrapListener() - tl.OnNewTrap = s.MyTrapHandler - - usmTable := g.NewSnmpV3SecurityParametersTable(g.NewLogger(log.New(os.Stdout, "", 0))) - for i := range s.setSecParamsList() { - sp := &s.setSecParamsList()[i] // 使用指针 - err := usmTable.Add(sp.UserName, sp) - if err != nil { - usmTable.Logger.Print(err) - } - } - - // 设置引擎启动次数和引varvar - //var engineBoots uint32 = 1 - // var engineTime uint32 = uint32(time.Now().Unix() % 2147483647) // 使用当前时间初始化 - //var engineTime uint32 = 3600 // 使用当前时间初始化 - gs := &g.GoSNMP{ - Target: s.TrapTarget, - Port: s.TrapPort, - Transport: "udp", - Timeout: time.Duration(s.TimeOut) * time.Second, // 设置超时时间为x秒 - Version: g.Version3, // Always using version3 for traps, only option that works with all SNMP versions simultaneously - MsgFlags: g.NoAuthNoPriv, - SecurityModel: g.UserSecurityModel, - SecurityParameters: &g.UsmSecurityParameters{ - UserName: s.UserName, - AuthoritativeEngineID: s.EngineID, - AuthoritativeEngineBoots: 1, - //AuthoritativeEngineTime: 3600, - AuthenticationProtocol: s.getAuthProto(), - AuthenticationPassphrase: s.AuthPass, - PrivacyProtocol: s.getPrivProto(), - PrivacyPassphrase: s.PrivPass, - }, - //TrapSecurityParametersTable: usmTable, - ContextEngineID: s.EngineID, - ContextName: "v3test", - } - tl.Params = gs - tl.Params.Logger = g.NewLogger(log.New(os.Stdout, "", 0)) - - // 定时发送Trap - if s.TrapBool { - go s.SendPeriodicTraps(gs) - } - go s.monitorNetwork(gs) - - if s.TrapListen { - err := tl.Listen(s.TrapHost) - if err != nil { - log.Panicf("error in listen: %s", err) - } - } -} - -func (s *SNMPService) MyTrapHandler(packet *g.SnmpPacket, addr *net.UDPAddr) { - log.Printf("got trapdata from %s\n", addr.IP) - for _, v := range packet.Variables { - switch v.Type { - case g.OctetString: - b := v.Value.([]byte) - fmt.Printf("OID: %s, string: %x\n", v.Name, b) - - default: - log.Printf("trap: %+v\n", v) - } - } -} - -func (s *SNMPService) SendPeriodicTraps(gs *g.GoSNMP) { - err := gs.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - defer gs.Conn.Close() - - ticker := time.NewTicker(time.Duration(s.TrapTick) * time.Second) // 每10秒发送一次Trap - defer ticker.Stop() - - for range ticker.C { // 每x秒发送一次Trap - trap := g.SnmpTrap{ - Variables: []g.SnmpPDU{ - { - Name: ".1.3.6.1.2.1.1.3.0", - Type: g.TimeTicks, - Value: uint32(time.Now().Unix()), - }, - { - Name: ".1.3.6.1.6.3.1.1.4.1.0", - Type: g.ObjectIdentifier, - Value: ".1.3.6.1.6.3.1.1.5.1", - }, - }, - } - _, err = gs.SendTrap(trap) - if err != nil { - log.Printf("error sending trap: %s", err) - } else { - log.Printf("trap sent successfully") - } - } -} - -// 1. 设备链路连接失败时发送Trap (LinkDown) -func (s *SNMPService) sendLinkDownTrap(gs *g.GoSNMP, ifIndex int, ifDescr string) { - err := gs.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - defer gs.Conn.Close() - - trap := g.SnmpTrap{ - Variables: []g.SnmpPDU{ - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.1", // linkDown - Type: g.OctetString, - Value: ".1.3.6.1.4.1.1379.2.3.3.3.3.1", - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.1.1", // ifIndex - Type: g.Integer, - Value: ifIndex, - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.1.2", // ifDescr - Type: g.OctetString, - Value: ifDescr, - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.4", // severity OID - Type: g.Integer, - Value: 2, // event - }, - }, - } - - _, err = gs.SendTrap(trap) - if err != nil { - log.Printf("error sending LinkDown trap: %s", err) - } else { - log.Printf("LinkDown trap sent successfully") - } -} - -// 2. 设备链路恢复正常时发送Trap (LinkUp) -func (s *SNMPService) sendLinkUpTrap(gs *g.GoSNMP, ifIndex int, ifDescr string) { - err := gs.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - defer gs.Conn.Close() - - trap := g.SnmpTrap{ - Variables: []g.SnmpPDU{ - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.2", // linkUp - Type: g.OctetString, - Value: ".1.3.6.1.4.1.1379.2.3.3.3.3.2", - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.2.1", // ifIndex - Type: g.Integer, - Value: ifIndex, - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.2.2", // ifDescr - Type: g.OctetString, - Value: ifDescr, - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.4", // severity OID - Type: g.Integer, - Value: 5, // event - }, - }, - } - - _, err = gs.SendTrap(trap) - if err != nil { - log.Printf("error sending LinkUp trap: %s", err) - } else { - log.Printf("LinkUp trap sent successfully") - } -} - -// 3. 设备鉴权失败时发送Trap (AuthenticationFailure) -func (s *SNMPService) sendAuthFailureTrap(gs *g.GoSNMP, username, descr string) { - err := gs.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - defer gs.Conn.Close() - - trap := g.SnmpTrap{ - Variables: []g.SnmpPDU{ - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.3", // authenticationFailure - Type: g.OctetString, - Value: ".1.3.6.1.4.1.1379.2.3.3.3.3.3", - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.3.1", // 自定义OID,用于记录失败的用户名 - Type: g.OctetString, - Value: username, - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.3.3.2", // 自定义OID,用于记录描述 - Type: g.OctetString, - Value: descr, - }, - { - Name: ".1.3.6.1.4.1.1379.2.3.3.3.4", // severity OID - Type: g.Integer, - Value: 4, // event - }, - }, - } - - _, err = gs.SendTrap(trap) - if err != nil { - log.Printf("error sending AuthenticationFailure trap: %s", err) - } else { - log.Printf("AuthenticationFailure trap sent successfully") - } -} - -func (s *SNMPService) monitorNetwork(gs *g.GoSNMP) { - // 假设有一个函数 checkLinkStatus 返回链路状态 - for { - serviceStatus := s.checkServiceStatus() - switch strings.ToUpper(serviceStatus) { - case "LINK_DOWN": - index := 1 - ifDescr := fmt.Sprintf("Link(index=%d) DOWN", index) - s.sendLinkDownTrap(gs, index, ifDescr) // 假设接口索引为1 - s.SysService = 0 - case "LINK_UP": - index := 1 - ifDescr := fmt.Sprintf("Link(index=%d) UP", index) - s.sendLinkUpTrap(gs, index, ifDescr) // 假设接口索引为1 - s.SysService = 0 - case "AUTH_FAILURE": - descr := "Authentication Failure" - s.sendAuthFailureTrap(gs, s.UserName, descr) - s.SysService = 0 - default: - } - - time.Sleep(10 * time.Second) // 每10秒检查一次 - } -} - -func (s *SNMPService) checkServiceStatus() string { - switch s.SysService { - case 1: - return "LINK_DOWN" - case 2: - return "LINK_UP" - case 3: - return "AUTH_FAILURE" - default: - } - return "NORMAL" -} diff --git a/sshsvc/sshsvc.go b/sshsvc/sshsvc.go deleted file mode 100644 index d0526ff8..00000000 --- a/sshsvc/sshsvc.go +++ /dev/null @@ -1,575 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" - "net" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "sync" - "time" - - "be.ems/lib/global" - "be.ems/lib/log" - "be.ems/lib/mmlp" - "be.ems/sshsvc/config" - "be.ems/sshsvc/dborm" - "be.ems/sshsvc/logmml" - "be.ems/sshsvc/snmp" - omctelnet "be.ems/sshsvc/telnet" - - //"github.com/gliderlabs/ssh" - "golang.org/x/crypto/ssh" - "golang.org/x/term" -) - -var conf *config.YamlConfig - -var ( - telnetCC int - sshCC int - telnetMu sync.Mutex - sshMu sync.Mutex -) - -func init() { - conf = config.GetYamlConfig() - log.InitLogger(conf.Logger.File, conf.Logger.Duration, conf.Logger.Count, "omc:sshsvc", config.GetLogLevel()) - fmt.Printf("OMC sshsvc version: %s\n", global.Version) - log.Infof("========================= OMC sshsvc startup =========================") - log.Infof("OMC sshsvc version: %s %s %s", global.Version, global.BuildTime, global.GoVer) - db := conf.Database - err := dborm.InitDbClient(db.Type, db.User, db.Password, db.Host, db.Port, db.Name, db.ConnParam) - if err != nil { - fmt.Println("dborm.initDbClient err:", err) - os.Exit(1) - } - logmml.InitMmlLogger(conf.Logmml.File, conf.Logmml.Duration, conf.Logmml.Count, "omc", config.GetLogMmlLevel()) -} - -// readPrivateKey 读取SSH私钥,如果不存在则生成新的密钥对 -func readPrivateKey() ssh.Signer { - // 检查私钥文件是否存在 - if _, err := os.Stat(conf.Sshd.PrivateKey); os.IsNotExist(err) { - // 如果文件不存在,创建目录并生成密钥 - dir := filepath.Dir(conf.Sshd.PrivateKey) - if err := os.MkdirAll(dir, 0700); err != nil { - log.Fatal("Failed to create .ssh directory:", err) - os.Exit(2) - } - - // 使用ssh-keygen命令生成密钥对 - cmd := exec.Command("ssh-keygen", "-t", "rsa", "-P", "", "-f", conf.Sshd.PrivateKey) - if err := cmd.Run(); err != nil { - log.Fatal("Failed to generate SSH key:", err) - os.Exit(2) - } - } - - // 读取SSH密钥对 - privateKeyBytes, err := os.ReadFile(conf.Sshd.PrivateKey) - if err != nil { - log.Fatal("Failed to ReadFile", err) - os.Exit(2) - } - - privateKey, err := ssh.ParsePrivateKey(privateKeyBytes) - if err != nil { - log.Fatal("Failed to ParsePrivateKey", err) - os.Exit(3) - } - return privateKey -} - -func main() { - // 配置SSH服务器 - serverConfig := &ssh.ServerConfig{ - PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { - // 这里可以进行密码验证逻辑,例如检查用户名和密码是否匹配 - // validUser, _, err := dborm.XormCheckLoginUser(conn.User(), string(password), conf.OMC.UserCrypt) - // if err != nil { - // return nil, err - // } - // if validUser == true { - // sessionToken := fmt.Sprintf("%x", conn.SessionID()) // Generate new token to session ID - // sourceAddr := conn.RemoteAddr().String() - // timeOut := uint32(conf.Sshd.Timeout) - // sessionMode := conf.Sshd.Session - // log.Debugf("token:%s sourceAddr:%s", sessionToken, sourceAddr) - // affected, err := dborm.XormInsertSession(conn.User(), sourceAddr, sessionToken, timeOut, sessionMode) - // if err != nil { - // log.Error("Failed to insert Session table:", err) - // return nil, err - // } - // if affected == -1 { - // err := errors.New("Failed to get session") - // log.Error(err) - // return nil, err - // } - - // return nil, nil - // } - if handleAuth(conf.Sshd.AuthType, conn.User(), string(password)) { - return nil, nil - } - return nil, fmt.Errorf("invalid user or password") - }, - PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { - // 这里可以进行公钥验证逻辑,例如检查用户的公钥是否在允许的公钥列表中 - return nil, fmt.Errorf("public key authentication is failed") - }, - } - - privateKey := readPrivateKey() - serverConfig.AddHostKey(privateKey) - - // 启动SSH服务器 - hostUri := fmt.Sprintf("%s:%d", conf.Sshd.ListenAddr, conf.Sshd.ListenPort) - listener, err := net.Listen("tcp", hostUri) - if err != nil { - log.Fatal("Failed to Listen: ", err) - os.Exit(4) - } - //fmt.Printf("MML SSH server startup, listen port:%d\n", conf.Sshd.ListenPort) - // 启动telnet服务器 - //telnetUri := fmt.Sprintf("%s:%d", conf.TelnetServer.ListenAddr, conf.TelnetServer.ListenPort) - // telnetListener, err := net.Listen("tcp", telnetUri) - // if err != nil { - // log.Fatal("Failed to Listen: ", err) - // os.Exit(4) - // } - //fmt.Printf("MML Telnet server startup, listen port:%d\n", conf.TelnetServer.ListenPort) - // telnetconn, err := telnetListener.Accept() - // if err != nil { - // log.Fatal("Failed to accept telnet connection: ", err) - // os.Exit(6) - // } - - telnetSvc := omctelnet.TelnetHandler{ - ListenAddr: conf.TelnetServer.ListenAddr, - ListenPort: conf.TelnetServer.ListenPort, - UserName: conf.TelnetServer.UserName, - Password: conf.TelnetServer.Password, - AuthType: conf.TelnetServer.AuthType, - MaxConnNum: conf.TelnetServer.MaxConnNum, - TagNE: conf.TelnetServer.TagNE, - ListenHost: conf.TelnetServer.ListenAddr + ":" + strconv.Itoa(int(conf.TelnetServer.ListenPort)), - } - go telnetSvc.StartTelnetServer() - // go StartTelnetServer(telnetSvc.ListenHost) - - snmpSvc := snmp.SNMPService{ - ListenAddr: conf.SNMPServer.ListenAddr, - ListenPort: conf.SNMPServer.ListenPort, - UserName: conf.SNMPServer.UserName, - AuthPass: conf.SNMPServer.AuthPass, - AuthProto: conf.SNMPServer.AuthProto, - PrivPass: conf.SNMPServer.PrivPass, - PrivProto: conf.SNMPServer.PrivProto, - EngineID: conf.SNMPServer.EngineID, - TrapPort: conf.SNMPServer.TrapPort, - TrapListen: conf.SNMPServer.TrapListen, - TrapBool: conf.SNMPServer.TrapBool, - TrapTick: conf.SNMPServer.TrapTick, - TimeOut: conf.SNMPServer.TimeOut, - TrapTarget: conf.SNMPServer.TrapTarget, - - ListenHost: conf.SNMPServer.ListenAddr + ":" + strconv.Itoa(int(conf.SNMPServer.ListenPort)), - TrapHost: conf.SNMPServer.ListenAddr + ":" + strconv.Itoa(int(conf.SNMPServer.TrapPort)), - SysName: "HLR-0", - SysStatus: "Normal", - SysDescr: "HLR server(sysNO=0)", - SysLocation: "Shanghai", - SysContact: "", - SysService: 0, - } - - go snmpSvc.StartSNMPServer() - go snmpSvc.StartTrapServer() - - for { - conn, err := listener.Accept() - if err != nil { - log.Fatal("Failed to Accept: ", err) - os.Exit(5) - } - - go handleSSHConnection(conn, serverConfig) - } -} - -func handleAuth(authType, userName, password string) bool { - switch authType { - case "local": - if userName == conf.Sshd.UserName && password == conf.Sshd.Password { - return true - } - return false - case "radius": - exist, err := dborm.XEngDB().Table("OMC_PUB.sysUser").Where("userName=? AND password=md5(?)", userName, password).Exist() - if err != nil { - return false - } - return exist - case "omc": - - default: - } - - return false -} - -func StartTelnetServer(addr string) { - listener, err := net.Listen("tcp", addr) - if err != nil { - fmt.Println("Error starting Telnet server:", err) - return - } - defer listener.Close() - fmt.Println("Telnet server started on", addr) - - for { - conn, err := listener.Accept() - if err != nil { - fmt.Println("Error accepting Telnet connection:", err) - continue - } - - telnetMu.Lock() - if telnetCC >= int(conf.TelnetServer.MaxConnNum) { - telnetMu.Unlock() - io.WriteString(conn, "Connection limit reached. Try again later.\r\n") - conn.Close() - continue - } - telnetCC++ - telnetMu.Unlock() - - go handleTelnetConnection(conn) - } -} - -func handleTelnetConnection(conn net.Conn) { - defer func() { - telnetMu.Lock() - telnetCC-- - telnetMu.Unlock() - }() - defer conn.Close() - - reader := bufio.NewReader(conn) - writer := bufio.NewWriter(conn) - - // 发送欢迎信息 - writer.WriteString("Welcome to the Telnet server!\r\n") - writer.Flush() - - // 请求用户名 - writer.WriteString("Username: ") - writer.Flush() - user, _ := reader.ReadString('\n') - user = strings.TrimSpace(user) - - // 关闭回显模式 - writer.Write([]byte{255, 251, 1}) // IAC WILL ECHO - writer.Flush() - - // 请求密码 - writer.WriteString("Password: ") - writer.Flush() - - // 读取密码并清除控制序列 - var passBuilder strings.Builder - for { - b, err := reader.ReadByte() - if err != nil { - return - } - if b == '\n' || b == '\r' { - break - } - if b == 255 { // IAC - reader.ReadByte() // 忽略下一个字节 - reader.ReadByte() // 忽略下一个字节 - } else { - passBuilder.WriteByte(b) - } - } - pass := passBuilder.String() - - // 恢复回显模式 - writer.Write([]byte{255, 252, 1}) // IAC WONT ECHO - writer.Flush() - - if handleAuth(conf.TelnetServer.AuthType, user, pass) { - writer.WriteString("\r\nAuthentication successful!\r\n") - writer.Flush() - HandleCommands(user, conf.TelnetServer.TagNE, reader, writer) - } else { - writer.WriteString("\r\nAuthentication failed!\r\n") - writer.Flush() - } -} - -// 处理命令输 -func HandleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer) { - header := fmt.Sprintf("[%s@%s]> ", user, tag) - clearLine := "\033[2K\r" // ANSI 转义序列,用于清除当前行 - for { - var commandBuilder strings.Builder - for { - b, err := reader.ReadByte() - if err != nil { - return - } - if b == '\n' || b == '\r' { - break - } - if b == '\xff' || b == '\xfe' || b == '\x01' { - continue - } - if b == 127 { // 处理退格键 - if commandBuilder.Len() > 0 { - // 手动截断字符串 - command := commandBuilder.String() - command = command[:len(command)-1] - commandBuilder.Reset() - commandBuilder.WriteString(command) - writer.WriteString("\b \b") // 回显退格 - writer.Flush() - } - } else { - // 回显用户输入的字符 - writer.WriteByte(b) - writer.Flush() - commandBuilder.WriteByte(b) - } - } - command := strings.TrimSpace(commandBuilder.String()) - - // 处理其他命令 - switch command { - case "hello": - writer.WriteString("\r\nHello, world!\r\n") - case "time": - writer.WriteString(fmt.Sprintf("\r\nCurrent time: %s\r\n", time.Now().Format(time.RFC1123))) - case "exit", "quit": - writer.WriteString("\r\nGoodbye!\r\n") - writer.Flush() - return - case "": - default: - writer.WriteString("\r\nUnknown command\r\n") - writer.Flush() - } - writer.WriteString(clearLine + header) - writer.Flush() - } -} - -func handleSSHConnection(conn net.Conn, serverConfig *ssh.ServerConfig) { - // SSH握手 - sshConn, chans, reqs, err := ssh.NewServerConn(conn, serverConfig) - if err != nil { - log.Error("Failed to NewServerConn: ", err) - return - } - - log.Infof("SSH connect accepted,client version:%s,user:%s", sshConn.ClientVersion(), sshConn.User()) - - // 处理SSH请求 - go ssh.DiscardRequests(reqs) - - // 处理SSH通道 - for newChannel := range chans { - if newChannel.ChannelType() != "session" { - newChannel.Reject(ssh.UnknownChannelType, "unsupported channel type") - continue - } - - channel, requests, err := newChannel.Accept() - if err != nil { - log.Error("Failed to NewServerConn: ", err) - continue - } - - sshMu.Lock() - sshCC++ - if sshCC > int(conf.Sshd.MaxConnNum) { - sshMu.Unlock() - log.Error("Maximum number of connections exceeded") - channel.Write([]byte(fmt.Sprintf("Connection limit reached (limit=%d). Try again later.\r\n", conf.Sshd.MaxConnNum))) - conn.Close() - continue - } - sshMu.Unlock() - - go handleSSHChannel(conn, sshConn, channel, requests) - } -} - -func handleSSHChannel(conn net.Conn, sshConn *ssh.ServerConn, channel ssh.Channel, requests <-chan *ssh.Request) { - for req := range requests { - switch req.Type { - case "exec": - // 执行远程命令 - command := strings.TrimSpace(string(req.Payload))[4:] - //cmd := exec.Command( - cmd := exec.Command("cmd", "/C", command) - cmd.Stdin = channel - cmd.Stdout = channel - cmd.Stderr = channel.Stderr() - log.Trace("command:", command) - - err := cmd.Run() - if err != nil { - log.Error("Failed to cmd.Run: ", err) - } - - channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) - channel.Close() - closeConnection(conn) - // case "shell": - // // 处理交互式shell会话 - // // 在这里添加您的处理逻辑,例如启动一个shell进程并将其连接到channel - // // 请注意,处理交互式shell会话需要更复杂的逻辑,您可能需要使用类似于pty包来处理终端相关的操作 - // channel.Write([]byte("交互式shell会话已启动\n")) - // channel.Close() - // handleSSHShell(user, channel) - case "pty-req": - log.Info("A pty-req processing...") - req.Reply(true, nil) - handleSSHShell(sshConn, channel) - channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) - channel.Close() - closeConnection(conn) - log.Info("Channel closed") - default: - req.Reply(false, nil) - } - } -} - -func closeConnection(conn net.Conn) { - sshMu.Lock() - conn.Close() - sshCC-- - sshMu.Unlock() -} - -func handleSSHShell(sshConn *ssh.ServerConn, channel ssh.Channel) { - //conf = config.GetYamlConfig() - // 检查通道是否支持终端 - - omcMmlVar := &mmlp.MmlVar{ - Version: global.Version, - Output: mmlp.DefaultFormatType, - MmlHome: conf.Sshd.MmlHome, - Limit: conf.Sshd.MaxConnNum, - User: sshConn.User(), - SessionToken: fmt.Sprintf("%x", sshConn.SessionID()), - HttpUri: conf.OMC.HttpUri, - UserAgent: config.GetDefaultUserAgent(), - TagNE: conf.Sshd.TagNE, - } - term := term.NewTerminal(channel, fmt.Sprintf("[%s@%s]> ", omcMmlVar.User, omcMmlVar.TagNE)) - msg := fmt.Sprintf("\r\nWelcome to the %s server!\r\n", strings.ToUpper(omcMmlVar.TagNE)) - term.Write([]byte(msg)) - msg = fmt.Sprintf("Last login: %s from %s \r\n\r\n", time.Now().Format(time.RFC1123), sshConn.RemoteAddr()) - term.Write([]byte(msg)) - - // 启动交互式shell会话 - for { - line, err := term.ReadLine() - if err != nil { - if err == io.EOF { - break - } - log.Error("Failed to read line: ", err) - break - } - - cmdline := strings.TrimSpace(line) - if cmdline != "" { - logmml.Cmd(cmdline) - } - var response string - switch cmdline { - case "hello": - term.Write([]byte("Hello, world!\r\n")) - goto continueLoop - case "time": - response = fmt.Sprintf("Current time: %s\r\n", time.Now().Format(time.RFC1123)) - term.Write([]byte(response)) - goto continueLoop - case "exit", "quit": - goto exitLoop - case "": - goto continueLoop - case "help": - response = fmt.Sprintf("Usage: %s\n", line) - term.Write([]byte(response)) - goto continueLoop - - case "dsp variables": - response = fmt.Sprintf("version: %s\n Output: %s\n", omcMmlVar.Version, omcMmlVar.Output) - term.Write([]byte(response)) - goto continueLoop - - case "set mml output=json": - // mmlp.SetOmcMmlVarOutput("json") - omcMmlVar.Output = "json" - response = fmt.Sprintf("set ok, mmlVar.output = %s\n", omcMmlVar.Output) - term.Write([]byte(response)) - goto continueLoop - - case "set mml output=table": - // mmlp.SetOmcMmlVarOutput("table") - omcMmlVar.Output = "table" - response = fmt.Sprintf("set ok, mmlVar.output = %s\n", omcMmlVar.Output) - term.Write([]byte(response)) - goto continueLoop - - default: - var mmlCmds []mmlp.MmlCommand - mmlLine := strings.TrimSpace(line) - if err = mmlp.ParseMMLCommand(mmlLine, &mmlCmds); err != nil { - response = fmt.Sprintf("parse command error: %v\n", err) - term.Write([]byte(response)) - goto continueLoop - } - // if err = mmlp.ParseMMLParams(&mmlCmds); err != nil { - // response := fmt.Sprintf("#2 parse command error: %v\n", err) - // term.Write([]byte(response)) - // } - - for _, mmlCmd := range mmlCmds { - output, err := mmlp.TransMml2HttpReq(omcMmlVar, &mmlCmd) - if err != nil { - response = fmt.Sprintf("translate MML command error: %v\n", err) - term.Write([]byte(response)) - goto continueLoop - } - response = string(*output) - term.Write(*output) - } - goto continueLoop - } - continueLoop: - if response != "" { - logmml.Ret(response) - } - continue - exitLoop: - token := fmt.Sprintf("%x", sshConn.SessionID()) - _, err = dborm.XormLogoutUpdateSession(token) - if err != nil { - log.Error("Failed to XormLogoutUpdateSession:", err) - } - break - } -} diff --git a/sshsvc/telnet/telnet.go b/sshsvc/telnet/telnet.go deleted file mode 100644 index 18e3ed9a..00000000 --- a/sshsvc/telnet/telnet.go +++ /dev/null @@ -1,198 +0,0 @@ -package omctelnet - -import ( - "bufio" - "fmt" - "io" - "net" - "strings" - "sync" - "time" - - "be.ems/sshsvc/dborm" -) - -type TelnetHandler struct { - ListenAddr string - ListenPort uint16 - UserName string - Password string - AuthType string - MaxConnNum int - TagNE string - ListenHost string - - connCount int - mu sync.Mutex -} - -func (t *TelnetHandler) handleTelnetAuth(authType, userName, password string) bool { - switch authType { - case "local": - if userName == t.UserName && password == t.Password { - return true - } - return false - case "radius", "omc": - exist, err := dborm.XEngDB().Table("OMC_PUB.sysUser").Where("userName=? AND password=md5(?)", userName, password).Exist() - if err != nil { - return false - } - return exist - - default: - } - - return false -} - -func (t *TelnetHandler) StartTelnetServer() { - listener, err := net.Listen("tcp", t.ListenHost) - if err != nil { - fmt.Println("Error starting Telnet server:", err) - return - } - defer listener.Close() - fmt.Println("Telnet server started on", t.ListenHost) - - for { - conn, err := listener.Accept() - if err != nil { - fmt.Println("Error accepting Telnet connection:", err) - continue - } - - t.mu.Lock() - if t.connCount >= int(t.MaxConnNum) { - t.mu.Unlock() - msg := fmt.Sprintf("Connection limit reached (limit=%d). Try again later.\r\n", t.MaxConnNum) - io.WriteString(conn, msg) - conn.Close() - continue - } - t.connCount++ - t.mu.Unlock() - - go t.handleTelnetConnection(conn) - } -} - -func (t *TelnetHandler) handleTelnetConnection(conn net.Conn) { - defer func() { - t.mu.Lock() - t.connCount-- - t.mu.Unlock() - }() - defer conn.Close() - - reader := bufio.NewReader(conn) - writer := bufio.NewWriter(conn) - - // 发送欢迎信息 - - writer.WriteString(fmt.Sprintf("\r\nWelcome to the %s server!\r\n", strings.ToUpper(t.TagNE))) - writer.Flush() - - // 请求用户名 - writer.WriteString("Username: ") - writer.Flush() - user, _ := reader.ReadString('\n') - user = strings.TrimSpace(user) - - // 关闭回显模式 - writer.Write([]byte{255, 251, 1}) // IAC WILL ECHO - writer.Flush() - - // 请求密码 - writer.WriteString("Password: ") - writer.Flush() - - // 读取密码并清除控制序列 - var passBuilder strings.Builder - for { - b, err := reader.ReadByte() - if err != nil { - return - } - if b == '\n' || b == '\r' { - break - } - if b == 255 { // IAC - reader.ReadByte() // 忽略下一个字节 - reader.ReadByte() // 忽略下一个字节 - } else { - passBuilder.WriteByte(b) - } - } - pass := passBuilder.String() - - // 恢复回显模式 - writer.Write([]byte{255, 252, 1}) // IAC WONT ECHO - writer.Flush() - - if t.handleTelnetAuth(t.AuthType, user, pass) { - msg := fmt.Sprintf("\r\n\r\nLast login: %s from %s \r\n\r\n", time.Now().Format(time.RFC1123), conn.RemoteAddr()) - writer.WriteString(msg) - writer.Flush() - t.HandleCommands(user, t.TagNE, reader, writer) - } else { - writer.WriteString("\r\nAuthentication failed!\r\n") - writer.Flush() - } -} - -// 处理命令输 -func (t *TelnetHandler) HandleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer) { - header := fmt.Sprintf("[%s@%s]> ", user, tag) - clearLine := "\033[2K\r" // ANSI 转义序列,用于清除当前行 - for { - var commandBuilder strings.Builder - for { - b, err := reader.ReadByte() - if err != nil { - return - } - if b == '\n' || b == '\r' { - break - } - if b == '\xff' || b == '\xfe' || b == '\x01' { - continue - } - if b == 127 { // 处理退格键 - if commandBuilder.Len() > 0 { - // 手动截断字符串 - command := commandBuilder.String() - command = command[:len(command)-1] - commandBuilder.Reset() - commandBuilder.WriteString(command) - writer.WriteString("\b \b") // 回显退格 - writer.Flush() - } - } else { - // 回显用户输入的字符 - writer.WriteByte(b) - writer.Flush() - commandBuilder.WriteByte(b) - } - } - command := strings.TrimSpace(commandBuilder.String()) - - // 处理其他命令 - switch command { - case "hello": - writer.WriteString("\r\nHello, world!\r\n") - case "time": - writer.WriteString(fmt.Sprintf("\r\nCurrent time: %s\r\n", time.Now().Format(time.RFC1123))) - case "exit", "quit": - writer.WriteString("\r\n\r\nGoodbye!\r\n") - writer.Flush() - return - case "": - default: - writer.WriteString("\r\nUnknown command\r\n") - writer.Flush() - } - writer.WriteString(clearLine + header) - writer.Flush() - } -} From 8680244af1c58a2f635bb5996de5a26b4a357cdc Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:41:04 +0800 Subject: [PATCH 09/80] =?UTF-8?q?del:=20=E7=A7=BB=E9=99=A4iperf=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deb/iperf_2.0.13+dfsg1-1build1_amd64.deb | Bin 76492 -> 0 bytes .../iperf/rpm/iperf-2.1.6-2.el8.aarch64.rpm | Bin 133076 -> 0 bytes .../iperf/rpm/iperf3-3.6-6.ky10.aarch64.rpm | Bin 76348 -> 0 bytes .../iperf3/deb/iperf3_3.1.3-1_amd64.deb | Bin 8802 -> 0 bytes .../iperf3/deb/libiperf0_3.1.3-1_amd64.deb | Bin 55184 -> 0 bytes .../libsctp1_1.0.19+dfsg-1build1_amd64.deb | Bin 9370 -> 0 bytes .../iperf3/rpm/iperf3-3.6-6.ky10.aarch64.rpm | Bin 76348 -> 0 bytes .../rpm/iperf3-help-3.6-6.ky10.noarch.rpm | Bin 14436 -> 0 bytes src/framework/socket/tcp_client.go | 96 ------------------ src/framework/socket/tcp_server.go | 83 --------------- src/framework/socket/udp_client.go | 96 ------------------ src/framework/socket/udp_server.go | 74 -------------- 12 files changed, 349 deletions(-) delete mode 100644 src/assets/dependency/iperf/deb/iperf_2.0.13+dfsg1-1build1_amd64.deb delete mode 100644 src/assets/dependency/iperf/rpm/iperf-2.1.6-2.el8.aarch64.rpm delete mode 100644 src/assets/dependency/iperf/rpm/iperf3-3.6-6.ky10.aarch64.rpm delete mode 100644 src/assets/dependency/iperf3/deb/iperf3_3.1.3-1_amd64.deb delete mode 100644 src/assets/dependency/iperf3/deb/libiperf0_3.1.3-1_amd64.deb delete mode 100644 src/assets/dependency/iperf3/deb/libsctp1_1.0.19+dfsg-1build1_amd64.deb delete mode 100644 src/assets/dependency/iperf3/rpm/iperf3-3.6-6.ky10.aarch64.rpm delete mode 100644 src/assets/dependency/iperf3/rpm/iperf3-help-3.6-6.ky10.noarch.rpm delete mode 100644 src/framework/socket/tcp_client.go delete mode 100644 src/framework/socket/tcp_server.go delete mode 100644 src/framework/socket/udp_client.go delete mode 100644 src/framework/socket/udp_server.go diff --git a/src/assets/dependency/iperf/deb/iperf_2.0.13+dfsg1-1build1_amd64.deb b/src/assets/dependency/iperf/deb/iperf_2.0.13+dfsg1-1build1_amd64.deb deleted file mode 100644 index 323ae584e25836b48e96189ba31566993acc6912..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76492 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%0D&T{`8h>A&3R8R-7O~S1%i=^!- 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%0D-o0fIp*nN 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 a0hyNvxc(Fg=Ve^B>E9dz000003RzmHLZ{XM diff --git a/src/assets/dependency/iperf/rpm/iperf3-3.6-6.ky10.aarch64.rpm b/src/assets/dependency/iperf/rpm/iperf3-3.6-6.ky10.aarch64.rpm deleted file mode 100644 index b5d5a4a558a3a6685b6678a3f171ab2589710be2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76348 zcmeFWcQl>N*FSvp7LjN{l!Itd4+n?nooG>_m*bS^MDM+m=q+jxEkub<1kp>>AfgjN zh%TbUd%5F&zTfZjJnOgCZ@uqY??3mPHP@cco;@>r_LO~H`)t4d@dXP6Br+>UloMKj zTYyK1TZqTT6T)}J{l7~XAe{f+;CcBv#x;)s1iF<3lqG zkcoi;?w>LUXp3?C8k=1SfIwL50L2E1xz~6Tpg?~Z1waPcV{QGxm@@zc`p4PbH?3Yub~!khD9i~ch>+mc z-yDs0d{9l&p~Epne**(+|3xguyA9Wg%lD7;i+)`)=>-op2|sk|%Pd+lwtu1g=68(S zi{m~G@$ZITu$Gja66SbLS-of720DErZu3u-Cu;lNJm7kjSNh!SR4U0*%ZWm;8uGG> zYNWO5M<~VehlWjBA&&!0_oP8Z3X`S%go|f1&rwFA^%w7JBd zh9J6Pm}{@muv&YEUNVP0JcVgWjsDpe$d=Zr?n!b9o1OeEapG7g*4Kp<8B|TrF^;ot zVeZCQNjdc=&njMGEyR~H4@*psQN6a(mv#9*RIvB558g0J9ZjoP=WtW7VMjl$L-s)* z_Re8j@$vH^1qIMB2pTOSf)IuygoFh6MflK2xCH`<78JJNgY!cyU{DZ}PXs9<022@p zu;7CVh(Lspf@mQD2vP_wA|N1$Mxs#yP?(SaiVrP}=0gftK;a_7!Z1O!02<0?Ap}JM zD@IlDf4@fM_whmH0?*?^Ioo%kdQl&z&u~-QFAmkLwc)r6Zwb`yG+yWx7;UJfnB2;q zT>Aa9fj%_9Fa&pju)+P;rjHGcUwS9?*n8Ot!)ZNH4uRrQF;?rOp1VZhc1XVsNEJP)>|^&%G}Z4DH&3Y;XKY@)s!|*6-<^# z%SXYg^||;>e8>uIPvk`EVisc^*-No6g!H$^)t>8!Vka10hHnmAYG%2~f9|-`oP9K! ze-_tusLI<{>qFK(R4E%juDc%d9^DMZL8xrpu5d(pUfcOPS639TDgYXcbS29Q- z;{*9B{T℘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 GWkh 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%0Dm+V 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 aOC%Hm4W;SGW!f}i^9u9d9Tc3N{{H}V)9`)( diff --git a/src/assets/dependency/iperf3/deb/libiperf0_3.1.3-1_amd64.deb b/src/assets/dependency/iperf3/deb/libiperf0_3.1.3-1_amd64.deb deleted file mode 100644 index c81f6622c6958e7b4806b5bc292dbce9446afbe3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55184 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�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 diff --git a/src/assets/dependency/iperf3/rpm/iperf3-3.6-6.ky10.aarch64.rpm b/src/assets/dependency/iperf3/rpm/iperf3-3.6-6.ky10.aarch64.rpm deleted file mode 100644 index b5d5a4a558a3a6685b6678a3f171ab2589710be2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76348 zcmeFWcQl>N*FSvp7LjN{l!Itd4+n?nooG>_m*bS^MDM+m=q+jxEkub<1kp>>AfgjN zh%TbUd%5F&zTfZjJnOgCZ@uqY??3mPHP@cco;@>r_LO~H`)t4d@dXP6Br+>UloMKj zTYyK1TZqTT6T)}J{l7~XAe{f+;CcBv#x;)s1iF<3lqG zkcoi;?w>LUXp3?C8k=1SfIwL50L2E1xz~6Tpg?~Z1waPcV{QGxm@@zc`p4PbH?3Yub~!khD9i~ch>+mc z-yDs0d{9l&p~Epne**(+|3xguyA9Wg%lD7;i+)`)=>-op2|sk|%Pd+lwtu1g=68(S zi{m~G@$ZITu$Gja66SbLS-of720DErZu3u-Cu;lNJm7kjSNh!SR4U0*%ZWm;8uGG> zYNWO5M<~VehlWjBA&&!0_oP8Z3X`S%go|f1&rwFA^%w7JBd zh9J6Pm}{@muv&YEUNVP0JcVgWjsDpe$d=Zr?n!b9o1OeEapG7g*4Kp<8B|TrF^;ot zVeZCQNjdc=&njMGEyR~H4@*psQN6a(mv#9*RIvB558g0J9ZjoP=WtW7VMjl$L-s)* z_Re8j@$vH^1qIMB2pTOSf)IuygoFh6MflK2xCH`<78JJNgY!cyU{DZ}PXs9<022@p zu;7CVh(Lspf@mQD2vP_wA|N1$Mxs#yP?(SaiVrP}=0gftK;a_7!Z1O!02<0?Ap}JM zD@IlDf4@fM_whmH0?*?^Ioo%kdQl&z&u~-QFAmkLwc)r6Zwb`yG+yWx7;UJfnB2;q zT>Aa9fj%_9Fa&pju)+P;rjHGcUwS9?*n8Ot!)ZNH4uRrQF;?rOp1VZhc1XVsNEJP)>|^&%G}Z4DH&3Y;XKY@)s!|*6-<^# z%SXYg^||;>e8>uIPvk`EVisc^*-No6g!H$^)t>8!Vka10hHnmAYG%2~f9|-`oP9K! ze-_tusLI<{>qFK(R4E%juDc%d9^DMZL8xrpu5d(pUfcOPS639TDgYXcbS29Q- z;{*9B{T℘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 GWkh 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%0Dm+V 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 0 { - if _, err := conn.Write(msg); err != nil { - return "", err - } - } - - var buf bytes.Buffer - defer buf.Reset() - - tmp := make([]byte, 1024) - for { - select { - case <-time.After(timer): - c.LastResult = buf.String() - return c.LastResult, fmt.Errorf("timeout") - default: - // 读取命令消息 - n, err := conn.Read(tmp) - if n == 0 || err != nil { - tmp = nil - break - } - - tmpStr := string(tmp[:n]) - buf.WriteString(tmpStr) - - // 是否有终止符 - if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") { - tmp = nil - c.LastResult = buf.String() - return c.LastResult, nil - } - } - } -} diff --git a/src/framework/socket/tcp_server.go b/src/framework/socket/tcp_server.go deleted file mode 100644 index 755b41c3..00000000 --- a/src/framework/socket/tcp_server.go +++ /dev/null @@ -1,83 +0,0 @@ -package socket - -import ( - "fmt" - "net" - "strings" - - "be.ems/src/framework/logger" -) - -// SocketTCP TCP服务端 -type SocketTCP struct { - Addr string `json:"addr"` // 主机地址 - Port int64 `json:"port"` // 端口 - Listener *net.TCPListener `json:"listener"` - StopChan chan struct{} `json:"stop"` // 停止信号 -} - -// New 创建TCP服务端 -func (s *SocketTCP) New() (*SocketTCP, error) { - // IPV6地址协议 - proto := "tcp" - if strings.Contains(s.Addr, ":") { - proto = "tcp6" - s.Addr = fmt.Sprintf("[%s]", s.Addr) - } - address := fmt.Sprintf("%s:%d", s.Addr, s.Port) - - // 解析 TCP 地址 - tcpAddr, err := net.ResolveTCPAddr(proto, address) - if err != nil { - return nil, err - } - - // 监听 TCP 地址 - listener, err := net.ListenTCP(proto, tcpAddr) - if err != nil { - return nil, err - } - - s.Listener = listener - s.StopChan = make(chan struct{}, 1) - return s, nil -} - -// Close 关闭当前TCP服务端 -func (s *SocketTCP) Close() { - if s.Listener != nil { - s.StopChan <- struct{}{} - (*s.Listener).Close() - } -} - -// Resolve 处理消息 -func (s *SocketTCP) Resolve(callback func(conn *net.Conn, err error)) { - if s.Listener == nil { - callback(nil, fmt.Errorf("tcp service not created")) - return - } - - defer func() { - if err := recover(); err != nil { - callback(nil, fmt.Errorf("tcp service panic err")) - } - }() - - listener := *s.Listener - for { - select { - case <-s.StopChan: - callback(nil, fmt.Errorf("udp service stop")) - return - default: - conn, err := listener.Accept() - if err != nil { - logger.Errorf("Error accepting connection: %v ", err) - continue - } - defer conn.Close() - callback(&conn, nil) - } - } -} diff --git a/src/framework/socket/udp_client.go b/src/framework/socket/udp_client.go deleted file mode 100644 index 9c77aade..00000000 --- a/src/framework/socket/udp_client.go +++ /dev/null @@ -1,96 +0,0 @@ -package socket - -import ( - "bytes" - "fmt" - "net" - "strings" - "time" -) - -// ConnUDP 连接UDP客户端 -type ConnUDP struct { - Addr string `json:"addr"` // 主机地址 - Port int64 `json:"port"` // 端口 - - DialTimeOut time.Duration `json:"dialTimeOut"` // 连接超时断开 - - Client *net.Conn `json:"client"` - LastResult string `json:"lastResult"` // 记最后一次发送消息的结果 -} - -// New 创建UDP客户端 -func (c *ConnUDP) New() (*ConnUDP, error) { - // IPV6地址协议 - proto := "udp" - if strings.Contains(c.Addr, ":") { - proto = "udp6" - c.Addr = fmt.Sprintf("[%s]", c.Addr) - } - address := net.JoinHostPort(c.Addr, fmt.Sprint(c.Port)) - - // 默认等待5s - if c.DialTimeOut == 0 { - c.DialTimeOut = 5 * time.Second - } - - // 连接到服务端 - client, err := net.DialTimeout(proto, address, c.DialTimeOut) - if err != nil { - return nil, err - } - - c.Client = &client - return c, nil -} - -// Close 关闭当前UDP客户端 -func (c *ConnUDP) Close() { - if c.Client != nil { - (*c.Client).Close() - } -} - -// Send 发送消息 -func (c *ConnUDP) Send(msg []byte, ms int) (string, error) { - if c.Client == nil { - return "", fmt.Errorf("udp client not connected") - } - conn := *c.Client - - // 写入信息 - if len(msg) > 0 { - if _, err := conn.Write(msg); err != nil { - return "", err - } - } - - var buf bytes.Buffer - defer buf.Reset() - - tmp := make([]byte, 1024) - for { - select { - case <-time.After(time.Duration(time.Duration(ms).Milliseconds())): - c.LastResult = buf.String() - return c.LastResult, fmt.Errorf("timeout") - default: - // 读取命令消息 - n, err := conn.Read(tmp) - if n == 0 || err != nil { - tmp = nil - break - } - - tmpStr := string(tmp[:n]) - buf.WriteString(tmpStr) - - // 是否有终止符 - if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") { - tmp = nil - c.LastResult = buf.String() - return c.LastResult, nil - } - } - } -} diff --git a/src/framework/socket/udp_server.go b/src/framework/socket/udp_server.go deleted file mode 100644 index 1c9f8eaa..00000000 --- a/src/framework/socket/udp_server.go +++ /dev/null @@ -1,74 +0,0 @@ -package socket - -import ( - "fmt" - "net" - "strings" -) - -// SocketUDP UDP服务端 -type SocketUDP struct { - Addr string `json:"addr"` // 主机地址 - Port int64 `json:"port"` // 端口 - Conn *net.UDPConn `json:"conn"` - StopChan chan struct{} `json:"stop"` // 停止信号 -} - -// New 创建UDP服务端 -func (s *SocketUDP) New() (*SocketUDP, error) { - // IPV6地址协议 - proto := "udp" - if strings.Contains(s.Addr, ":") { - proto = "udp6" - s.Addr = fmt.Sprintf("[%s]", s.Addr) - } - address := fmt.Sprintf("%s:%d", s.Addr, s.Port) - - // 解析 UDP 地址 - udpAddr, err := net.ResolveUDPAddr(proto, address) - if err != nil { - return nil, err - } - - // 监听 UDP 地址 - conn, err := net.ListenUDP("udp", udpAddr) - if err != nil { - return nil, err - } - - s.Conn = conn - s.StopChan = make(chan struct{}, 1) - return s, nil -} - -// CloseService 关闭当前UDP服务端 -func (s *SocketUDP) Close() { - if s.Conn != nil { - s.StopChan <- struct{}{} - (*s.Conn).Close() - } -} - -// Resolve 处理消息 -func (s *SocketUDP) Resolve(callback func(*net.UDPConn, error)) { - if s.Conn == nil { - callback(nil, fmt.Errorf("udp service not created")) - return - } - - defer func() { - if err := recover(); err != nil { - callback(nil, fmt.Errorf("udp service panic err")) - } - }() - - for { - select { - case <-s.StopChan: - callback(nil, fmt.Errorf("udp service not created")) - return - default: - callback(s.Conn, nil) - } - } -} From d7adfa79ba79ce387972b1f580e419e3536146bc Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:45:45 +0800 Subject: [PATCH 10/80] =?UTF-8?q?perf:=20=E7=A7=BB=E9=99=A4=E6=8E=89?= =?UTF-8?q?=E6=97=A0=E7=94=A8=E9=85=8D=E7=BD=AE=E7=B2=BE=E7=AE=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/default/omc.yaml | 172 +++----------------------- local/omc.yaml | 219 ++++++++------------------------- src/config/config.default.yaml | 25 +++- src/config/config.local.yaml | 56 ++++----- src/config/config.prod.yaml | 32 +++-- src/framework/config/config.go | 43 +------ 6 files changed, 142 insertions(+), 405 deletions(-) diff --git a/build/default/omc.yaml b/build/default/omc.yaml index c1a1dae6..2da64727 100644 --- a/build/default/omc.yaml +++ b/build/default/omc.yaml @@ -7,21 +7,15 @@ serverVersion: "std" # interface encryption, default false # serverCryptoApi: false - +# route service configuration # service listen ipv4/v6 and port, support multiple routines -# ip: 0.0.0.0 or ::0, support IPv4/v6 -server: - - ipv4: 0.0.0.0 - ipv6: "" - port: 33030 # http listen port - schema: http - - ipv4: 0.0.0.0 - ipv6: "" - port: 33443 # https listen port - schema: https - certFile: /usr/local/etc/omc/certs/www.omc.net.crt - keyFile: /usr/local/etc/omc/certs/www.omc.net.key - +routeServer: + - addr: "0.0.0.0:33030" # route http port + schema: "http" + - addr: "0.0.0.0:33443" # route https port + schema: "https" + certFile: "/usr/local/etc/omc/certs/www.omc.net.crt" + keyFile: "/usr/local/etc/omc/certs/www.omc.net.key" # web service configuration # if you are using nginx to take over, you can disable the @@ -29,12 +23,12 @@ webServer: enabled: true # web server enabled, default false rootDir: /usr/local/etc/omc/web listen: - - addr: 0.0.0.0:80 - schema: http - - addr: 0.0.0.0:443 - schema: https - certFile: /usr/local/etc/omc/certs/www.omc.net.crt - keyFile: /usr/local/etc/omc/certs/www.omc.net.key + - addr: "0.0.0.0:80" # web http port + schema: "http" + - addr: "0.0.0.0:443" # web https port + schema: "https" + certFile: "/usr/local/etc/omc/certs/www.omc.net.crt" + keyFile: "/usr/local/etc/omc/certs/www.omc.net.key" # track configuration for NE signaling trace # host fill in the specific IP address @@ -61,7 +55,6 @@ database: # default data source name defaultDataSourceName: "std" - # redis cached data redis: dataSource: @@ -73,136 +66,11 @@ redis: # default data source name defaultDataSourceName: "default" - -# file: log file name -# level: /trace/debug/info/warn/error/fatal, default: debug -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation +# log logger: - file: /var/log/omc_restagent.log - level: warn - duration: 24 - count: 90 + fileDir: "/var/log" # Log File Dir + fileName: "omc.log" # Log File Name + level: 2 # Log Level of 0:silent<1:info<2:warn<3:error + maxDay: 7 # Log retention Days + maxSize: 10 # Log File cutting by size -# sleep: time delay for after write buffer (millisecond) -# deadLine: timeout for io read and write (second) -mml: - sleep: 200 - deadLine: 10 - sizeRow: 600 - sizeCol: 128 - bufferSize: 65535 - mmlHome: ./mmlhome - -# NE config -ne: - user: omcuser - etcdir: /usr/local/etc - bindir: /usr/local/bin - omcdir: /usr/local/omc - scpdir: /tmp - licensedir: /usr/local/etc/{neType}/license - # backup etc list of IMS, does not contain spaces - etcListIMS: "{*.yaml,mmtel,vars.cfg}" - etcListDefault: "{*.yaml,*.conf,*.cfg}" - # true/false to overwrite config file when dpkg ne software - dpkgOverwrite: false - # dpkg timeout (second) - dpkgTimeout: 180 - -# chk2ne: true/false, if put OmcNeConfig parameters to NE -omc: - uriPrefix: "/omc/rest" - neType: OMC - neId: 001 - rmUID: 4400HX101 - neName: OMC - province: "" - vendor: "" - dn: "" - chk2ne: false - capability: 50 - sn: "-" - expiryDate: "-" - checksign: false - rootDir: /usr/local/omc - binDir: /usr/local/omc/bin - backup: /usr/local/omc/backup - upload: /usr/local/omc/upload - frontUpload: /usr/local/omc/htdocs/front/upload - frontTraceDir: /usr/local/omc/htdocs/front/trace - software: /usr/local/omc/software - license: /usr/local/omc/license - gtpUri: gtp:192.168.2.119:32152 - checkContentType: false - testMode: false - rbacMode: true - runDir: /usr/local/omc/run - cmdTimeout: 120 - -# Alarm module setting -# Forward interface: -# TLS Skip verify: true/false -# email/sms -# smProxy: sms(Short Message Service)/smsc(SMS Centre) -# dataCoding: 0:GSM7BIT, 1:ASCII, 2:BINARY8BIT1, 3:LATIN1, -# 4:BINARY8BIT2, 6:CYRILLIC, 7:HEBREW, 8:UCS2 -alarm: - alarmEmailForward: - enable: false - emailList: "" - title: "Alarm from OMC" - smtp: mail.smtp.com - port: 25 - user: smtpext@smtp.com - password: "1000smtp@omc!" - tlsSkipVerify: true - alarmSMSForward: - enable: false - mobileList: "" - smscAddr: "192.168.13.114:2775" - systemID: "omc" - password: "omc123" - systemType: "UTRAN" - dataCoding: 0 - serviceNumber: "OMC" - sms: - apiURL: http://smsc.xxx.com/ - accessKeyID: xxxx - accessKeySecret: xxxx - signName: xxx SMSC - templateCode: 1000 - smProxy: smsc - -# User authorized information -# crypt: mysql/md5/bcrypt -# token: true/false to check accessToken -# expires for session, unit: second -# Support single/multiple session of user -# -auth: - crypt: bcrypt - token: true - expires: 1800 - session: multiple - publicKey: /usr/local/omc/etc/certs/omc - privateKey: /usr/local/omc/etc/certs/omc - -# Parameter for limit number -# rmuid_maxnum: the max number of rmUID, default: 50 -# alarmid_maxnum: the max number of AlarmID, default: 50 -# pmid_maxnum: the max number of pmID, default: 50 -# subid_maxnum: the max number of subscription ID, default: 20 -# uri_maxlen: the max length of uri, default: 8192 -# rmuid_regexp: regexp pattern of rmUID -params: - rmuidmaxnum: 50 - alarmidmaxnum: 50 - pmidmaxnum: 50 - subidmaxnum: 20 - urimaxlen: 2100000 - rmuidregexp: "[0-9]{4}[A-Z]{2}[A-Z]{2}[0-9A-Z]{1}[0-9A-Z]{3}[0-9A-Z]{1,16}" - -testConfig: - enabled: false - file: /usr/local/omc/etc/testconfig.yaml diff --git a/local/omc.yaml b/local/omc.yaml index f2adc98e..d4987cca 100644 --- a/local/omc.yaml +++ b/local/omc.yaml @@ -7,32 +7,28 @@ serverVersion: "std" # interface encryption, default false # serverCryptoApi: false +# route service configuration # service listen ipv4/v6 and port, support multiple routines -# ip: 0.0.0.0 or ::0, support IPv4/v6 -server: - - ipv4: "0.0.0.0" - ipv6: "" - port: 33040 # http listen port - schema: http - - ipv4: "0.0.0.0" - ipv6: "" - port: 33443 # https listen port - schema: https - certFile: ./local/certs/www.omc.net.crt - keyFile: ./local/certs/www.omc.net.key +routeServer: + - addr: "0.0.0.0:33040" # route http port + schema: "http" + - addr: "0.0.0.0:33443" # route https port + schema: "https" + certFile: "./local/certs/www.omc.net.crt" + keyFile: "./local/certs/www.omc.net.key" # web service configuration # if you are using nginx to take over, you can disable the webServer: enabled: false # web server enabled, default false - rootDir: ./local/web + rootDir: /usr/local/etc/omc/web listen: - - addr: "0.0.0.0:80" - schema: http - - addr: "0.0.0.0:443" - schema: https - certFile: ./local/certs/www.omc.net.crt - keyFile: ./local/certs/www.omc.net.key + - addr: "0.0.0.0:80" # web http port + schema: "http" + - addr: "0.0.0.0:443" # web https port + schema: "https" + certFile: "./local/certs/www.omc.net.crt" + keyFile: "./local/certs/www.omc.net.key" # track configuration for NE signaling trace # host fill in the specific IP address @@ -41,46 +37,42 @@ trace: host: "192.168.5.58" # trace host, default 127.0.0.1 port: 33033 # trace port, default 33033 -# data sources +# data source database: dataSource: - # Default database instance + # std: standard std: type: "mysql" - host: "192.168.9.58" - port: 13306 - username: "root" - password: "1000omc@kp!" - database: "omc_db_mainv2" - logging: true - # SQLite database instance + host: "192.168.9.58" # mysql host + port: 13306 # mysql port + username: "root" # mysql username + password: "1000omc@kp!" # mysql password + database: "omc_db_mainv2" # mysql database + # lite: lite lite: type: "sqlite" - database: "./local/omc_db.sqlite" - logging: true - # used to specify the default data source for multiple data resourece + database: "./local/omc_db.sqlite" # sqlite database + # default data source name defaultDataSourceName: "std" # redis cached data redis: dataSource: default: - port: 16379 # port - host: "192.168.9.58" # host - password: "helloearth" - db: 10 # db_num + port: 16379 # redis port + host: "192.168.9.58" # redis host + password: "helloearth" # redis password + db: 10 # Redis db_num # default data source name defaultDataSourceName: "default" -# file: log file name -# level: /trace/debug/info/warn/error/fatal, default: debug -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation +# log logger: - file: "C:/var/log/omc_restagent.log" - level: warn - duration: 24 - count: 90 + fileDir: "/var/log" # Log File Dir + fileName: "omc.log" # Log File Name + level: 0 # Log Level of 0:silent<1:info<2:warn<3:error + maxDay: 7 # Log retention Days + maxSize: 10 # Log File cutting by size # prometheus metrics metrics: true @@ -98,125 +90,22 @@ staticFile: prefix: "/upload" dir: "C:/usr/local/omc/upload" -# sleep: time delay for after write buffer (millisecond) -# deadLine: timeout for io read and write (second) -mml: - sleep: 200 - deadLine: 10 - sizeRow: 600 - sizeCol: 128 - bufferSize: 65535 - mmlHome: ./mmlhome - -# NE config -ne: - user: omcuser - etcdir: /usr/local/etc - bindir: /usr/local/bin - omcdir: /usr/local/omc - scpdir: /tmp - licensedir: /usr/local/etc/{neType}/license - # backup etc list of IMS, does not contain spaces - etcListIMS: "{*.yaml,mmtel,vars.cfg}" - etcListDefault: "{*.yaml,*.conf,*.cfg}" - # true/false to overwrite config file when dpkg ne software - dpkgOverwrite: false - # dpkg timeout (second) - dpkgTimeout: 180 - -# chk2ne: true/false, if put OmcNeConfig parameters to NE -omc: - uriPrefix: "/omc/rest" - neType: OMC - neId: 001 - rmUID: 4400HX101 - neName: OMC - province: "" - vendor: "" - dn: "" - chk2ne: false - capability: 50 - sn: "12345678" - expiryDate: "2099-12-31" - checksign: false - rootDir: /usr/local/omc - binDir: /usr/local/omc/bin - backup: /usr/local/omc/backup - upload: /usr/local/omc/upload - frontUpload: /usr/local/omc/htdocs/front/upload - frontTraceDir: /usr/local/omc/htdocs/front/trace - software: /usr/local/omc/software - license: /usr/local/omc/license - gtpUri: gtp:192.168.2.119:32152 - checkContentType: false - testMode: false - rbacMode: true - runDir: /usr/local/omc/run - cmdTimeout: 120 - -# Alarm module setting -# Forward interface: -# TLS Skip verify: true/false -# email/sms -# smProxy: sms(Short Message Service)/smsc(SMS Centre) -# dataCoding: 0:GSM7BIT, 1:ASCII, 2:BINARY8BIT1, 3:LATIN1, -# 4:BINARY8BIT2, 6:CYRILLIC, 7:HEBREW, 8:UCS2 -alarm: - alarmEmailForward: - enable: false - emailList: "" - title: "Alarm from OMC" - smtp: mail.smtp.com - port: 25 - user: smtpext@smtp.com - password: "1000smtp@omc!" - tlsSkipVerify: true - alarmSMSForward: - enable: false - mobileList: "" - smscAddr: "192.168.13.114:2775" - systemID: "omc" - password: "omc123" - systemType: "UTRAN" - dataCoding: 0 - serviceNumber: "OMC" - sms: - apiURL: http://smsc.xxx.com/ - accessKeyID: xxxx - accessKeySecret: xxxx - signName: xxx SMSC - templateCode: 1000 - smProxy: smsc - -# User authorized information -# crypt: mysql/md5/bcrypt -# token: true/false to check accessToken -# expires for session, unit: second -# Support single/multiple session of user -# -auth: - crypt: bcrypt - token: true - expires: 1800 - session: multiple - publicKey: /usr/local/omc/etc/certs/omc - privateKey: /usr/local/omc/etc/certs/omc - -# Parameter for limit number -# rmuid_maxnum: the max number of rmUID, default: 50 -# alarmid_maxnum: the max number of AlarmID, default: 50 -# pmid_maxnum: the max number of pmID, default: 50 -# subid_maxnum: the max number of subscription ID, default: 20 -# uri_maxlen: the max length of uri, default: 8192 -# rmuid_regexp: regexp pattern of rmUID -params: - rmuidmaxnum: 50 - alarmidmaxnum: 50 - pmidmaxnum: 50 - subidmaxnum: 20 - urimaxlen: 2100000 - rmuidregexp: "[0-9]{4}[A-Z]{2}[A-Z]{2}[0-9A-Z]{1}[0-9A-Z]{3}[0-9A-Z]{1,16}" - -testConfig: - enabled: false - file: /usr/local/omc/etc/testconfig.yaml +# notification only alarm use +notification: + email: + enable: false # email enable + list: "" # toEmail,email,email + title: "Alarm from OMC" # email title + smtp: "mail.smtp.com" # email smtp + port: 25 # email port + user: "smtpext@smtp.com" # email user + password: "1000smtp@omc!" # email password + smsc: + enable: false # smsc enable + list: "" # toMobile,mobile,mobile + addr: "192.168.13.114:2775" # smsc addr + systemid: "omc" # smsc system id + systemtype: "UTRAN" # smsc system type + password: "omc123" # smsc password + coding: 0 # smsc codingMap 0:GSM7BIT, 1:ASCII, 2:BINARY8BIT1, 3:LATIN1, 4:BINARY8BIT2, 6:CYRILLIC, 7:HEBREW, 8:UCS2 + servicenumber: "OMC" # smsc service number diff --git a/src/config/config.default.yaml b/src/config/config.default.yaml index c98c4678..41ef001b 100644 --- a/src/config/config.default.yaml +++ b/src/config/config.default.yaml @@ -7,6 +7,29 @@ serverLoginAuth: true # 接口加密,默认关闭 serverCryptoApi: false +# 路由服务配置 +# 服务监听 ipv4/v6 端口,支持多路由 +routeServer: + - addr: "0.0.0.0:33030" # 路由 http 端口 + schema: "http" + - addr: "0.0.0.0:33443" # 路由 https 端口 + schema: "https" + certFile: "/usr/local/etc/omc/certs/www.omc.net.crt" + keyFile: "/usr/local/etc/omc/certs/www.omc.net.key" + +# Web 服务配置 +# 如果使用 nginx 接管,可以禁用 +webServer: + enabled: true # Web 服务启用,默认 false + rootDir: /usr/local/etc/omc/web + listen: + - addr: "0.0.0.0:80" # Web http 端口 + schema: "http" + - addr: "0.0.0.0:443" # Web https 端口 + schema: "https" + certFile: "/usr/local/etc/omc/certs/www.omc.net.crt" + keyFile: "/usr/local/etc/omc/certs/www.omc.net.key" + # 日志 logger: fileDir: "/var/log" @@ -158,7 +181,7 @@ database: # 内置轻量级数据库 lite: type: "sqlite" - database: "" + database: "" logging: false # 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: "std" diff --git a/src/config/config.local.yaml b/src/config/config.local.yaml index 250cdc6f..19e30744 100644 --- a/src/config/config.local.yaml +++ b/src/config/config.local.yaml @@ -1,49 +1,45 @@ -# 日志 +# log logger: - fileDir: "/var/log" - fileName: "omc.log" - level: 0 # 日志记录的等级 0:silent<1:info<2:warn<3:error - maxDay: 7 # 日志会保留 180 天 - maxSize: 10 # 调整按 10MB 大小的切割 + fileDir: "/var/log" # Log File Dir + fileName: "omc.log" # Log File Name + level: 0 # Log Level of 0:silent<1:info<2:warn<3:error + maxDay: 7 # Log retention Days + maxSize: 10 # Log File cutting by size -# 静态文件配置, 相对项目根路径或填绝对路径 +# static file resource access staticFile: - # 默认资源,dir目录需要预先创建 default: - prefix: "/static" - dir: "/usr/local/omc/static" - # 文件上传资源目录映射,与项目目录同级 + prefix: "/static" # Static File Prefix + dir: "/usr/local/omc/static" # Static File Dir upload: - prefix: "/upload" - dir: "/usr/local/omc/upload" + prefix: "/upload" # Upload File Prefix + dir: "/usr/local/omc/upload" # Upload File Dir -# DB 数据源 +# data source database: dataSource: - # 默认数据库实例 + # std: standard std: type: "mysql" - host: "127.0.0.1" - port: 33066 - username: "root" - password: "1000omc@kp!" - database: "omc_db" - logging: true - # 内置轻量级数据库 + host: "127.0.0.1" # mysql host + port: 33066 # mysql port + username: "root" # mysql username + password: "1000omc@kp!" # mysql password + database: "omc_db" # mysql database + # lite: lite lite: type: "sqlite" - database: "/usr/local/etc/omc/database/omc_db.sqlite" - logging: true - # 多个数据源时可以用这个指定默认的数据源 + database: "/usr/local/etc/omc/database/omc_db.sqlite" # sqlite database + # default data source name defaultDataSourceName: "std" -# Redis 缓存数据 +# redis cached data redis: dataSource: default: - port: 6379 # Redis port - host: "127.0.0.1" # Redis host - password: "helloearth" + port: 6379 # redis port + host: "127.0.0.1" # redis host + password: "helloearth" # redis password db: 10 # Redis db_num - # 多个数据源时可以用这个指定默认的数据源 + # default data source name defaultDataSourceName: "default" diff --git a/src/config/config.prod.yaml b/src/config/config.prod.yaml index bdf5cfd6..6e380cbf 100644 --- a/src/config/config.prod.yaml +++ b/src/config/config.prod.yaml @@ -1,30 +1,28 @@ -# DB 数据源 +# data source database: dataSource: - # 默认数据库实例 + # std: standard std: type: "mysql" - host: "127.0.0.1" - port: 33066 - username: "root" - password: "1000omc@kp!" - database: "omc_db" - logging: false - # 内置轻量级数据库 + host: "127.0.0.1" # mysql host + port: 33066 # mysql port + username: "root" # mysql username + password: "1000omc@kp!" # mysql password + database: "omc_db" # mysql database + # lite: lite lite: type: "sqlite" - database: "/usr/local/etc/omc/database/omc_db.sqlite" - logging: false - # 多个数据源时可以用这个指定默认的数据源 + database: "/usr/local/etc/omc/database/omc_db.sqlite" # sqlite database + # default data source name defaultDataSourceName: "std" -# Redis 缓存数据 +# redis cached data redis: dataSource: default: - port: 6379 # Redis port - host: "127.0.0.1" # Redis host - password: "helloearth" + port: 6379 # redis port + host: "127.0.0.1" # redis host + password: "helloearth" # redis password db: 10 # Redis db_num - # 多个数据源时可以用这个指定默认的数据源 + # default data source name defaultDataSourceName: "default" diff --git a/src/framework/config/config.go b/src/framework/config/config.go index 764333d4..c4e8fc0f 100644 --- a/src/framework/config/config.go +++ b/src/framework/config/config.go @@ -10,8 +10,6 @@ import ( "github.com/spf13/pflag" "github.com/spf13/viper" - - libConfig "be.ems/lib/config" ) var ( @@ -21,11 +19,10 @@ var ( ) // 程序配置 -var conf *viper.Viper +var conf *viper.Viper = viper.New() // 初始化程序配置 func InitConfig(configDir *embed.FS) { - conf = viper.New() initFlag() initViper(configDir) } @@ -97,16 +94,14 @@ func initViper(configDir *embed.FS) { // 外部文件配置 externalConfig := conf.GetString("config") if externalConfig != "" { - // readExternalConfig(externalConfig) - // 处理旧配置,存在相同的配置项处理 - configInMerge(externalConfig) + readExternalConfig(externalConfig) } // 记录程序开始运行的时间点 conf.Set("runTime", time.Now()) } -// readExternalConfig 读取外部文件配置(放弃旧的配置序列化时候才用) +// readExternalConfig 读取外部文件配置 func readExternalConfig(configPaht string) { f, err := os.Open(configPaht) if err != nil { @@ -121,38 +116,6 @@ func readExternalConfig(configPaht string) { } } -// 配置文件读取进行内部参数合并 -func configInMerge(configFile string) { - // 指定配置文件读取序列化 - libConfig.ReadConfig(configFile) - uriPrefix := libConfig.GetYamlConfig().OMC.UriPrefix - if uriPrefix != "" { - libConfig.UriPrefix = uriPrefix - } - if libConfig.GetYamlConfig().TestConfig.Enabled { - libConfig.ReadTestConfigYaml(libConfig.GetYamlConfig().TestConfig.File) - } - - // 配置文件读取 - var v = viper.New() - // 设置配置文件路径 - v.SetConfigFile(configFile) - v.SetConfigType("yaml") - // 读取配置文件 - if err := v.ReadInConfig(); err != nil { - fmt.Printf("failure to read configuration file: %v \n", err) - return - } - // 合并外层lib和features使用配置 - for key, value := range v.AllSettings() { - // 跳过配置 - if key == "testconfig" || key == "logger" { - continue - } - conf.Set(key, value) - } -} - // Env 获取运行服务环境 // local prod func Env() string { From adb0d5f4e28f9ff01314b597301d6bebd06732c4 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:51:16 +0800 Subject: [PATCH 11/80] =?UTF-8?q?perf:=20=E9=87=8D=E6=9E=84=E6=8E=A5?= =?UTF-8?q?=E6=94=B6CDR=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backup_export_cdr/backup_export_cdr.go | 99 ++- src/modules/network_data/controller/ims.go | 57 +- src/modules/network_data/controller/sgwc.go | 55 +- src/modules/network_data/controller/smf.go | 61 +- src/modules/network_data/controller/smsc.go | 57 +- src/modules/network_data/model/cdr_event.go | 17 + .../network_data/model/cdr_event_ims.go | 33 - .../network_data/model/cdr_event_sgwc.go | 32 - .../network_data/model/cdr_event_smf.go | 33 - .../network_data/model/cdr_event_smsc.go | 33 - .../network_data/repository/cdr_event.go | 167 +++++ .../network_data/repository/cdr_event_ims.go | 107 --- .../network_data/repository/cdr_event_sgwc.go | 95 --- .../network_data/repository/cdr_event_smf.go | 98 --- .../network_data/repository/cdr_event_smsc.go | 107 --- src/modules/network_data/service/cdr_event.go | 645 ++++++++++++++++++ .../network_data/service/cdr_event_ims.go | 173 ----- .../network_data/service/cdr_event_sgwc.go | 235 ------- .../network_data/service/cdr_event_smf.go | 230 ------- .../network_data/service/cdr_event_smsc.go | 137 ---- src/modules/oam/service/cdr.go | 73 ++ src/modules/ws/processor/cdr_connect.go | 78 +-- 22 files changed, 1059 insertions(+), 1563 deletions(-) create mode 100644 src/modules/network_data/model/cdr_event.go delete mode 100644 src/modules/network_data/model/cdr_event_ims.go delete mode 100644 src/modules/network_data/model/cdr_event_sgwc.go delete mode 100644 src/modules/network_data/model/cdr_event_smf.go delete mode 100644 src/modules/network_data/model/cdr_event_smsc.go create mode 100644 src/modules/network_data/repository/cdr_event.go delete mode 100644 src/modules/network_data/repository/cdr_event_ims.go delete mode 100644 src/modules/network_data/repository/cdr_event_sgwc.go delete mode 100644 src/modules/network_data/repository/cdr_event_smf.go delete mode 100644 src/modules/network_data/repository/cdr_event_smsc.go create mode 100644 src/modules/network_data/service/cdr_event.go delete mode 100644 src/modules/network_data/service/cdr_event_ims.go delete mode 100644 src/modules/network_data/service/cdr_event_sgwc.go delete mode 100644 src/modules/network_data/service/cdr_event_smf.go delete mode 100644 src/modules/network_data/service/cdr_event_smsc.go create mode 100644 src/modules/oam/service/cdr.go diff --git a/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go b/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go index c04b6781..755e1d6f 100644 --- a/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go +++ b/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go @@ -15,7 +15,6 @@ import ( "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" - neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neModel "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" @@ -23,26 +22,20 @@ import ( ) var NewProcessor = &BackupExportCDRProcessor{ - count: 0, - backupService: neDataService.NewBackup, - sysDictService: systemService.NewSysDictData, - neInfoService: neService.NewNeInfo, - imsCDREventService: neDataService.NewCDREventIMS, - smscCDREventService: neDataService.NewCDREventSMSC, - smfCDREventService: neDataService.NewCDREventSMF, - sgwcCDREventService: neDataService.NewCDREventSGWC, + count: 0, + backupService: neDataService.NewBackup, + sysDictService: systemService.NewSysDictData, + neInfoService: neService.NewNeInfo, + cdrEventService: neDataService.NewCDREvent, } // BackupExportCDR 队列任务处理 type BackupExportCDRProcessor struct { - count int // 执行次数 - backupService *neDataService.Backup // 备份相关服务 - sysDictService *systemService.SysDictData // 字典类型数据服务 - neInfoService *neService.NeInfo // 网元信息服务 - imsCDREventService *neDataService.CDREventIMS // IMS-CDR会话事件服务 - smscCDREventService *neDataService.CDREventSMSC // SMSC-CDR会话事件服务 - smfCDREventService *neDataService.CDREventSMF // SMF-CDR会话事件服务 - sgwcCDREventService *neDataService.CDREventSGWC // SGWC-CDR会话事件服务 + count int // 执行次数 + backupService *neDataService.Backup // 备份相关服务 + sysDictService *systemService.SysDictData // 字典类型数据服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 } func (s *BackupExportCDRProcessor) Execute(data any) (any, error) { @@ -104,16 +97,16 @@ func (s BackupExportCDRProcessor) exportIMS(hour int, rmUID, fileType string) st start := end.Add(-time.Duration(hour) * time.Hour) language := "en" - query := neDataModel.CDREventIMSQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + query := map[string]string{ + "sortField": "timestamp", + "sortOrder": "asc", + "rmUID": rmUID, + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + "pageNum": fmt.Sprint(1), + "pageSize": fmt.Sprint(30000), } - rows, total := s.imsCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("IMS", query) if total == 0 { return "no data" } @@ -393,16 +386,16 @@ func (s BackupExportCDRProcessor) exportSMSC(hour int, rmUID, fileType string) s start := end.Add(-time.Duration(hour) * time.Hour) language := "en" - query := neDataModel.CDREventSMSCQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + query := map[string]string{ + "sortField": "timestamp", + "sortOrder": "asc", + "rmUID": rmUID, + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + "pageNum": fmt.Sprint(1), + "pageSize": fmt.Sprint(30000), } - rows, total := s.smscCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("SMSC", query) if total == 0 { return "no data" } @@ -609,16 +602,16 @@ func (s BackupExportCDRProcessor) exportSMF(hour int, rmUID, fileType string) st end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) start := end.Add(-time.Duration(hour) * time.Hour) - query := neDataModel.CDREventSMFQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + query := map[string]string{ + "sortField": "timestamp", + "sortOrder": "asc", + "rmUID": rmUID, + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + "pageNum": fmt.Sprint(1), + "pageSize": fmt.Sprint(30000), } - rows, total := s.smfCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("SMF", query) if total == 0 { return "no data" } @@ -1017,16 +1010,16 @@ func (s BackupExportCDRProcessor) exportSGWC(hour int, rmUID, fileType string) s end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) start := end.Add(-time.Duration(hour) * time.Hour) - query := neDataModel.CDREventSGWCQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + query := map[string]string{ + "sortField": "timestamp", + "sortOrder": "asc", + "rmUID": rmUID, + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + "pageNum": fmt.Sprint(1), + "pageSize": fmt.Sprint(30000), } - rows, total := s.sgwcCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("SGWC", query) if total == 0 { return "no data" } diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index 08861dd2..c4ca4431 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" @@ -19,15 +18,15 @@ import ( // 实例化控制层 IMSController 结构体 var NewIMS = &IMSController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventIMS, + cdrEventService: neDataService.NewCDREvent, } // 网元IMS // // PATH /ims type IMSController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventIMS // CDR会话事件服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 } // CDR会话列表 @@ -50,23 +49,20 @@ type IMSController struct { // @Router /neData/ims/cdr/list [get] func (s *IMSController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventIMSQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -99,7 +95,7 @@ func (s *IMSController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("IMS", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -110,7 +106,7 @@ func (s *IMSController) CDRRemove(c *gin.Context) { // CDR会话列表导出 // -// POST /cdr/export +// GET /cdr/export // // @Tags network_data/ims // @Accept json @@ -120,28 +116,23 @@ func (s *IMSController) CDRRemove(c *gin.Context) { // @Security TokenAuth // @Summary CDR Session List Export // @Description CDR Session List Export -// @Router /neData/ims/cdr/export [post] +// @Router /neData/ims/cdr/export [get] func (s *IMSController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventIMSQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -151,7 +142,7 @@ func (s *IMSController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language) + saveFilePath, err := s.cdrEventService.ExportIMS(rows, fileName, language) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/controller/sgwc.go b/src/modules/network_data/controller/sgwc.go index 8c72f621..ea7589ec 100644 --- a/src/modules/network_data/controller/sgwc.go +++ b/src/modules/network_data/controller/sgwc.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "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" @@ -17,7 +16,7 @@ import ( // 实例化控制层 SGWCController 结构体 var NewSGWC = &SGWCController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventSGWC, + cdrEventService: neDataService.NewCDREvent, UDMExtendService: neDataService.NewUDMExtend, } @@ -25,9 +24,9 @@ var NewSGWC = &SGWCController{ // // PATH /sgwc type SGWCController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventSGWC // CDR会话事件服务 - UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 + UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 } // CDR会话列表 @@ -50,23 +49,20 @@ type SGWCController struct { // @Router /neData/sgwc/cdr/list [get] func (s *SGWCController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventSGWCQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -99,7 +95,7 @@ func (s *SGWCController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("SGWC", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -123,25 +119,20 @@ func (s *SGWCController) CDRRemove(c *gin.Context) { // @Router /neData/sgwc/cdr/export [post] func (s *SGWCController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventSGWCQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -151,7 +142,7 @@ func (s *SGWCController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName) + saveFilePath, err := s.cdrEventService.ExportSGWC(rows, fileName) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index 9e382bff..e1e77d9b 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -9,7 +9,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" @@ -20,7 +19,7 @@ import ( // 实例化控制层 SMFController 结构体 var NewSMF = &SMFController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventSMF, + cdrEventService: neDataService.NewCDREvent, UDMExtendService: neDataService.NewUDMExtend, } @@ -28,9 +27,9 @@ var NewSMF = &SMFController{ // // PATH /smf type SMFController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventSMF // CDR会话事件服务 - UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 + UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 } // CDR会话列表 @@ -52,23 +51,20 @@ type SMFController struct { // @Router /neData/smf/cdr/list [get] func (s *SMFController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventSMFQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -101,7 +97,7 @@ func (s *SMFController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("SMF", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -112,7 +108,7 @@ func (s *SMFController) CDRRemove(c *gin.Context) { // CDR会话列表导出 // -// POST /cdr/export +// GET /cdr/export // // @Tags network_data/smf // @Accept json @@ -122,28 +118,23 @@ func (s *SMFController) CDRRemove(c *gin.Context) { // @Security TokenAuth // @Summary CDR Session List Export // @Description CDR Session List Export -// @Router /neData/smf/cdr/export [post] +// @Router /neData/smf/cdr/export [get] func (s *SMFController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventSMFQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -153,7 +144,7 @@ func (s *SMFController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName) + saveFilePath, err := s.cdrEventService.ExportSMF(rows, fileName) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return @@ -219,7 +210,7 @@ func (s *SMFController) SubUserNum(c *gin.Context) { // @Security TokenAuth // @Summary Online session user list information // @Description Online session user list information -// @Router /neData/smf/session/list [get] +// @Router /neData/smf/sub/list [get] func (s *SMFController) SubUserList(c *gin.Context) { language := reqctx.AcceptLanguage(c) var query struct { diff --git a/src/modules/network_data/controller/smsc.go b/src/modules/network_data/controller/smsc.go index fc9420e0..f3efc33e 100644 --- a/src/modules/network_data/controller/smsc.go +++ b/src/modules/network_data/controller/smsc.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" @@ -18,15 +17,15 @@ import ( // 实例化控制层 SMSCController 结构体 var NewSMSC = &SMSCController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventSMSC, + cdrEventService: neDataService.NewCDREvent, } // 网元SMSC // // PATH /smsc type SMSCController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventSMSC // CDR会话事件服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 } // CDR会话列表 @@ -49,23 +48,20 @@ type SMSCController struct { // @Router /neData/smsc/cdr/list [get] func (s *SMSCController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventSMSCQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -98,7 +94,7 @@ func (s *SMSCController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("SMSC", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -109,7 +105,7 @@ func (s *SMSCController) CDRRemove(c *gin.Context) { // CDR会话列表导出 // -// POST /cdr/export +// GET /cdr/export // // @Tags network_data/smsc // @Accept json @@ -119,28 +115,23 @@ func (s *SMSCController) CDRRemove(c *gin.Context) { // @Security TokenAuth // @Summary CDR Session List Export // @Description CDR Session List Export -// @Router /neData/smsc/cdr/export [post] +// @Router /neData/smsc/cdr/export [get] func (s *SMSCController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventSMSCQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -150,7 +141,7 @@ func (s *SMSCController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language) + saveFilePath, err := s.cdrEventService.ExportSMSC(rows, fileName, language) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/model/cdr_event.go b/src/modules/network_data/model/cdr_event.go new file mode 100644 index 00000000..8b713d13 --- /dev/null +++ b/src/modules/network_data/model/cdr_event.go @@ -0,0 +1,17 @@ +package model + +// CDREvent CDR会话对象 cdr_event +type CDREvent struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeName string `json:"neName" gorm:"column:ne_name"` + RmUid string `json:"rmUid" gorm:"column:rm_uid"` // 可能没有 + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 + CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String + CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 +} + +// TableName 表名称 +func (*CDREvent) TableName() string { + return "cdr_event" +} diff --git a/src/modules/network_data/model/cdr_event_ims.go b/src/modules/network_data/model/cdr_event_ims.go deleted file mode 100644 index 8c383ad2..00000000 --- a/src/modules/network_data/model/cdr_event_ims.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// CDREventIMS CDR会话对象IMS cdr_event_ims -type CDREventIMS struct { - ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUid string `json:"rmUid" gorm:"column:rm_uid"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventIMS) TableName() string { - return "cdr_event_ims" -} - -// CDREventIMSQuery CDR会话对象IMS查询参数结构体 -type CDREventIMSQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=IMS"` // 网元类型IMS - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC - CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码 - CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码 - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_sgwc.go b/src/modules/network_data/model/cdr_event_sgwc.go deleted file mode 100644 index 26562065..00000000 --- a/src/modules/network_data/model/cdr_event_sgwc.go +++ /dev/null @@ -1,32 +0,0 @@ -package model - -// CDREventSGWC CDR会话对象SGWC cdr_event_sgwc -type CDREventSGWC struct { - ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUid string `json:"rmUid" gorm:"column:rm_uid"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventSGWC) TableName() string { - return "cdr_event_sgwc" -} - -// CDREventSGWCQuery CDR会话对象SGWC查询参数结构体 -type CDREventSGWCQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=SGWC"` // SGWC - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - IMSI string `json:"imsi" form:"imsi"` - MSISDN string `json:"msisdn" form:"msisdn"` - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_smf.go b/src/modules/network_data/model/cdr_event_smf.go deleted file mode 100644 index a6df3ced..00000000 --- a/src/modules/network_data/model/cdr_event_smf.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// CDREventSMF CDR会话对象SMF cdr_event_smf -type CDREventSMF struct { - ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUid string `json:"rmUid" gorm:"column:rm_uid"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventSMF) TableName() string { - return "cdr_event_smf" -} - -// CDREventSMFQuery CDR会话对象SMF查询参数结构体 -type CDREventSMFQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=SMF"` // 网元类型, 暂时支持SMF - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 暂时没用到 - SubscriberID string `json:"subscriberID" form:"subscriberID"` - DNN string `json:"dnn" form:"dnn"` - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_smsc.go b/src/modules/network_data/model/cdr_event_smsc.go deleted file mode 100644 index 753e694a..00000000 --- a/src/modules/network_data/model/cdr_event_smsc.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// CDREventSMSC CDR会话对象SMSC cdr_event_smsc -type CDREventSMSC struct { - ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUid string `json:"rmUid" gorm:"column:rm_uid"` // 可能没有 - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventSMSC) TableName() string { - return "cdr_event_smsc" -} - -// CDREventSMSCQuery CDR会话对象SMSC查询参数结构体 -type CDREventSMSCQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=SMSC"` // 网元类型, 暂时支持SMSC - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOSM MTSM - CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码 - CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码 - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/repository/cdr_event.go b/src/modules/network_data/repository/cdr_event.go new file mode 100644 index 00000000..4ce8532e --- /dev/null +++ b/src/modules/network_data/repository/cdr_event.go @@ -0,0 +1,167 @@ +package repository + +import ( + "fmt" + "strings" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/network_data/model" +) + +// 实例化数据层 CDREvent 结构体 +var NewCDREvent = &CDREvent{} + +// CDREvent CDR会话事件 数据层处理 +type CDREvent struct{} + +// SelectByPage 分页查询集合 +func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model.CDREvent, int64) { + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Model(&model.CDREvent{}) + // 查询条件拼接 + if v, ok := query["rmUID"]; ok && v != "" { + tx = tx.Where("rm_uid = ?", v) + } + if v, ok := query["beginTime"]; ok && v != "" { + if len(v) == 10 { + v = v + "000" + } + tx = tx.Where("timestamp >= ?", v) + } + if v, ok := query["endTime"]; ok && v != "" { + if len(v) == 10 { + v = v + "000" + } + tx = tx.Where("timestamp <= ?", v) + } + + // 各个网元特殊查询条件 + switch neType { + case "SMSC": + if v, ok := query["callerParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", v) + } + if v, ok := query["calledParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", v) + } + if v, ok := query["recordType"]; ok && v != "" { + recordTypes := strings.Split(v, ",") + var querytrArr []string + for _, recordType := range recordTypes { + querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) + } + tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR "))) + } + case "SMF": + if v, ok := query["recordType"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", v) + } + if v, ok := query["subscriberID"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?", v) + } + if v, ok := query["dnn"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", v) + } + case "SGWC": + if v, ok := query["imsi"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') = ?", v) + } + if v, ok := query["msisdn"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') = ?", v) + } + case "IMS": + if v, ok := query["callerParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", v) + } + if v, ok := query["calledParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", v) + } + } + + var total int64 = 0 + rows := []model.CDREvent{} + + // 查询数量 长度为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize)) + + // 排序 + if v, ok := query["sortField"]; ok && v != "" { + sortSql := v + if o, ok := query["sortOrder"]; ok && o != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + tx = tx.Order(sortSql) + } + + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query err => %v", err) + } + + return rows, total +} + +// SelectByIds 通过ID查询 +func (r CDREvent) SelectByIds(neType string, ids []int64) []model.CDREvent { + rows := []model.CDREvent{} + if len(ids) <= 0 { + return rows + } + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Model(&model.CDREvent{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// DeleteByIds 批量删除信息 +func (r CDREvent) DeleteByIds(neType string, ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Where("id in ?", ids) + if err := tx.Delete(&model.CDREvent{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// Insert 新增信息 返回新增数据ID +func (r CDREvent) Insert(param model.CDREvent) int64 { + if param.NeType == "" { + return 0 + } + if param.CreatedAt == 0 { + param.CreatedAt = time.Now().UnixMilli() + } + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(param.NeType)) + // 执行插入 + if err := db.DB("").Table(tableName).Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.ID +} diff --git a/src/modules/network_data/repository/cdr_event_ims.go b/src/modules/network_data/repository/cdr_event_ims.go deleted file mode 100644 index 814bd83d..00000000 --- a/src/modules/network_data/repository/cdr_event_ims.go +++ /dev/null @@ -1,107 +0,0 @@ -package repository - -import ( - "fmt" - "strings" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventIMS 结构体 -var NewCDREventIMS = &CDREventIMS{} - -// CDREventIMS CDR会话事件 数据层处理 -type CDREventIMS struct{} - -// SelectByPage 分页查询集合 -func (r CDREventIMS) SelectByPage(query model.CDREventIMSQuery) ([]model.CDREventIMS, int64) { - tx := db.DB("").Model(&model.CDREventIMS{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("created_at >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("created_at <= ?", query.EndTime) - } - if query.CallerParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", query.CallerParty) - } - if query.CalledParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", query.CalledParty) - } - - if query.RecordType != "" { - recordTypes := strings.Split(query.RecordType, ",") - var querytrArr []string - for _, recordType := range recordTypes { - querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) - } - tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR "))) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventIMS{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventIMS) SelectByIds(ids []int64) []model.CDREventIMS { - rows := []model.CDREventIMS{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventIMS{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventIMS) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventIMS{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/cdr_event_sgwc.go b/src/modules/network_data/repository/cdr_event_sgwc.go deleted file mode 100644 index 6410120f..00000000 --- a/src/modules/network_data/repository/cdr_event_sgwc.go +++ /dev/null @@ -1,95 +0,0 @@ -package repository - -import ( - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventSGWC 结构体 -var NewCDREventSGWC = &CDREventSGWC{} - -// CDREventSGWC CDR会话事件 数据层处理 -type CDREventSGWC struct{} - -// SelectByPage 分页查询集合 -func (r CDREventSGWC) SelectByPage(query model.CDREventSGWCQuery) ([]model.CDREventSGWC, int64) { - tx := db.DB("").Model(&model.CDREventSGWC{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.IMSI != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') = ?", query.IMSI) - } - if query.MSISDN != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') = ?", query.MSISDN) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventSGWC{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventSGWC) SelectByIds(ids []int64) []model.CDREventSGWC { - rows := []model.CDREventSGWC{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventSGWC{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSGWC) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventSGWC{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/cdr_event_smf.go b/src/modules/network_data/repository/cdr_event_smf.go deleted file mode 100644 index 6892e19d..00000000 --- a/src/modules/network_data/repository/cdr_event_smf.go +++ /dev/null @@ -1,98 +0,0 @@ -package repository - -import ( - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventSMF 结构体 -var NewCDREventSMF = &CDREventSMF{} - -// CDREventSMF CDR会话事件 数据层处理 -type CDREventSMF struct{} - -// SelectByPage 分页查询集合 -func (r CDREventSMF) SelectByPage(query model.CDREventSMFQuery) ([]model.CDREventSMF, int64) { - tx := db.DB("").Model(&model.CDREventSMF{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.RecordType != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", query.RecordType) - } - if query.SubscriberID != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?", query.SubscriberID) - } - if query.DNN != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", query.DNN) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventSMF{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventSMF) SelectByIds(ids []int64) []model.CDREventSMF { - rows := []model.CDREventSMF{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventSMF{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMF) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventSMF{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/cdr_event_smsc.go b/src/modules/network_data/repository/cdr_event_smsc.go deleted file mode 100644 index 928e5063..00000000 --- a/src/modules/network_data/repository/cdr_event_smsc.go +++ /dev/null @@ -1,107 +0,0 @@ -package repository - -import ( - "fmt" - "strings" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventSMSC 结构体 -var NewCDREventSMSC = &CDREventSMSC{} - -// CDREventSMSC CDR会话事件 数据层处理 -type CDREventSMSC struct{} - -// SelectByPage 分页查询集合 -func (r CDREventSMSC) SelectByPage(query model.CDREventSMSCQuery) ([]model.CDREventSMSC, int64) { - tx := db.DB("").Model(&model.CDREventSMSC{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.CallerParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", query.CallerParty) - } - if query.CalledParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", query.CalledParty) - } - - if query.RecordType != "" { - recordTypes := strings.Split(query.RecordType, ",") - var querytrArr []string - for _, recordType := range recordTypes { - querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) - } - tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR "))) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventSMSC{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventSMSC) SelectByIds(ids []int64) []model.CDREventSMSC { - rows := []model.CDREventSMSC{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventSMSC{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMSC) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventSMSC{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/service/cdr_event.go b/src/modules/network_data/service/cdr_event.go new file mode 100644 index 00000000..952e0ebf --- /dev/null +++ b/src/modules/network_data/service/cdr_event.go @@ -0,0 +1,645 @@ +package service + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/file" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" + sysService "be.ems/src/modules/system/service" +) + +// 实例化数据层 CDREvent 结构体 +var NewCDREvent = &CDREvent{ + cdrEventRepository: repository.NewCDREvent, +} + +// CDREvent CDR会话事件 服务层处理 +type CDREvent struct { + cdrEventRepository *repository.CDREvent // CDR会话事件数据信息 +} + +// FindByPage 根据条件分页查询 +func (r CDREvent) FindByPage(neType string, query map[string]string) ([]model.CDREvent, int64) { + return r.cdrEventRepository.SelectByPage(neType, query) +} + +// DeleteByIds 批量删除信息 +func (r CDREvent) DeleteByIds(neType string, ids []int64) (int64, error) { + // 检查是否存在 + rows := r.cdrEventRepository.SelectByIds(neType, ids) + if len(rows) <= 0 { + return 0, fmt.Errorf("not data") + } + + if len(rows) == len(ids) { + rows := r.cdrEventRepository.DeleteByIds(neType, ids) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} + +// Insert 新增信息 +func (s CDREvent) Insert(param model.CDREvent) int64 { + return s.cdrEventRepository.Insert(param) +} + +// ExportSMSC 导出数据到 xlsx 文件 +func (r CDREvent) ExportSMSC(rows []model.CDREvent, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Service Type", + "E1": "Caller", + "F1": "Called", + "G1": "Result", + "H1": "Time", + } + // 读取字典数据 CDR 原因码 + dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 服务类型 + serviceType := "" + if v, ok := cdrJSON["serviceType"]; ok && v != nil { + serviceType = v.(string) + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 呼叫结果 0失败,1成功 + callResult := "Fail" + if v, ok := cdrJSON["result"]; ok && v != nil { + resultVal := parse.Number(v) + if resultVal == 1 { + callResult = "Success" + } + } + // 结果原因 + if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" { + cause := fmt.Sprint(v) + for _, v := range dictCDRCauseCode { + if cause == v.DataValue { + callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel)) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["updateTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + timeStr = v.(string) + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: serviceType, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: callResult, + "H" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportSMF 导出数据到 xlsx 文件 +func (r CDREvent) ExportSMF(rows []model.CDREvent, fileName string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Charging ID", + "C1": "NE Name", + "D1": "Resource Unique ID", + "E1": "Subscriber ID Data", + "F1": "Subscriber ID Type", + "G1": "Data Volume Uplink", + "H1": "Data Volume Downlink", + "I1": "Data Total Volume", + "J1": "Duration", + "K1": "Invocation Time", + "L1": "User Identifier", + "M1": "SSC Mode", + "N1": "DNN ID", + "O1": "PDU Type", + "P1": "RAT Type", + "Q1": "PDU IPv4 Address", + "R1": "Network Function IPv4", + "S1": "PDU IPv6 Address Swith Prefix", + "T1": "Record Network Function ID", + "U1": "Record Type", + "V1": "Record Opening Time", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // 订阅 ID 类型 + subscriptionIDType := "-" + // 订阅 ID 数据 + subscriptionIDData := "-" + if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { + if sub, subOk := v.(map[string]any); subOk && sub != nil { + subscriptionIDType = sub["subscriptionIDType"].(string) + subscriptionIDData = sub["subscriptionIDData"].(string) + } + } + + // 网络功能 IPv4 地址 + networkFunctionIPv4Address := "" + if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil { + if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil { + networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string) + } + } + + // 数据量上行链路 + var dataVolumeUplink int64 = 0 + // 数据量下行链路 + var dataVolumeDownlink int64 = 0 + // 数据总量 + var dataTotalVolume int64 = 0 + if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + usedUnitList := usedUnit["usedUnitContainer"].([]any) + if len(usedUnitList) > 0 { + for _, data := range usedUnitList { + udata := data.(map[string]any) + if dup, dupOk := udata["dataVolumeUplink"]; dupOk { + dataVolumeUplink += parse.Number(dup) + } + if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { + dataVolumeDownlink += parse.Number(ddown) + } + if dt, dtOk := udata["dataTotalVolume"]; dtOk { + dataTotalVolume += parse.Number(dt) + } + } + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { + invocationTimestamp = v.(string) + } + // 记录打开时间 + User_Identifier := "" + SSC_Mode := "" + RAT_Type := "" + DNN_ID := "" + PDU_Type := "" + PDU_IPv4 := "" + PDU_IPv6 := "" + if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { + pduInfo := v.(map[string]any) + + if v, ok := pduInfo["userIdentifier"]; ok && v != nil { + User_Identifier = v.(string) + } + if v, ok := pduInfo["sSCMode"]; ok && v != nil { + SSC_Mode = v.(string) + } + if v, ok := pduInfo["rATType"]; ok && v != nil { + RAT_Type = v.(string) + } + if v, ok := pduInfo["dNNID"]; ok && v != nil { + DNN_ID = v.(string) + } + if v, ok := pduInfo["pDUType"]; ok && v != nil { + PDU_Type = v.(string) + } + if v, ok := pduInfo["pDUAddress"]; ok && v != nil { + pDUAddress := v.(map[string]any) + if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { + PDU_IPv4 = addr.(string) + } + if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { + PDU_IPv6 = addr.(string) + } + } + } + + // 记录网络参数ID + recordNFID := "" + if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil { + recordNFID = v.(string) + } + + //记录开始时间 + recordOpeningTime := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + recordOpeningTime = v.(string) + } + + //记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: chargingID, + "C" + idx: row.NeName, + "D" + idx: row.RmUid, + "E" + idx: subscriptionIDData, + "F" + idx: subscriptionIDType, + "G" + idx: dataVolumeUplink, + "H" + idx: dataVolumeDownlink, + "I" + idx: dataTotalVolume, + "J" + idx: duration, + "K" + idx: invocationTimestamp, + "L" + idx: User_Identifier, + "M" + idx: SSC_Mode, + "N" + idx: DNN_ID, + "O" + idx: PDU_Type, + "P" + idx: RAT_Type, + "Q" + idx: PDU_IPv4, + "R" + idx: networkFunctionIPv4Address, + "S" + idx: PDU_IPv6, + "T" + idx: recordNFID, + "U" + idx: recordType, + "V" + idx: recordOpeningTime, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportSGWC 导出数据到 xlsx 文件 +func (r CDREvent) ExportSGWC(rows []model.CDREvent, fileName string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Resource Unique ID", + "D1": "Charging ID", + "E1": "IMSI", + "F1": "MSISDN", + "G1": "GPRS Uplink", + "H1": "GPRS Downlink", + "I1": "Duration", + "J1": "Invocation Time", + "K1": "PGW Address", + "L1": "SGW Address", + "M1": "RAT Type", + "N1": "PDPPDN Type", + "O1": "PDPPDN Address", + "P1": "Node Address", + "Q1": "Node Type", + "R1": "Record Access Point Name NI", + "S1": "Record Cause For Rec Closing", + "T1": "Record Sequence Number", + "U1": "Local Record Sequence Number", + "V1": "Record Type", + "W1": "Record Opening Time", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // IMSI + servedIMSI := "" + if v, ok := cdrJSON["servedIMSI"]; ok && v != nil { + servedIMSI = fmt.Sprint(v) + } + // MSISDN + servedMSISDN := "" + if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil { + servedMSISDN = fmt.Sprint(v) + } + // pGWAddressUsed + pGWAddressUsed := "" + if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + headerCells["K1"] = "PGW Address" + } + if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + headerCells["K1"] = "GGSN Address" + } + // sGWAddress + sGWAddress := "" + if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + headerCells["L1"] = "SGW Address" + } + if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + headerCells["L1"] = "SGSN Address" + } + // recordType + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = fmt.Sprint(v) + } + // rATType + rATType := "" + if v, ok := cdrJSON["rATType"]; ok && v != nil { + rATType = fmt.Sprint(v) + } + // pdpPDNType + pdpPDNType := "" + if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil { + pdpPDNType = fmt.Sprint(v) + } + // servedPDPPDNAddress + servedPDPPDNAddress := "" + if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil { + servedPDPPDNAddress = fmt.Sprint(v) + } + // servedPDPPDNAddress + servingNodeAddress := []string{} + if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil { + for _, v := range v.([]any) { + servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v)) + } + } + // servingNodeType + servingNodeType := []string{} + if v, ok := cdrJSON["servingNodeType"]; ok && v != nil { + for _, v := range v.([]any) { + if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil { + servingNodeType = append(servingNodeType, fmt.Sprint(v)) + } + } + } + // accessPointNameNI + accessPointNameNI := "" + if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil { + accessPointNameNI = fmt.Sprint(v) + } + // causeForRecClosing + causeForRecClosing := "" + if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil { + causeForRecClosing = fmt.Sprint(v) + } + // recordSequenceNumber + recordSequenceNumber := "" + if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil { + recordSequenceNumber = fmt.Sprint(v) + } + // localRecordSequenceNumber + localRecordSequenceNumber := "" + if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil { + localRecordSequenceNumber = fmt.Sprint(v) + } + // 数据量上行链路 + var dataVolumeGPRSUplink int64 = 0 + // 数据量下行链路 + var dataVolumeGPRSDownlink int64 = 0 + if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk { + dataVolumeGPRSUplink = parse.Number(dup) + } + if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk { + dataVolumeGPRSDownlink = parse.Number(ddown) + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + invocationTimestamp = v.(string) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: row.RmUid, + "D" + idx: chargingID, + "E" + idx: servedIMSI, + "F" + idx: servedMSISDN, + "G" + idx: dataVolumeGPRSUplink, + "H" + idx: dataVolumeGPRSDownlink, + "I" + idx: duration, + "J" + idx: invocationTimestamp, + "K" + idx: pGWAddressUsed, + "L" + idx: sGWAddress, + "M" + idx: rATType, + "N" + idx: pdpPDNType, + "O" + idx: servedPDPPDNAddress, + "P" + idx: strings.Join(servingNodeAddress, ","), + "Q" + idx: strings.Join(servingNodeType, ","), + "R" + idx: accessPointNameNI, + "S" + idx: causeForRecClosing, + "T" + idx: recordSequenceNumber, + "U" + idx: localRecordSequenceNumber, + "V" + idx: recordType, + "W" + idx: invocationTimestamp, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportIMS 导出数据到 xlsx 文件 +func (r CDREvent) ExportIMS(rows []model.CDREvent, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Type", + "E1": "Caller", + "F1": "Called", + "G1": "Duration", + "H1": "Result Code", + "I1": "Result Cause", + "J1": "Call Start Time", + "K1": "Hangup Time", + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code") + // 读取字典数据 CDR SIP响应代码类别类型原因 + dictCDRSipCodeCause := sysService.NewSysDictData.FindByType("cdr_sip_code_cause") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := sysService.NewSysDictData.FindByType("cdr_call_type") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]any + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 呼叫类型 + callType := "sms" + callTypeLable := "SMS" + if v, ok := cdrJSON["callType"]; ok && v != nil { + callType = v.(string) + for _, v := range dictCDRCallType { + if callType == v.DataValue { + callTypeLable = i18n.TKey(language, v.DataLabel) + break + } + } + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 时长 + duration := "-" + if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { + duration = fmt.Sprintf("%ds", parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Other" + callCause := "Call failure for other reason" + if callType == "sms" { + callResult = "Success" + callCause = "Normal Send" + } else { + if v, ok := cdrJSON["cause"]; ok && v != nil { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DataValue { + callResult = i18n.TKey(language, v.DataLabel) + break + } + } + for _, v := range dictCDRSipCodeCause { + if cause == v.DataValue { + callCause = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + // 呼叫时间 + seizureTimeStr := "" + if v, ok := cdrJSON["seizureTime"]; ok && v != nil { + if seizureTime := parse.Number(v); seizureTime > 0 { + seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + seizureTimeStr = v.(string) + } + } + // 挂断时间 + releaseTimeStr := "" + if v, ok := cdrJSON["releaseTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + releaseTimeStr = v.(string) + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: callTypeLable, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: duration, + "H" + idx: callResult, + "I" + idx: callCause, + "J" + idx: seizureTimeStr, + "K" + idx: releaseTimeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} diff --git a/src/modules/network_data/service/cdr_event_ims.go b/src/modules/network_data/service/cdr_event_ims.go deleted file mode 100644 index 30ad78a8..00000000 --- a/src/modules/network_data/service/cdr_event_ims.go +++ /dev/null @@ -1,173 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" - sysService "be.ems/src/modules/system/service" -) - -// 实例化数据层 CDREventIMS 结构体 -var NewCDREventIMS = &CDREventIMS{ - cdrEventIMSRepository: repository.NewCDREventIMS, -} - -// CDREventImpl CDR会话事件IMS 服务层处理 -type CDREventIMS struct { - cdrEventIMSRepository *repository.CDREventIMS // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventIMS) FindByPage(query model.CDREventIMSQuery) ([]model.CDREventIMS, int64) { - return r.cdrEventIMSRepository.SelectByPage(query) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventIMS) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventIMSRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventIMSRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventIMS) ExportXlsx(rows []model.CDREventIMS, fileName, language string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "NE Name", - "C1": "Record Behavior", - "D1": "Type", - "E1": "Caller", - "F1": "Called", - "G1": "Duration", - "H1": "Result Code", - "I1": "Result Cause", - "J1": "Call Start Time", - "K1": "Hangup Time", - } - // 读取字典数据 CDR SIP响应代码类别类型 - dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code") - // 读取字典数据 CDR SIP响应代码类别类型原因 - dictCDRSipCodeCause := sysService.NewSysDictData.FindByType("cdr_sip_code_cause") - // 读取字典数据 CDR 呼叫类型 - dictCDRCallType := sysService.NewSysDictData.FindByType("cdr_call_type") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]any - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 记录类型 - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = v.(string) - } - // 呼叫类型 - callType := "sms" - callTypeLable := "SMS" - if v, ok := cdrJSON["callType"]; ok && v != nil { - callType = v.(string) - for _, v := range dictCDRCallType { - if callType == v.DataValue { - callTypeLable = i18n.TKey(language, v.DataLabel) - break - } - } - } - // 被叫 - called := "" - if v, ok := cdrJSON["calledParty"]; ok && v != nil { - called = v.(string) - } - // 主叫 - caller := "" - if v, ok := cdrJSON["callerParty"]; ok && v != nil { - caller = v.(string) - } - // 时长 - duration := "-" - if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { - duration = fmt.Sprintf("%ds", parse.Number(v)) - } - // 呼叫结果 非短信都有code作为结果 sms短信都ok - callResult := "Other" - callCause := "Call failure for other reason" - if callType == "sms" { - callResult = "Success" - callCause = "Normal Send" - } else { - if v, ok := cdrJSON["cause"]; ok && v != nil { - cause := fmt.Sprint(v) - for _, v := range dictCDRSipCode { - if cause == v.DataValue { - callResult = i18n.TKey(language, v.DataLabel) - break - } - } - for _, v := range dictCDRSipCodeCause { - if cause == v.DataValue { - callCause = i18n.TKey(language, v.DataLabel) - break - } - } - } - } - // 呼叫时间 - seizureTimeStr := "" - if v, ok := cdrJSON["seizureTime"]; ok && v != nil { - if seizureTime := parse.Number(v); seizureTime > 0 { - seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ) - } else { - seizureTimeStr = v.(string) - } - } - // 挂断时间 - releaseTimeStr := "" - if v, ok := cdrJSON["releaseTime"]; ok && v != nil { - if releaseTime := parse.Number(v); releaseTime > 0 { - releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) - } else { - releaseTimeStr = v.(string) - } - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: row.NeName, - "C" + idx: recordType, - "D" + idx: callTypeLable, - "E" + idx: caller, - "F" + idx: called, - "G" + idx: duration, - "H" + idx: callResult, - "I" + idx: callCause, - "J" + idx: seizureTimeStr, - "K" + idx: releaseTimeStr, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/cdr_event_sgwc.go b/src/modules/network_data/service/cdr_event_sgwc.go deleted file mode 100644 index ca6ede41..00000000 --- a/src/modules/network_data/service/cdr_event_sgwc.go +++ /dev/null @@ -1,235 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - "strings" - - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" -) - -// 实例化数据层 CDREventSGWC 结构体 -var NewCDREventSGWC = &CDREventSGWC{ - cdrEventRepository: repository.NewCDREventSGWC, -} - -// CDREventSGWC CDR会话事件SGWC 服务层处理 -type CDREventSGWC struct { - cdrEventRepository *repository.CDREventSGWC // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventSGWC) FindByPage(query model.CDREventSGWCQuery) ([]model.CDREventSGWC, int64) { - return r.cdrEventRepository.SelectByPage(query) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSGWC) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventSGWC) ExportXlsx(rows []model.CDREventSGWC, fileName string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "NE Name", - "C1": "Resource Unique ID", - "D1": "Charging ID", - "E1": "IMSI", - "F1": "MSISDN", - "G1": "GPRS Uplink", - "H1": "GPRS Downlink", - "I1": "Duration", - "J1": "Invocation Time", - "K1": "PGW Address", - "L1": "SGW Address", - "M1": "RAT Type", - "N1": "PDPPDN Type", - "O1": "PDPPDN Address", - "P1": "Node Address", - "Q1": "Node Type", - "R1": "Record Access Point Name NI", - "S1": "Record Cause For Rec Closing", - "T1": "Record Sequence Number", - "U1": "Local Record Sequence Number", - "V1": "Record Type", - "W1": "Record Opening Time", - } - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]interface{} - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 计费ID - chargingID := "" - if v, ok := cdrJSON["chargingID"]; ok && v != nil { - chargingID = fmt.Sprint(parse.Number(v)) - } - // IMSI - servedIMSI := "" - if v, ok := cdrJSON["servedIMSI"]; ok && v != nil { - servedIMSI = fmt.Sprint(v) - } - // MSISDN - servedMSISDN := "" - if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil { - servedMSISDN = fmt.Sprint(v) - } - // pGWAddressUsed - pGWAddressUsed := "" - if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil { - pGWAddressUsed = fmt.Sprint(v) - headerCells["K1"] = "PGW Address" - } - if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil { - pGWAddressUsed = fmt.Sprint(v) - headerCells["K1"] = "GGSN Address" - } - // sGWAddress - sGWAddress := "" - if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { - sGWAddress = fmt.Sprint(v) - headerCells["L1"] = "SGW Address" - } - if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil { - sGWAddress = fmt.Sprint(v) - headerCells["L1"] = "SGSN Address" - } - // recordType - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = fmt.Sprint(v) - } - // rATType - rATType := "" - if v, ok := cdrJSON["rATType"]; ok && v != nil { - rATType = fmt.Sprint(v) - } - // pdpPDNType - pdpPDNType := "" - if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil { - pdpPDNType = fmt.Sprint(v) - } - // servedPDPPDNAddress - servedPDPPDNAddress := "" - if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil { - servedPDPPDNAddress = fmt.Sprint(v) - } - // servedPDPPDNAddress - servingNodeAddress := []string{} - if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil { - for _, v := range v.([]any) { - servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v)) - } - } - // servingNodeType - servingNodeType := []string{} - if v, ok := cdrJSON["servingNodeType"]; ok && v != nil { - for _, v := range v.([]any) { - if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil { - servingNodeType = append(servingNodeType, fmt.Sprint(v)) - } - } - } - // accessPointNameNI - accessPointNameNI := "" - if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil { - accessPointNameNI = fmt.Sprint(v) - } - // causeForRecClosing - causeForRecClosing := "" - if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil { - causeForRecClosing = fmt.Sprint(v) - } - // recordSequenceNumber - recordSequenceNumber := "" - if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil { - recordSequenceNumber = fmt.Sprint(v) - } - // localRecordSequenceNumber - localRecordSequenceNumber := "" - if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil { - localRecordSequenceNumber = fmt.Sprint(v) - } - // 数据量上行链路 - var dataVolumeGPRSUplink int64 = 0 - // 数据量下行链路 - var dataVolumeGPRSDownlink int64 = 0 - if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil { - usageList := v.([]any) - if len(usageList) > 0 { - for _, used := range usageList { - usedUnit := used.(map[string]any) - if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk { - dataVolumeGPRSUplink = parse.Number(dup) - } - if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk { - dataVolumeGPRSDownlink = parse.Number(ddown) - } - } - } - } - // 时长 - duration := "-" - if v, ok := cdrJSON["duration"]; ok && v != nil { - duration = fmt.Sprint(parse.Number(v)) - } - // 调用时间 - invocationTimestamp := "" - if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { - invocationTimestamp = v.(string) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: row.NeName, - "C" + idx: row.RmUid, - "D" + idx: chargingID, - "E" + idx: servedIMSI, - "F" + idx: servedMSISDN, - "G" + idx: dataVolumeGPRSUplink, - "H" + idx: dataVolumeGPRSDownlink, - "I" + idx: duration, - "J" + idx: invocationTimestamp, - "K" + idx: pGWAddressUsed, - "L" + idx: sGWAddress, - "M" + idx: rATType, - "N" + idx: pdpPDNType, - "O" + idx: servedPDPPDNAddress, - "P" + idx: strings.Join(servingNodeAddress, ","), - "Q" + idx: strings.Join(servingNodeType, ","), - "R" + idx: accessPointNameNI, - "S" + idx: causeForRecClosing, - "T" + idx: recordSequenceNumber, - "U" + idx: localRecordSequenceNumber, - "V" + idx: recordType, - "W" + idx: invocationTimestamp, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/cdr_event_smf.go b/src/modules/network_data/service/cdr_event_smf.go deleted file mode 100644 index cb5bc7fb..00000000 --- a/src/modules/network_data/service/cdr_event_smf.go +++ /dev/null @@ -1,230 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" -) - -// 实例化数据层 CDREventSMF 结构体 -var NewCDREventSMF = &CDREventSMF{ - cdrEventRepository: repository.NewCDREventSMF, -} - -// CDREventSMF CDR会话事件SMF 服务层处理 -type CDREventSMF struct { - cdrEventRepository *repository.CDREventSMF // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventSMF) FindByPage(querys model.CDREventSMFQuery) ([]model.CDREventSMF, int64) { - return r.cdrEventRepository.SelectByPage(querys) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMF) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventSMF) ExportXlsx(rows []model.CDREventSMF, fileName string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "Charging ID", - "C1": "NE Name", - "D1": "Resource Unique ID", - "E1": "Subscriber ID Data", - "F1": "Subscriber ID Type", - "G1": "Data Volume Uplink", - "H1": "Data Volume Downlink", - "I1": "Data Total Volume", - "J1": "Duration", - "K1": "Invocation Time", - "L1": "User Identifier", - "M1": "SSC Mode", - "N1": "DNN ID", - "O1": "PDU Type", - "P1": "RAT Type", - "Q1": "PDU IPv4 Address", - "R1": "Network Function IPv4", - "S1": "PDU IPv6 Address Swith Prefix", - "T1": "Record Network Function ID", - "U1": "Record Type", - "V1": "Record Opening Time", - } - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]interface{} - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 计费ID - chargingID := "" - if v, ok := cdrJSON["chargingID"]; ok && v != nil { - chargingID = fmt.Sprint(parse.Number(v)) - } - // 订阅 ID 类型 - subscriptionIDType := "-" - // 订阅 ID 数据 - subscriptionIDData := "-" - if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { - if sub, subOk := v.(map[string]any); subOk && sub != nil { - subscriptionIDType = sub["subscriptionIDType"].(string) - subscriptionIDData = sub["subscriptionIDData"].(string) - } - } - - // 网络功能 IPv4 地址 - networkFunctionIPv4Address := "" - if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil { - if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil { - networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string) - } - } - - // 数据量上行链路 - var dataVolumeUplink int64 = 0 - // 数据量下行链路 - var dataVolumeDownlink int64 = 0 - // 数据总量 - var dataTotalVolume int64 = 0 - if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { - usageList := v.([]any) - if len(usageList) > 0 { - for _, used := range usageList { - usedUnit := used.(map[string]any) - usedUnitList := usedUnit["usedUnitContainer"].([]any) - if len(usedUnitList) > 0 { - for _, data := range usedUnitList { - udata := data.(map[string]any) - if dup, dupOk := udata["dataVolumeUplink"]; dupOk { - dataVolumeUplink += parse.Number(dup) - } - if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { - dataVolumeDownlink += parse.Number(ddown) - } - if dt, dtOk := udata["dataTotalVolume"]; dtOk { - dataTotalVolume += parse.Number(dt) - } - } - } - } - } - } - // 时长 - duration := "-" - if v, ok := cdrJSON["duration"]; ok && v != nil { - duration = fmt.Sprint(parse.Number(v)) - } - // 调用时间 - invocationTimestamp := "" - if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { - invocationTimestamp = v.(string) - } - // 记录打开时间 - User_Identifier := "" - SSC_Mode := "" - RAT_Type := "" - DNN_ID := "" - PDU_Type := "" - PDU_IPv4 := "" - PDU_IPv6 := "" - if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { - pduInfo := v.(map[string]any) - - if v, ok := pduInfo["userIdentifier"]; ok && v != nil { - User_Identifier = v.(string) - } - if v, ok := pduInfo["sSCMode"]; ok && v != nil { - SSC_Mode = v.(string) - } - if v, ok := pduInfo["rATType"]; ok && v != nil { - RAT_Type = v.(string) - } - if v, ok := pduInfo["dNNID"]; ok && v != nil { - DNN_ID = v.(string) - } - if v, ok := pduInfo["pDUType"]; ok && v != nil { - PDU_Type = v.(string) - } - if v, ok := pduInfo["pDUAddress"]; ok && v != nil { - pDUAddress := v.(map[string]any) - if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { - PDU_IPv4 = addr.(string) - } - if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { - PDU_IPv6 = addr.(string) - } - } - } - - // 记录网络参数ID - recordNFID := "" - if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil { - recordNFID = v.(string) - } - - //记录开始时间 - recordOpeningTime := "" - if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { - recordOpeningTime = v.(string) - } - - //记录类型 - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = v.(string) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: chargingID, - "C" + idx: row.NeName, - "D" + idx: row.RmUid, - "E" + idx: subscriptionIDData, - "F" + idx: subscriptionIDType, - "G" + idx: dataVolumeUplink, - "H" + idx: dataVolumeDownlink, - "I" + idx: dataTotalVolume, - "J" + idx: duration, - "K" + idx: invocationTimestamp, - "L" + idx: User_Identifier, - "M" + idx: SSC_Mode, - "N" + idx: DNN_ID, - "O" + idx: PDU_Type, - "P" + idx: RAT_Type, - "Q" + idx: PDU_IPv4, - "R" + idx: networkFunctionIPv4Address, - "S" + idx: PDU_IPv6, - "T" + idx: recordNFID, - "U" + idx: recordType, - "V" + idx: recordOpeningTime, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/cdr_event_smsc.go b/src/modules/network_data/service/cdr_event_smsc.go deleted file mode 100644 index 99006c31..00000000 --- a/src/modules/network_data/service/cdr_event_smsc.go +++ /dev/null @@ -1,137 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" - sysService "be.ems/src/modules/system/service" -) - -// 实例化数据层 CDREventSMSC 结构体 -var NewCDREventSMSC = &CDREventSMSC{ - cdrEventRepository: repository.NewCDREventSMSC, -} - -// CDREventSMSC CDR会话事件SMSC 服务层处理 -type CDREventSMSC struct { - cdrEventRepository *repository.CDREventSMSC // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventSMSC) FindByPage(query model.CDREventSMSCQuery) ([]model.CDREventSMSC, int64) { - return r.cdrEventRepository.SelectByPage(query) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMSC) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventSMSC) ExportXlsx(rows []model.CDREventSMSC, fileName, language string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "NE Name", - "C1": "Record Behavior", - "D1": "Service Type", - "E1": "Caller", - "F1": "Called", - "G1": "Result", - "H1": "Time", - } - // 读取字典数据 CDR 原因码 - dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]interface{} - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 记录类型 - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = v.(string) - } - // 服务类型 - serviceType := "" - if v, ok := cdrJSON["serviceType"]; ok && v != nil { - serviceType = v.(string) - } - // 被叫 - called := "" - if v, ok := cdrJSON["calledParty"]; ok && v != nil { - called = v.(string) - } - // 主叫 - caller := "" - if v, ok := cdrJSON["callerParty"]; ok && v != nil { - caller = v.(string) - } - // 呼叫结果 0失败,1成功 - callResult := "Fail" - if v, ok := cdrJSON["result"]; ok && v != nil { - resultVal := parse.Number(v) - if resultVal == 1 { - callResult = "Success" - } - } - // 结果原因 - if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" { - cause := fmt.Sprint(v) - for _, v := range dictCDRCauseCode { - if cause == v.DataValue { - callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel)) - break - } - } - } - // 取时间 - timeStr := "" - if v, ok := cdrJSON["updateTime"]; ok && v != nil { - if releaseTime := parse.Number(v); releaseTime > 0 { - timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) - } else { - timeStr = v.(string) - } - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: row.NeName, - "C" + idx: recordType, - "D" + idx: serviceType, - "E" + idx: caller, - "F" + idx: called, - "G" + idx: callResult, - "H" + idx: timeStr, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/oam/service/cdr.go b/src/modules/oam/service/cdr.go new file mode 100644 index 00000000..7173087d --- /dev/null +++ b/src/modules/oam/service/cdr.go @@ -0,0 +1,73 @@ +package service + +import ( + "encoding/json" + "fmt" + + "be.ems/src/framework/logger" + "github.com/tsmask/go-oam" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +// 实例化服务层 CDR 结构体 +var NewCDR = &CDR{ + neInfoService: neService.NewNeInfo, + wsService: wsService.NewWSSend, + cdrEventService: neDataService.NewCDREvent, +} + +// CDR 消息处理 +type CDR struct { + neInfoService *neService.NeInfo + wsService *wsService.WSSend + cdrEventService *neDataService.CDREvent // CDR会话事件服务 +} + +// Resolve 接收处理 +func (s *CDR) Resolve(c oam.CDR) error { + if c.Data == nil { + return fmt.Errorf("cdr data is nil") + } + // 是否存在网元 + neInfo := s.neInfoService.FindByRmuid(c.NeUid) + if neInfo.NeType == "" || neInfo.RmUID != c.NeUid { + logger.Warnf("resolve cdr network element does not exist %s", c.NeUid) + return fmt.Errorf("resolve cdr network element does not exist %s", c.NeUid) + } + + cdrByte, _ := json.Marshal(c.Data) + cdrEvent := neDataModel.CDREvent{ + NeType: neInfo.NeType, + NeName: neInfo.NeName, + RmUid: neInfo.RmUID, + Timestamp: c.RecordTime, + CdrJson: string(cdrByte), + CreatedAt: c.RecordTime, + } + insertId := s.cdrEventService.Insert(cdrEvent) + if insertId <= 0 { + return fmt.Errorf("add cdr data fail") + } + cdrEvent.ID = insertId + + // 推送到ws订阅组 + switch neInfo.NeType { + case "IMS": + dataMap := c.Data.(map[string]any) + v, ok := dataMap["recordType"] + if ok && (v == "MOC" || v == "MTSM") { + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_IMS_CDR, neInfo.NeId), cdrEvent) + } + case "SMF": + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMF_CDR, neInfo.NeId), cdrEvent) + case "SMSC": + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMSC_CDR, neInfo.NeId), cdrEvent) + case "SGWC": + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SGWC_CDR, neInfo.NeId), cdrEvent) + } + return nil +} diff --git a/src/modules/ws/processor/cdr_connect.go b/src/modules/ws/processor/cdr_connect.go index a3848860..884008c4 100644 --- a/src/modules/ws/processor/cdr_connect.go +++ b/src/modules/ws/processor/cdr_connect.go @@ -6,79 +6,29 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/resp" - neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neInfoService "be.ems/src/modules/network_element/service" ) -// GetCDRConnectByIMS 获取CDR会话事件-IMS -func GetCDRConnectByIMS(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventIMSQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") +// GetCDRConnect 获取CDR会话事件 +func GetCDRConnect(requestID string, data any) ([]byte, error) { + if data == nil { + logger.Errorf("ws processor GetCDRConnect data is nil") + return nil, fmt.Errorf("query data error") + } + dataMap := data.(map[string]any) + query := make(map[string]string, 0) + for k, v := range dataMap { + query[k] = fmt.Sprintf("%v", v) } // 查询网元信息 rmUID - neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query.NeType, query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { + neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { return nil, fmt.Errorf("query neinfo not found") } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewCDREventIMS.FindByPage(query) - resultByte, err := json.Marshal(resp.Ok(map[string]any{ - "requestId": requestID, - "data": map[string]any{"rows": rows, "total": total}, - })) - return resultByte, err -} - -// GetCDRConnectBySMF 获取CDR会话事件-SMF -func GetCDRConnectBySMF(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventSMFQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") - } - - // 查询网元信息 rmUID - neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query.NeType, query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { - return nil, fmt.Errorf("query neinfo not found") - } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewCDREventSMF.FindByPage(query) - resultByte, err := json.Marshal(resp.Ok(map[string]any{ - "requestId": requestID, - "data": map[string]any{"rows": rows, "total": total}, - })) - return resultByte, err -} - -// GetCDRConnectBySMSC 获取CDR会话事件-SMSC -func GetCDRConnectBySMSC(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventSMSCQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") - } - - // 查询网元信息 rmUID - neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query.NeType, query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { - return nil, fmt.Errorf("query neinfo not found") - } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewCDREventSMSC.FindByPage(query) + query["rmUID"] = neInfo.RmUID + rows, total := neDataService.NewCDREvent.FindByPage(neInfo.NeType, query) resultByte, err := json.Marshal(resp.Ok(map[string]any{ "requestId": requestID, "data": map[string]any{"rows": rows, "total": total}, From 00e8b63890ad1a71f59cf0a1ad5ec333acf6e48f Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:53:26 +0800 Subject: [PATCH 12/80] =?UTF-8?q?perf:=20=E9=87=8D=E6=9E=84=E6=8E=A5?= =?UTF-8?q?=E6=94=B6UE=E6=8E=A5=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/controller/amf.go | 61 ++--- src/modules/network_data/controller/mme.go | 61 ++--- src/modules/network_data/model/ue_event.go | 18 ++ .../network_data/model/ue_event_amf.go | 33 --- .../network_data/model/ue_event_mme.go | 33 --- .../network_data/repository/ue_event.go | 132 ++++++++++ .../network_data/repository/ue_event_amf.go | 98 -------- .../network_data/repository/ue_event_mme.go | 98 -------- src/modules/network_data/service/ue_event.go | 229 ++++++++++++++++++ .../network_data/service/ue_event_amf.go | 138 ----------- .../network_data/service/ue_event_mme.go | 130 ---------- src/modules/oam/service/ue_nb.go | 64 +++++ src/modules/ws/processor/ue_connect.go | 57 ++--- 13 files changed, 511 insertions(+), 641 deletions(-) create mode 100644 src/modules/network_data/model/ue_event.go delete mode 100644 src/modules/network_data/model/ue_event_amf.go delete mode 100644 src/modules/network_data/model/ue_event_mme.go create mode 100644 src/modules/network_data/repository/ue_event.go delete mode 100644 src/modules/network_data/repository/ue_event_amf.go delete mode 100644 src/modules/network_data/repository/ue_event_mme.go create mode 100644 src/modules/network_data/service/ue_event.go delete mode 100644 src/modules/network_data/service/ue_event_amf.go delete mode 100644 src/modules/network_data/service/ue_event_mme.go create mode 100644 src/modules/oam/service/ue_nb.go diff --git a/src/modules/network_data/controller/amf.go b/src/modules/network_data/controller/amf.go index 51cc8fbb..02bbed35 100644 --- a/src/modules/network_data/controller/amf.go +++ b/src/modules/network_data/controller/amf.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" @@ -19,15 +18,15 @@ import ( // 实例化控制层 AMFController 结构体 var NewAMF = &AMFController{ neInfoService: neService.NewNeInfo, - ueEventService: neDataService.NewUEEventAMF, + ueEventService: neDataService.NewUEEvent, } // 网元AMF // // PATH /amf type AMFController struct { - neInfoService *neService.NeInfo // 网元信息服务 - ueEventService *neDataService.UEEventAMF // UE会话事件服务 + neInfoService *neService.NeInfo // 网元信息服务 + ueEventService *neDataService.UEEvent // UE会话事件服务 } // UE会话列表 @@ -49,23 +48,20 @@ type AMFController struct { // @Router /neData/amf/ue/list [get] func (s *AMFController) UEList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.UEEventAMFQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - - // 查询网元获取IP - neInfo := s.neInfoService.FindByNeTypeAndNeID("AMF", querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // 查询网元信息 rmUID + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.ueEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.ueEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -98,7 +94,7 @@ func (s *AMFController) UERemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.ueEventService.DeleteByIds(ids) + rows, err := s.ueEventService.DeleteByIds("AMF", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -109,7 +105,7 @@ func (s *AMFController) UERemove(c *gin.Context) { // UE会话列表导出 // -// POST /ue/export +// GET /ue/export // // @Tags network_data/amf // @Accept json @@ -119,28 +115,23 @@ func (s *AMFController) UERemove(c *gin.Context) { // @Security TokenAuth // @Summary UE Session List Export // @Description UE Session List Export -// @Router /neData/amf/ue/export [post] +// @Router /neData/amf/ue/export [get] func (s *AMFController) UEExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.UEEventAMFQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元获取IP - neInfo := s.neInfoService.FindByNeTypeAndNeID("AMF", querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // 查询网元信息 rmUID + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.ueEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.ueEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -150,7 +141,7 @@ func (s *AMFController) UEExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.ueEventService.ExportXlsx(rows, fileName, language) + saveFilePath, err := s.ueEventService.ExportAMF(rows, fileName, language) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/controller/mme.go b/src/modules/network_data/controller/mme.go index a64e15da..057689ab 100644 --- a/src/modules/network_data/controller/mme.go +++ b/src/modules/network_data/controller/mme.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" @@ -19,15 +18,15 @@ import ( // 实例化控制层 MMEController 结构体 var NewMME = &MMEController{ neInfoService: neService.NewNeInfo, - ueEventService: neDataService.NewUEEventMME, + ueEventService: neDataService.NewUEEvent, } // 网元MME // // PATH /mme type MMEController struct { - neInfoService *neService.NeInfo // 网元信息服务 - ueEventService *neDataService.UEEventMME // UE会话事件服务 + neInfoService *neService.NeInfo // 网元信息服务 + ueEventService *neDataService.UEEvent // UE会话事件服务 } // UE会话列表 @@ -49,23 +48,20 @@ type MMEController struct { // @Router /neData/mme/ue/list [get] func (s *MMEController) UEList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.UEEventMMEQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - - // 查询网元获取IP - neInfo := s.neInfoService.FindByNeTypeAndNeID("MME", querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // 查询网元信息 rmUID + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.ueEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.ueEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -98,7 +94,7 @@ func (s *MMEController) UERemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.ueEventService.DeleteByIds(ids) + rows, err := s.ueEventService.DeleteByIds("MME", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -109,7 +105,7 @@ func (s *MMEController) UERemove(c *gin.Context) { // UE会话列表导出 // -// POST /ue/export +// GET /ue/export // // @Tags network_data/mme // @Accept json @@ -119,28 +115,23 @@ func (s *MMEController) UERemove(c *gin.Context) { // @Security TokenAuth // @Summary UE Session List Export // @Description UE Session List Export -// @Router /neData/mme/ue/export [post] +// @Router /neData/mme/ue/export [get] func (s *MMEController) UEExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.UEEventMMEQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元获取IP - neInfo := s.neInfoService.FindByNeTypeAndNeID("MME", querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // 查询网元信息 rmUID + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.ueEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.ueEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -150,7 +141,7 @@ func (s *MMEController) UEExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("mme_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.ueEventService.ExportXlsx(rows, fileName, language) + saveFilePath, err := s.ueEventService.ExportMME(rows, fileName, language) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/model/ue_event.go b/src/modules/network_data/model/ue_event.go new file mode 100644 index 00000000..5b0b309d --- /dev/null +++ b/src/modules/network_data/model/ue_event.go @@ -0,0 +1,18 @@ +package model + +// UEEvent UE会话对象 ue_event +type UEEvent struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeName string `json:"neName" gorm:"column:ne_name"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到时间 + EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 + EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String + CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 +} + +// TableName 表名称 +func (*UEEvent) TableName() string { + return "ue_event" +} diff --git a/src/modules/network_data/model/ue_event_amf.go b/src/modules/network_data/model/ue_event_amf.go deleted file mode 100644 index 23340324..00000000 --- a/src/modules/network_data/model/ue_event_amf.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// UEEventAMF UE会话对象AMF ue_event_amf -type UEEventAMF struct { - ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state - EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*UEEventAMF) TableName() string { - return "ue_event_amf" -} - -// UEEventAMFQuery UE会话对象AMF查询参数结构体 -type UEEventAMFQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=AMF"` // 网元类型, 暂时支持AMF - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - EventType string `json:"eventType" form:"eventType"` // 事件类型 auth-result detach cm-state - IMSI string `json:"imsi" form:"imsi"` // imsi - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/ue_event_mme.go b/src/modules/network_data/model/ue_event_mme.go deleted file mode 100644 index 5c43eb79..00000000 --- a/src/modules/network_data/model/ue_event_mme.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// UEEventMME UE会话对象MME ue_event_mme -type UEEventMME struct { - ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state - EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*UEEventMME) TableName() string { - return "ue_event_mme" -} - -// UEEventMMEQuery UE会话对象MME查询参数结构体 -type UEEventMMEQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=MME"` // 网元类型, 暂时支持MME - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - EventType string `json:"eventType" form:"eventType"` // 事件类型 auth-result detach cm-state - IMSI string `json:"imsi" form:"imsi"` // imsi - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/repository/ue_event.go b/src/modules/network_data/repository/ue_event.go new file mode 100644 index 00000000..d06730f7 --- /dev/null +++ b/src/modules/network_data/repository/ue_event.go @@ -0,0 +1,132 @@ +package repository + +import ( + "fmt" + "strings" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/network_data/model" +) + +// 实例化数据层 UEEvent 结构体 +var NewUEEvent = &UEEvent{} + +// UEEvent UE会话事件 数据层处理 +type UEEvent struct{} + +// SelectByPage 分页查询集合 +func (r UEEvent) SelectByPage(neType string, query map[string]string) ([]model.UEEvent, int64) { + // 表名 + tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Model(&model.CDREvent{}) + // 查询条件拼接 + if v, ok := query["rmUID"]; ok && v != "" { + tx = tx.Where("rm_uid = ?", v) + } + if v, ok := query["beginTime"]; ok && v != "" { + if len(v) == 10 { + v = v + "000" + } + tx = tx.Where("timestamp >= ?", v) + } + if v, ok := query["endTime"]; ok && v != "" { + if len(v) == 10 { + v = v + "000" + } + tx = tx.Where("timestamp <= ?", v) + } + if v, ok := query["eventType"]; ok && v != "" { + eventTypes := strings.Split(v, ",") + tx = tx.Where("event_type in ?", eventTypes) + } + if v, ok := query["imsi"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') = ?", v) + } + + // 查询结果 + var total int64 = 0 + rows := []model.UEEvent{} + + // 查询数量 长度为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize)) + + // 排序 + if v, ok := query["sortField"]; ok && v != "" { + sortSql := v + if o, ok := query["sortOrder"]; ok && o != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + tx = tx.Order(sortSql) + } + + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query err => %v", err) + } + + return rows, total +} + +// SelectByIds 通过ID查询 +func (r UEEvent) SelectByIds(neType string, ids []int64) []model.UEEvent { + rows := []model.UEEvent{} + if len(ids) <= 0 { + return rows + } + // 表名 + tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Model(&model.UEEvent{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// DeleteByIds 批量删除信息 +func (r UEEvent) DeleteByIds(neType string, ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + // 表名 + tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Where("id in ?", ids) + if err := tx.Delete(&model.UEEvent{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// Insert 新增信息 返回新增数据ID +func (r UEEvent) Insert(param model.UEEvent) int64 { + if param.NeType == "" { + return 0 + } + if param.CreatedAt == 0 { + param.CreatedAt = time.Now().UnixMilli() + } + // 表名 + tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(param.NeType)) + // 执行插入 + if err := db.DB("").Table(tableName).Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.ID +} diff --git a/src/modules/network_data/repository/ue_event_amf.go b/src/modules/network_data/repository/ue_event_amf.go deleted file mode 100644 index 60c109cc..00000000 --- a/src/modules/network_data/repository/ue_event_amf.go +++ /dev/null @@ -1,98 +0,0 @@ -package repository - -import ( - "strings" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 UEEventAMF 结构体 -var NewUEEventAMF = &UEEventAMF{} - -// UEEventAMF UE会话事件 数据层处理 -type UEEventAMF struct{} - -// SelectByPage 分页查询集合 -func (r UEEventAMF) SelectByPage(query model.UEEventAMFQuery) ([]model.UEEventAMF, int64) { - tx := db.DB("").Model(&model.UEEventAMF{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.EventType != "" { - eventTypes := strings.Split(query.EventType, ",") - tx = tx.Where("event_type in ?", eventTypes) - } - if query.IMSI != "" { - tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') = ?", query.IMSI) - } - - // 查询结果 - var total int64 = 0 - rows := []model.UEEventAMF{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r UEEventAMF) SelectByIds(ids []int64) []model.UEEventAMF { - rows := []model.UEEventAMF{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.UEEventAMF{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r UEEventAMF) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.UEEventAMF{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/ue_event_mme.go b/src/modules/network_data/repository/ue_event_mme.go deleted file mode 100644 index ffcb6262..00000000 --- a/src/modules/network_data/repository/ue_event_mme.go +++ /dev/null @@ -1,98 +0,0 @@ -package repository - -import ( - "strings" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 UEEventMME 结构体 -var NewUEEventMME = &UEEventMME{} - -// UEEventMME UE会话事件 数据层处理 -type UEEventMME struct{} - -// SelectByPage 分页查询集合 -func (r UEEventMME) SelectByPage(query model.UEEventMMEQuery) ([]model.UEEventMME, int64) { - tx := db.DB("").Model(&model.UEEventMME{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.EventType != "" { - eventTypes := strings.Split(query.EventType, ",") - tx = tx.Where("event_type in ?", eventTypes) - } - if query.IMSI != "" { - tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') = ?", query.IMSI) - } - - // 查询结果 - var total int64 = 0 - rows := []model.UEEventMME{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r UEEventMME) SelectByIds(ids []int64) []model.UEEventMME { - rows := []model.UEEventMME{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.UEEventMME{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r UEEventMME) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.UEEventMME{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/service/ue_event.go b/src/modules/network_data/service/ue_event.go new file mode 100644 index 00000000..3f3d7a5f --- /dev/null +++ b/src/modules/network_data/service/ue_event.go @@ -0,0 +1,229 @@ +package service + +import ( + "encoding/json" + "fmt" + "strconv" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/file" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" + sysService "be.ems/src/modules/system/service" + "github.com/tsmask/go-oam" +) + +// 实例化数据层 UEEvent 结构体 +var NewUEEvent = &UEEvent{ + ueEventRepository: repository.NewUEEvent, +} + +// UEEvent UE会话事件 服务层处理 +type UEEvent struct { + ueEventRepository *repository.UEEvent // UE会话事件数据信息 +} + +// FindByPage 根据条件分页查询 +func (r UEEvent) FindByPage(neType string, query map[string]string) ([]model.UEEvent, int64) { + return r.ueEventRepository.SelectByPage(neType, query) +} + +// DeleteByIds 批量删除信息 +func (r UEEvent) DeleteByIds(neType string, ids []int64) (int64, error) { + // 检查是否存在 + rows := r.ueEventRepository.SelectByIds(neType, ids) + if len(rows) <= 0 { + return 0, fmt.Errorf("no data") + } + + if len(rows) == len(ids) { + rows := r.ueEventRepository.DeleteByIds(neType, ids) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} + +// Insert 新增信息 +func (r UEEvent) Insert(param model.UEEvent) int64 { + return r.ueEventRepository.Insert(param) +} + +// ExportAMF 导出数据到 xlsx 文件 +func (r UEEvent) ExportAMF(rows []model.UEEvent, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := "" + for _, v := range dictUEEventType { + if row.EventType == v.DataValue { + eventType = i18n.TKey(language, v.DataLabel) + break + } + } + // 取结果 + eventResult := "" + // 取时间 + timeStr := "" + if row.EventType == oam.UENB_TYPE_AUTH { + if v, ok := eventJSON["authTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["authCode"]; ok && v != nil { + eventResult = v.(string) + for _, v := range dictUEAauthCode { + if eventResult == v.DataValue { + eventResult = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + if row.EventType == oam.UENB_TYPE_DETACH { + if v, ok := eventJSON["detachTime"]; ok && v != nil { + timeStr = v.(string) + } + eventResult = "Success" + } + if row.EventType == oam.UENB_TYPE_CM { + if v, ok := eventJSON["changeTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["status"]; ok && v != nil { + eventResult = fmt.Sprint(v) + for _, v := range dictUEEventCmState { + if eventResult == v.DataValue { + eventResult = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportMME 导出数据到 xlsx 文件 +func (r UEEvent) ExportMME(rows []model.UEEvent, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := row.EventType + for _, v := range dictUEEventType { + if row.EventType == v.DataValue { + eventType = i18n.TKey(language, v.DataLabel) + break + } + } + // 取结果 + eventResult := "" + if v, ok := eventJSON["result"]; ok && v != nil { + eventResult = v.(string) + if row.EventType == oam.UENB_TYPE_AUTH { + for _, v := range dictUEAauthCode { + if eventResult == v.DataValue { + eventResult = i18n.TKey(language, v.DataLabel) + break + } + } + } + if row.EventType == oam.UENB_TYPE_CM { + for _, v := range dictUEEventCmState { + if eventResult == v.DataValue { + eventResult = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + // 取时间 + timeStr := "" + if v, ok := eventJSON["timestamp"]; ok && v != nil { + rowTime := parse.Number(v) + timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") + +} diff --git a/src/modules/network_data/service/ue_event_amf.go b/src/modules/network_data/service/ue_event_amf.go deleted file mode 100644 index 4ff49c8a..00000000 --- a/src/modules/network_data/service/ue_event_amf.go +++ /dev/null @@ -1,138 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/file" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" - sysService "be.ems/src/modules/system/service" -) - -// 实例化数据层 UEEventAMF 结构体 -var NewUEEventAMF = &UEEventAMF{ - ueEventRepository: repository.NewUEEventAMF, -} - -// UEEventAMF UE会话事件AMF 服务层处理 -type UEEventAMF struct { - ueEventRepository *repository.UEEventAMF // UE会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *UEEventAMF) FindByPage(querys model.UEEventAMFQuery) ([]model.UEEventAMF, int64) { - return r.ueEventRepository.SelectByPage(querys) -} - -// DeleteByIds 批量删除信息 -func (r *UEEventAMF) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.ueEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("no data") - } - - if len(rows) == len(ids) { - rows := r.ueEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r UEEventAMF) ExportXlsx(rows []model.UEEventAMF, fileName, language string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "IMSI", - "C1": "Event Type", - "D1": "Result", - "E1": "Time", - } - // 读取字典数据 UE 事件类型 - dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type") - // 读取字典数据 UE 事件认证代码类型 - dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code") - // 读取字典数据 UE 事件CM状态 - dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var eventJSON map[string]interface{} - err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) - if err != nil { - logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) - continue - } - - // 取IMSI - imsi := "" - if v, ok := eventJSON["imsi"]; ok && v != nil { - imsi = v.(string) - } - // 取类型 - eventType := "" - for _, v := range dictUEEventType { - if row.EventType == v.DataValue { - eventType = i18n.TKey(language, v.DataLabel) - break - } - } - // 取结果 - eventResult := "" - // 取时间 - timeStr := "" - if row.EventType == "auth-result" { - if v, ok := eventJSON["authTime"]; ok && v != nil { - timeStr = v.(string) - } - if v, ok := eventJSON["authCode"]; ok && v != nil { - eventResult = v.(string) - for _, v := range dictUEAauthCode { - if eventResult == v.DataValue { - eventResult = i18n.TKey(language, v.DataLabel) - break - } - } - } - } - if row.EventType == "detach" { - if v, ok := eventJSON["detachTime"]; ok && v != nil { - timeStr = v.(string) - } - eventResult = "Success" - } - if row.EventType == "cm-state" { - if v, ok := eventJSON["changeTime"]; ok && v != nil { - timeStr = v.(string) - } - if v, ok := eventJSON["status"]; ok && v != nil { - eventResult = fmt.Sprint(v) - for _, v := range dictUEEventCmState { - if eventResult == v.DataValue { - eventResult = i18n.TKey(language, v.DataLabel) - break - } - } - } - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: imsi, - "C" + idx: eventType, - "D" + idx: eventResult, - "E" + idx: timeStr, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/ue_event_mme.go b/src/modules/network_data/service/ue_event_mme.go deleted file mode 100644 index 87cf9c25..00000000 --- a/src/modules/network_data/service/ue_event_mme.go +++ /dev/null @@ -1,130 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" - sysService "be.ems/src/modules/system/service" -) - -// 实例化数据层 UEEventMME 结构体 -var NewUEEventMME = &UEEventMME{ - ueEventRepository: repository.NewUEEventMME, -} - -// UEEventMME UE会话事件MME 服务层处理 -type UEEventMME struct { - ueEventRepository *repository.UEEventMME // UE会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *UEEventMME) FindByPage(querys model.UEEventMMEQuery) ([]model.UEEventMME, int64) { - return r.ueEventRepository.SelectByPage(querys) -} - -// DeleteByIds 批量删除信息 -func (r *UEEventMME) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.ueEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("no data") - } - - if len(rows) == len(ids) { - rows := r.ueEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r UEEventMME) ExportXlsx(rows []model.UEEventMME, fileName, language string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "IMSI", - "C1": "Event Type", - "D1": "Result", - "E1": "Time", - } - // 读取字典数据 UE 事件类型 - dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type") - // 读取字典数据 UE 事件认证代码类型 - dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code") - // 读取字典数据 UE 事件CM状态 - dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var eventJSON map[string]interface{} - err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) - if err != nil { - logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) - continue - } - - // 取IMSI - imsi := "" - if v, ok := eventJSON["imsi"]; ok && v != nil { - imsi = v.(string) - } - // 取类型 - eventType := row.EventType - for _, v := range dictUEEventType { - if row.EventType == v.DataValue { - eventType = i18n.TKey(language, v.DataLabel) - break - } - } - // 取结果 - eventResult := "" - if v, ok := eventJSON["result"]; ok && v != nil { - eventResult = v.(string) - if row.EventType == "auth-result" { - for _, v := range dictUEAauthCode { - if eventResult == v.DataValue { - eventResult = i18n.TKey(language, v.DataLabel) - break - } - } - } - if row.EventType == "cm-state" { - for _, v := range dictUEEventCmState { - if eventResult == v.DataValue { - eventResult = i18n.TKey(language, v.DataLabel) - break - } - } - } - } - // 取时间 - timeStr := "" - if v, ok := eventJSON["timestamp"]; ok && v != nil { - rowTime := parse.Number(v) - timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: imsi, - "C" + idx: eventType, - "D" + idx: eventResult, - "E" + idx: timeStr, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") - -} diff --git a/src/modules/oam/service/ue_nb.go b/src/modules/oam/service/ue_nb.go new file mode 100644 index 00000000..5a419049 --- /dev/null +++ b/src/modules/oam/service/ue_nb.go @@ -0,0 +1,64 @@ +package service + +import ( + "encoding/json" + "fmt" + + "be.ems/src/framework/logger" + "github.com/tsmask/go-oam" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +// 实例化服务层 UENB 结构体 +var NewUENB = &UENB{ + neInfoService: neService.NewNeInfo, + wsService: wsService.NewWSSend, + ueEventService: neDataService.NewUEEvent, +} + +// UENB 消息处理 +type UENB struct { + neInfoService *neService.NeInfo + wsService *wsService.WSSend + ueEventService *neDataService.UEEvent // UE会话事件服务 +} + +// Resolve 接收处理 +func (s *UENB) Resolve(u oam.UENB) error { + // 是否存在网元 + neInfo := s.neInfoService.FindByRmuid(u.NeUid) + if neInfo.NeType == "" || neInfo.RmUID != u.NeUid { + logger.Warnf("resolve ue_nb network element does not exist %s", u.NeUid) + return fmt.Errorf("resolve ue_nb network element does not exist %s", u.NeUid) + } + + uenbByte, _ := json.Marshal(u) + uenbEvent := neDataModel.UEEvent{ + NeType: neInfo.NeType, + NeName: neInfo.NeName, + RmUID: neInfo.RmUID, + Timestamp: u.RecordTime, + EventType: u.Type, + EventJSONStr: string(uenbByte), + } + insertId := s.ueEventService.Insert(uenbEvent) + if insertId <= 0 { + return fmt.Errorf("add ue_nb data fail") + } + uenbEvent.ID = insertId + + // 推送到ws订阅组 + switch neInfo.NeType { + case "AMF": + s.wsService.ByGroupID(wsService.GROUP_AMF_UE, uenbEvent) + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_AMF_UE, neInfo.NeId), uenbEvent) + case "MME": + s.wsService.ByGroupID(wsService.GROUP_MME_UE, uenbEvent) + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_MME_UE, neInfo.NeId), uenbEvent) + } + return nil +} diff --git a/src/modules/ws/processor/ue_connect.go b/src/modules/ws/processor/ue_connect.go index 79d99952..20ebf461 100644 --- a/src/modules/ws/processor/ue_connect.go +++ b/src/modules/ws/processor/ue_connect.go @@ -6,54 +6,29 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/resp" - neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" ) -// GetUEConnectByAMF 获取UE会话事件-AMF -func GetUEConnectByAMF(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.UEEventAMFQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetUEConnectByAMF err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") +// GetUEConnect 获取UE会话事件 +func GetUEConnect(requestID string, data any) ([]byte, error) { + if data == nil { + logger.Errorf("ws processor GetUEConnect data is nil") + return nil, fmt.Errorf("query data error") + } + dataMap := data.(map[string]any) + query := make(map[string]string, 0) + for k, v := range dataMap { + query[k] = fmt.Sprintf("%v", v) } - // 查询网元获取IP - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID("AMF", query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { - return nil, fmt.Errorf("not fount neId info") + // 查询网元信息 rmUID + neInfo := neService.NewNeInfo.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { + return nil, fmt.Errorf("query neinfo not found") } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewUEEventAMF.FindByPage(query) - resultByte, err := json.Marshal(resp.Ok(map[string]any{ - "requestId": requestID, - "data": map[string]any{"rows": rows, "total": total}, - })) - return resultByte, err -} - -// GetUEConnectByMME 获取UE会话事件-MME -func GetUEConnectByMME(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.UEEventMMEQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetUEConnectByMME err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") - } - - // 查询网元获取IP - neInfo := neService.NewNeInfo.FindByNeTypeAndNeID("MME", query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { - return nil, fmt.Errorf("not fount neId info") - } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewUEEventMME.FindByPage(query) + query["rmUID"] = neInfo.RmUID + rows, total := neDataService.NewUEEvent.FindByPage(neInfo.NeType, query) resultByte, err := json.Marshal(resp.Ok(map[string]any{ "requestId": requestID, "data": map[string]any{"rows": rows, "total": total}, From 6f48e0ae41f80e51788860aa3a186ce730d7cddf Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:55:47 +0800 Subject: [PATCH 13/80] =?UTF-8?q?perf:=20=E9=87=8D=E6=9E=84=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=E5=91=8A=E8=AD=A6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/constants/alarm.go | 24 +- .../ne_alarm_state_check.go | 134 ++------ .../ne_alarm_state_check_cmd.go | 224 +++++-------- .../ne_alarm_state_check_license.go | 137 ++------ .../network_data/controller/all_alarm.go | 5 +- src/modules/network_data/model/alarm.go | 24 +- src/modules/network_data/model/alarm_event.go | 10 +- .../network_data/model/alarm_forward_log.go | 14 +- src/modules/network_data/model/alarm_log.go | 20 +- src/modules/network_data/service/alarm.go | 25 +- .../network_data/service/alarm_event.go | 44 ++- src/modules/oam/service/alarm.go | 310 ++++++++++++++++++ 12 files changed, 538 insertions(+), 433 deletions(-) create mode 100644 src/modules/oam/service/alarm.go diff --git a/src/framework/constants/alarm.go b/src/framework/constants/alarm.go index f22c8e2d..e64a4d8d 100644 --- a/src/framework/constants/alarm.go +++ b/src/framework/constants/alarm.go @@ -1,13 +1,19 @@ package constants -// 告警 alarmCode 常量 const ( - // ALARM_EVENT_REBOOT 事件-网元重启 - ALARM_EVENT_REBOOT = 9000 - // ALARM_STATE_CHECK 告警-状态检查 - ALARM_STATE_CHECK = 10000 - // ALARM_RAM_CPU_CHECK 告警-内存/CPU/磁盘检查 - ALARM_CMD_CHECK = 10001 - // ALARM_LICENSE_CHECK 告警-网元License到期检查 - ALARM_LICENSE_CHECK = 10002 + ALARM_EVENT_REBOOT = 9000 // 告警Code-事件-网元重启 + ALARM_STATE_CHECK = 10000 // 告警Code-状态检查 + ALARM_CMD_CHECK = 10001 // 告警Code-内存/CPU/磁盘检查 + ALARM_LICENSE_CHECK = 10002 // 告警Code-网元License到期检查 +) + +const ( + ALARM_ACK_STATE_NOT_ACK = "NotAck" // 告警确认状态-未确认 + ALARM_ACK_STATE_ACK = "Ack" // 告警确认状态-已确认 +) + +const ( + ALARM_CLEAR_TYPE_NOT_CLEAR = "NotClear" // 告警清除状态-未清除 + ALARM_CLEAR_TYPE_AUTO_CLEAR = "AutoClear" // 告警清除状态-自动清除 + ALARM_CLEAR_TYPE_MANUAL_CLEAR = "ManualClear" // 告警清除状态-手动清除 ) diff --git a/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go b/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go index f2d6e9a7..e79e6f1d 100644 --- a/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go +++ b/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go @@ -5,33 +5,26 @@ import ( "fmt" "time" + "github.com/tsmask/go-oam" + "be.ems/src/framework/constants" "be.ems/src/framework/cron" "be.ems/src/framework/logger" "be.ems/src/framework/utils/parse" - - neDataModel "be.ems/src/modules/network_data/model" - neDataService "be.ems/src/modules/network_data/service" neModel "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" - wsService "be.ems/src/modules/ws/service" + oamService "be.ems/src/modules/oam/service" ) var NewProcessor = &NeAlarmStateCheckProcessor{ - neConfigBackupService: neService.NewNeConfigBackup, - neInfoService: neService.NewNeInfo, - alarmService: neDataService.NewAlarm, - wsSendService: wsService.NewWSSend, - count: 0, + neInfoService: neService.NewNeInfo, + count: 0, } // NeAlarmStateCheckProcessor 网元告警状态检查 type NeAlarmStateCheckProcessor struct { - neConfigBackupService *neService.NeConfigBackup // 网元配置文件备份记录服务 - neInfoService *neService.NeInfo // 网元信息服务 - alarmService *neDataService.Alarm // 告警信息服务 - wsSendService *wsService.WSSend // ws发送服务 - count int // 执行次数 + neInfoService *neService.NeInfo // 网元信息服务 + count int // 执行次数 } // alarmParams 告警参数 @@ -69,104 +62,37 @@ func (s *NeAlarmStateCheckProcessor) Execute(data any) (any, error) { if neInfo.CreateTime == 0 { continue } - neTypeAndId := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) + // 网元在线状态 isOnline := parse.Boolean(neInfo.ServerState["online"]) // 告警ID params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_STATE_CHECK, neInfo.CreateTime) - // 检查网元告警ID是否唯一 - alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: params.AlarmId, - }) - // 告警状态 - alarmStatus := "" - if len(alarmIdArr) > 0 { - alarmStatus = fmt.Sprint(alarmIdArr[0].AlarmStatus) - } - // 在线且状态为活动告警 - if isOnline && alarmStatus == "1" { - // 进行清除 - clearAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) - if err != nil { - result[neTypeAndId] = err.Error() - continue - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, clearAlarm) - result[neTypeAndId] = "alarm clear" - } - // 不在线 - if !isOnline && alarmStatus == "" { - // 进行新增 - newAlarm, err := s.alarmNew(neInfo, params) - if err != nil { - result[neTypeAndId] = err.Error() - continue - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, newAlarm) - result[neTypeAndId] = "alarm new" + // 告警状态 + alarmStatus := oam.ALARM_STATUS_ACTIVE + if isOnline { + alarmStatus = oam.ALARM_STATUS_CLEAR + } + // 创建告警 + alarm := oam.Alarm{ + NeUid: neInfo.RmUID, // 网元唯一标识 + AlarmTime: time.Now().UnixMilli(), // 事件产生时间 + AlarmId: params.AlarmId, // 告警ID 唯一,清除时对应 + AlarmCode: constants.ALARM_STATE_CHECK, // 告警状态码 + AlarmType: params.AlarmType, // 告警类型 + AlarmTitle: params.AlarmTitle, // 告警标题 + PerceivedSeverity: params.OrigSeverity, // 告警级别 + AlarmStatus: alarmStatus, // 告警状态 + SpecificProblem: params.SpecificProblem, // 告警问题原因 + SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID + AddInfo: params.AddInfo, // 告警辅助信息 + LocationInfo: "NE State: Heartbeat", // 告警定位信息 + } + if err = oamService.NewAlarm.Resolve(alarm); err == nil { + result[neInfo.RmUID] = "state alarm" } } // 返回结果,用于记录执行结果 return result, nil } - -// alarmClear 清除告警 -func (s NeAlarmStateCheckProcessor) alarmClear(neInfo neModel.NeInfo, v neDataModel.Alarm) (neDataModel.Alarm, error) { - // 变更告警ID为告警清除ID - v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) - v.AlarmStatus = "0" - // 告警清除 - v.ClearType = 1 - v.ClearTime = neInfo.UpdateTime - v.ClearUser = "system" - rows := s.alarmService.Update(v) - if rows > 0 { - return v, nil - } - return neDataModel.Alarm{}, fmt.Errorf("clear alarm fail") -} - -// alarmNew 新增告警 -func (s NeAlarmStateCheckProcessor) alarmNew(neInfo neModel.NeInfo, v alarmParams) (neDataModel.Alarm, error) { - // seq 告警序号 - lastSeq := s.alarmService.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) - lastTime := neInfo.UpdateTime // 网元最后更新时间 - if lastTime < neInfo.CreateTime { - lastTime = time.Now().UnixMilli() - } - alarm := neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - NeName: neInfo.NeName, - Province: neInfo.Province, - PvFlag: neInfo.PvFlag, - AlarmSeq: lastSeq + 1, - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: constants.ALARM_STATE_CHECK, - EventTime: lastTime, - AlarmType: v.AlarmType, - OrigSeverity: v.OrigSeverity, - PerceivedSeverity: v.OrigSeverity, - ObjectUid: neInfo.RmUID, - ObjectName: "NE State", - ObjectType: "state", - LocationInfo: "NE State: Heartbeat", - AlarmStatus: "1", // 活动告警 - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - insertId := s.alarmService.InsertAndForword(alarm) - if insertId > 0 { - alarm.ID = insertId - return alarm, nil - } - return neDataModel.Alarm{}, fmt.Errorf("new alarm fail") -} diff --git a/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go b/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go index 6a622081..2d7fc89e 100644 --- a/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go +++ b/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go @@ -10,6 +10,8 @@ import ( "sync" "time" + "github.com/tsmask/go-oam" + "be.ems/src/framework/constants" "be.ems/src/framework/cron" "be.ems/src/framework/logger" @@ -18,6 +20,7 @@ import ( neDataService "be.ems/src/modules/network_data/service" neModel "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" + oamService "be.ems/src/modules/oam/service" wsService "be.ems/src/modules/ws/service" ) @@ -28,22 +31,18 @@ var ( ) var NewProcessor = &NeAlarmStateCheckCMDProcessor{ - neConfigBackupService: neService.NewNeConfigBackup, - neInfoService: neService.NewNeInfo, - neStateService: neDataService.NewNEState, - alarmService: neDataService.NewAlarm, - wsSendService: wsService.NewWSSend, - count: 0, + neInfoService: neService.NewNeInfo, + neStateService: neDataService.NewNEState, + wsSendService: wsService.NewWSSend, + count: 0, } // NeAlarmStateCheckCMDProcessor 网元告警内存/CPU/磁盘检查 type NeAlarmStateCheckCMDProcessor struct { - neConfigBackupService *neService.NeConfigBackup // 网元配置文件备份记录服务 - neInfoService *neService.NeInfo // 网元信息服务 - neStateService *neDataService.NEState // 网元状态信息服务 - alarmService *neDataService.Alarm // 告警信息服务 - wsSendService *wsService.WSSend // ws发送服务 - count int // 执行次数 + neInfoService *neService.NeInfo // 网元信息服务 + neStateService *neDataService.NEState // 网元状态信息服务 + wsSendService *wsService.WSSend // ws发送服务 + count int // 执行次数 } // alarmParams 告警参数 @@ -103,65 +102,83 @@ func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) { } // 检查状态 - err := s.serverState(neInfo.ServerState, params.CPUUseGt, params.MemUseGt, params.DiskUseGt) + sysCpuUsage, sysMemUsage, sysDiskUsage := s.serverState(neInfo.ServerState) + // 检查CPU/Menory/Disk使用率 + warnMsg := []string{} + if int64(sysCpuUsage) >= params.CPUUseGt { + warnMsg = append(warnMsg, fmt.Sprintf("cpu usage %.2f%%", sysCpuUsage)) + } + if int64(sysMemUsage) >= params.MemUseGt { + warnMsg = append(warnMsg, fmt.Sprintf("memory usage %.2f%%", sysMemUsage)) + } + if int64(sysDiskUsage) >= params.DiskUseGt { + warnMsg = append(warnMsg, fmt.Sprintf("disk usage %.2f%%", sysDiskUsage)) + } + var err error + if len(warnMsg) > 0 { + currentTime := time.Now() + validTimes := []time.Time{} + if v, ok := triggerCount.Load(neInfo.RmUID); ok { + times := v.([]time.Time) + // 清理过期的记录:10秒前的触发记录不再计入 + for _, t := range times { + if currentTime.Sub(t) <= triggerWindow { + validTimes = append(validTimes, t) + } + } + validTimes = append(validTimes, currentTime) + triggerCount.Store(neInfo.RmUID, validTimes) + } else { + // 事件第一次触发,初始化记录 + validTimes = append(validTimes, currentTime) + triggerCount.Store(neInfo.RmUID, validTimes) + } + if int64(len(validTimes)) >= triggerMax { + err = fmt.Errorf("greater than %s", strings.Join(warnMsg, ", ")) + } + } + + // 检查状态连续触发 if err == nil { continue } + if params.AddInfo != "" { + params.AddInfo = params.AddInfo + ", " + err.Error() + } else { + params.AddInfo = err.Error() + } - neTypeAndId := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) + // 事件产生时间 + alarmTime := time.Now().UnixMilli() // 告警ID - params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_CMD_CHECK, neInfo.CreateTime) - // 检查网元告警ID是否唯一 - alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: params.AlarmId, - }) - // 告警状态, 存在的需要手动清除 - alarmStatus := "" - if len(alarmIdArr) > 0 { - alarmStatus = fmt.Sprint(alarmIdArr[0].AlarmStatus) + params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_CMD_CHECK, alarmTime) + // 创建告警 + alarm := oam.Alarm{ + NeUid: neInfo.RmUID, // 网元唯一标识 + AlarmTime: alarmTime, // 事件产生时间 + AlarmId: params.AlarmId, // 告警ID 唯一,清除时对应 + AlarmCode: constants.ALARM_CMD_CHECK, // 告警状态码 + AlarmType: params.AlarmType, // 告警类型 + AlarmTitle: params.AlarmTitle, // 告警标题 + PerceivedSeverity: params.OrigSeverity, // 告警级别 + AlarmStatus: oam.ALARM_STATUS_ACTIVE, // 告警状态 + SpecificProblem: params.SpecificProblem, // 告警问题原因 + SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID + AddInfo: params.AddInfo, // 告警辅助信息 + LocationInfo: "NE CPU/Menory/Disk: Heartbeat", // 告警定位信息 } - // 活动告警进行清除 - if alarmStatus == "1" { - clearAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) - if err != nil { - result[neTypeAndId] = err.Error() - continue - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, clearAlarm) - result[neTypeAndId] = "alarm clear" - alarmStatus = "" // 标记为未记录再次发起新告警 - } - // 未记录 - if alarmStatus == "" { - addInfo := params.AddInfo - if params.AddInfo != "" { - params.AddInfo = params.AddInfo + ", " + err.Error() - } else { - params.AddInfo = err.Error() - } - // 进行新增 - newAlarm, err := s.alarmNew(neInfo, params) - params.AddInfo = addInfo // 恢复附加信息 - triggerCount.Clear() // 重置连续触发次数 - if err != nil { - result[neTypeAndId] = err.Error() - continue - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, newAlarm) - result[neTypeAndId] = "alarm new" + if err = oamService.NewAlarm.Resolve(alarm); err == nil { + result[neInfo.RmUID] = "cmd alarm" } + triggerCount.Delete(neInfo.RmUID) } // 返回结果,用于记录执行结果 return result, nil } -// serverState 网元状态 -func (s NeAlarmStateCheckCMDProcessor) serverState(state map[string]any, cpuUseGt, memUseGt, diskUseGt int64) error { +// serverState 网元状态记录 +func (s NeAlarmStateCheckCMDProcessor) serverState(state map[string]any) (float64, float64, float64) { // 网元CPU使用率 var nfCpuUsage float64 = 0 // CPU使用率 @@ -224,94 +241,5 @@ func (s NeAlarmStateCheckCMDProcessor) serverState(state map[string]any, cpuUseG groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_NE_STATE, neState.NeType, neState.NeId) s.wsSendService.ByGroupID(groupID, neState) - // 检查CPU/Menory/Disk使用率 - warnMsg := []string{} - if int64(sysCpuUsage) >= cpuUseGt { - warnMsg = append(warnMsg, fmt.Sprintf("cpu usage %.2f%%", sysCpuUsage)) - } - if int64(sysMemUsage) >= memUseGt { - warnMsg = append(warnMsg, fmt.Sprintf("memory usage %.2f%%", sysMemUsage)) - } - if int64(sysDiskUsage) >= diskUseGt { - warnMsg = append(warnMsg, fmt.Sprintf("disk usage %.2f%%", sysDiskUsage)) - } - if len(warnMsg) > 0 { - currentTime := time.Now() - neTypeAndId := fmt.Sprintf("%s_%s", neState.NeType, neState.NeId) - validTimes := []time.Time{} - if v, ok := triggerCount.Load(neTypeAndId); ok { - times := v.([]time.Time) - // 清理过期的记录:10秒前的触发记录不再计入 - for _, t := range times { - if currentTime.Sub(t) <= triggerWindow { - validTimes = append(validTimes, t) - } - } - validTimes = append(validTimes, currentTime) - triggerCount.Store(neTypeAndId, validTimes) - } else { - // 事件第一次触发,初始化记录 - validTimes = append(validTimes, currentTime) - triggerCount.Store(neTypeAndId, validTimes) - } - if int64(len(validTimes)) >= triggerMax { - return fmt.Errorf("greater than %s", strings.Join(warnMsg, ", ")) - } - } - return nil -} - -// alarmClear 清除告警 -func (s NeAlarmStateCheckCMDProcessor) alarmClear(neInfo neModel.NeInfo, v neDataModel.Alarm) (neDataModel.Alarm, error) { - // 变更告警ID为告警清除ID - v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) - v.AlarmStatus = "0" - // 告警清除 - v.ClearType = 1 - v.ClearTime = neInfo.UpdateTime - v.ClearUser = "system" - rows := s.alarmService.Update(v) - if rows > 0 { - return v, nil - } - return neDataModel.Alarm{}, fmt.Errorf("clear alarm fail") -} - -// alarmNew 新增告警 -func (s NeAlarmStateCheckCMDProcessor) alarmNew(neInfo neModel.NeInfo, v alarmParams) (neDataModel.Alarm, error) { - // seq 告警序号 - lastSeq := s.alarmService.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) - lastTime := neInfo.UpdateTime // 网元最后更新时间 - if lastTime < neInfo.CreateTime { - lastTime = time.Now().UnixMilli() - } - alarm := neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - NeName: neInfo.NeName, - Province: neInfo.Province, - PvFlag: neInfo.PvFlag, - AlarmSeq: lastSeq + 1, - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: constants.ALARM_CMD_CHECK, - EventTime: lastTime, - AlarmType: v.AlarmType, - OrigSeverity: v.OrigSeverity, - PerceivedSeverity: v.OrigSeverity, - ObjectUid: neInfo.RmUID, - ObjectName: "NE CPU/Menory/Disk", - ObjectType: "cmd", - LocationInfo: "NE CPU/Menory/Disk: Heartbeat", - AlarmStatus: "1", // 活动告警 - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - insertId := s.alarmService.InsertAndForword(alarm) - if insertId > 0 { - alarm.ID = insertId - return alarm, nil - } - return neDataModel.Alarm{}, fmt.Errorf("new alarm fail") + return sysCpuUsage, sysMemUsage, sysDiskUsage } diff --git a/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go b/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go index 761fad13..a5ae5411 100644 --- a/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go +++ b/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go @@ -10,29 +10,22 @@ import ( "be.ems/src/framework/cron" "be.ems/src/framework/logger" "be.ems/src/framework/utils/parse" + "github.com/tsmask/go-oam" - neDataModel "be.ems/src/modules/network_data/model" - neDataService "be.ems/src/modules/network_data/service" neModel "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" - wsService "be.ems/src/modules/ws/service" + oamService "be.ems/src/modules/oam/service" ) var NewProcessor = &NeAlarmStateCheckLicenseProcessor{ - neConfigBackupService: neService.NewNeConfigBackup, - neInfoService: neService.NewNeInfo, - alarmService: neDataService.NewAlarm, - wsSendService: wsService.NewWSSend, - count: 0, + neInfoService: neService.NewNeInfo, + count: 0, } // NeAlarmStateCheckLicenseProcessor 网元告警License到期检查 type NeAlarmStateCheckLicenseProcessor struct { - neConfigBackupService *neService.NeConfigBackup // 网元配置文件备份记录服务 - neInfoService *neService.NeInfo // 网元信息服务 - alarmService *neDataService.Alarm // 告警信息服务 - wsSendService *wsService.WSSend // ws发送服务 - count int // 执行次数 + neInfoService *neService.NeInfo // 网元信息服务 + count int // 执行次数 } // alarmParams 告警参数 @@ -83,7 +76,7 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) { } // 检查状态 - err := s.serverState(neInfo.ServerState, params.DayLt) + err := s.cheackState(neInfo.ServerState, params.DayLt) if err == nil { continue } @@ -93,50 +86,25 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) { params.AddInfo = err.Error() } - neTypeAndId := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) // 告警ID params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_LICENSE_CHECK, neInfo.CreateTime) - // 检查网元告警ID是否唯一 - alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - AlarmId: params.AlarmId, - }) - // 告警状态, 存在的需要手动清除 - alarmStatus := "" - if len(alarmIdArr) > 0 { - alarmStatus = fmt.Sprint(alarmIdArr[0].AlarmStatus) + // 创建告警 + alarm := oam.Alarm{ + NeUid: neInfo.RmUID, // 网元唯一标识 + AlarmTime: time.Now().UnixMilli(), // 事件产生时间 + AlarmId: params.AlarmId, // 告警ID 唯一,清除时对应 + AlarmCode: constants.ALARM_LICENSE_CHECK, // 告警状态码 + AlarmType: params.AlarmType, // 告警类型 + AlarmTitle: params.AlarmTitle, // 告警标题 + PerceivedSeverity: params.OrigSeverity, // 告警级别 + AlarmStatus: oam.ALARM_STATUS_ACTIVE, // 告警状态 + SpecificProblem: params.SpecificProblem, // 告警问题原因 + SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID + AddInfo: params.AddInfo, // 告警辅助信息 + LocationInfo: "NE License: Heartbeat", // 告警定位信息 } - // 活动告警进行清除 - if alarmStatus == "1" { - clearAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) - if err != nil { - result[neTypeAndId] = err.Error() - continue - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, clearAlarm) - result[neTypeAndId] = "alarm clear" - alarmStatus = "" // 标记为未记录再次发起新告警 - } - // 未记录 - if alarmStatus == "" { - addInfo := params.AddInfo - if params.AddInfo != "" { - params.AddInfo = params.AddInfo + ", " + err.Error() - } else { - params.AddInfo = err.Error() - } - // 进行新增 - newAlarm, err := s.alarmNew(neInfo, params) - params.AddInfo = addInfo // 恢复附加信息 - if err != nil { - result[neTypeAndId] = err.Error() - continue - } - groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, newAlarm) - result[neTypeAndId] = "alarm new" + if err = oamService.NewAlarm.Resolve(alarm); err == nil { + result[neInfo.RmUID] = "license alarm" } } @@ -144,8 +112,8 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) { return result, nil } -// serverState 网元状态 -func (s NeAlarmStateCheckLicenseProcessor) serverState(state map[string]any, dayLt int64) error { +// cheackState 检查网元状态 +func (s NeAlarmStateCheckLicenseProcessor) cheackState(state map[string]any, dayLt int64) error { expire := fmt.Sprint(state["expire"]) if expire == "" || expire == "" || expire == "-" || expire == "2099-12-31" { return nil @@ -168,58 +136,3 @@ func (s NeAlarmStateCheckLicenseProcessor) serverState(state map[string]any, day } return nil } - -// alarmClear 清除告警 -func (s NeAlarmStateCheckLicenseProcessor) alarmClear(neInfo neModel.NeInfo, v neDataModel.Alarm) (neDataModel.Alarm, error) { - // 变更告警ID为告警清除ID - v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) - v.AlarmStatus = "0" - // 告警清除 - v.ClearType = 1 - v.ClearTime = neInfo.UpdateTime - v.ClearUser = "system" - rows := s.alarmService.Update(v) - if rows > 0 { - return v, nil - } - return neDataModel.Alarm{}, fmt.Errorf("clear alarm fail") -} - -// alarmNew 新增告警 -func (s NeAlarmStateCheckLicenseProcessor) alarmNew(neInfo neModel.NeInfo, v alarmParams) (neDataModel.Alarm, error) { - // seq 告警序号 - lastSeq := s.alarmService.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) - lastTime := neInfo.UpdateTime // 网元最后更新时间 - if lastTime < neInfo.CreateTime { - lastTime = time.Now().UnixMilli() - } - alarm := neDataModel.Alarm{ - NeType: neInfo.NeType, - NeId: neInfo.NeId, - NeName: neInfo.NeName, - Province: neInfo.Province, - PvFlag: neInfo.PvFlag, - AlarmSeq: lastSeq + 1, - AlarmId: v.AlarmId, - AlarmTitle: v.AlarmTitle, - AlarmCode: constants.ALARM_LICENSE_CHECK, - EventTime: lastTime, - AlarmType: v.AlarmType, - OrigSeverity: v.OrigSeverity, - PerceivedSeverity: v.OrigSeverity, - ObjectUid: neInfo.RmUID, - ObjectName: "NE License", - ObjectType: "license", - LocationInfo: "NE License: Heartbeat", - AlarmStatus: "1", // 活动告警 - SpecificProblem: v.SpecificProblem, - SpecificProblemId: v.SpecificProblemID, - AddInfo: v.AddInfo, - } - insertId := s.alarmService.InsertAndForword(alarm) - if insertId > 0 { - alarm.ID = insertId - return alarm, nil - } - return neDataModel.Alarm{}, fmt.Errorf("new alarm fail") -} diff --git a/src/modules/network_data/controller/all_alarm.go b/src/modules/network_data/controller/all_alarm.go index c2918524..b9e41d99 100644 --- a/src/modules/network_data/controller/all_alarm.go +++ b/src/modules/network_data/controller/all_alarm.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "be.ems/src/framework/constants" "be.ems/src/framework/i18n" "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" @@ -107,7 +108,7 @@ func (s AlarmController) Clear(c *gin.Context) { } clearUser := reqctx.LoginUserToUserName(c) - rows, err := s.alarmService.AlarmClearByIds(body.Ids, clearUser) + rows, err := s.alarmService.ClearByIds(body.Ids, clearUser, constants.ALARM_CLEAR_TYPE_MANUAL_CLEAR) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return @@ -130,7 +131,7 @@ func (s AlarmController) Ack(c *gin.Context) { } ackUser := reqctx.LoginUserToUserName(c) - rows, err := s.alarmService.AlarmAckByIds(body.Ids, ackUser, body.AckState) + rows, err := s.alarmService.AckByIds(body.Ids, ackUser, constants.ALARM_ACK_STATE_ACK) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/model/alarm.go b/src/modules/network_data/model/alarm.go index 61abd550..d0a2e104 100644 --- a/src/modules/network_data/model/alarm.go +++ b/src/modules/network_data/model/alarm.go @@ -8,26 +8,26 @@ type Alarm struct { NeName string `json:"neName" gorm:"column:ne_name"` // 网元名称 Province string `json:"province" gorm:"column:province"` // 网元省份地域 PvFlag string `json:"pvFlag" gorm:"column:pv_flag"` // 网元标识虚拟化标识 - AlarmSeq int64 `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 同网元类型连续递增 + AlarmSeq int64 `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 连续递增 AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题 AlarmCode int64 `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码 - EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 秒级 - AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5 - OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - PerceivedSeverity string `json:"perceivedSeverity" gorm:"column:perceived_severity"` // 告警级别 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) + EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 + AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型 + OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度 + PerceivedSeverity string `json:"perceivedSeverity" gorm:"column:perceived_severity"` // 告警级别 ObjectUid string `json:"objectUid" gorm:"column:object_uid"` // 对象ID ObjectName string `json:"objectName" gorm:"column:object_name"` // 对象名称 ObjectType string `json:"objectType" gorm:"column:object_type"` // 对象类型 LocationInfo string `json:"locationInfo" gorm:"column:location_info"` // 告警定位信息 - AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 0:clear, 1:active + AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 SpecificProblem string `json:"specificProblem" gorm:"column:specific_problem"` // 告警问题原因 SpecificProblemId string `json:"specificProblemId" gorm:"column:specific_problem_id"` // 告警问题原因ID AddInfo string `json:"addInfo" gorm:"column:add_info"` // 告警辅助信息 - AckState int64 `json:"ackState" gorm:"column:ack_state"` // 确认状态 0: Unacked, 1: Acked - AckTime int64 `json:"ackTime" gorm:"column:ack_time"` // 确认时间 秒级 + AckState string `json:"ackState" gorm:"column:ack_state"` // 确认状态 + AckTime int64 `json:"ackTime" gorm:"column:ack_time"` // 确认时间 AckUser string `json:"ackUser" gorm:"column:ack_user"` // 确认用户 - ClearType int64 `json:"clearType" gorm:"column:clear_type"` // 清除状态 0: Unclear, 1: AutoClear, 2: ManualClear + ClearType string `json:"clearType" gorm:"column:clear_type"` // 清除状态 ClearTime int64 `json:"clearTime" gorm:"column:clear_time"` // 清除时间 ClearUser string `json:"clearUser" gorm:"column:clear_user"` // 清除用户 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 创建时间 @@ -46,9 +46,9 @@ type AlarmQuery struct { PvFlag string `json:"pvFlag" form:"pvFlag"` AlarmCode string `json:"alarmCode" form:"alarmCode"` AlarmType string `json:"alarmType" form:"alarmType"` - AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=0 1"` // 告警状态 0:clear, 1:active - OrigSeverity string `json:"origSeverity" form:"origSeverity"` // 告警类型 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time + AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=Clear Active"` // 告警状态 + OrigSeverity string `json:"origSeverity" form:"origSeverity"` // 告警类型 + BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time EndTime int64 `json:"endTime" form:"endTime"` SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段 SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc diff --git a/src/modules/network_data/model/alarm_event.go b/src/modules/network_data/model/alarm_event.go index e1190720..d157f0e3 100644 --- a/src/modules/network_data/model/alarm_event.go +++ b/src/modules/network_data/model/alarm_event.go @@ -9,16 +9,16 @@ type AlarmEvent struct { AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题 AlarmCode int64 `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码 - EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 秒级 + EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 ObjectUid string `json:"objectUid" gorm:"column:object_uid"` // 对象ID ObjectName string `json:"objectName" gorm:"column:object_name"` // 对象名称 ObjectType string `json:"objectType" gorm:"column:object_type"` // 对象类型 LocationInfo string `json:"locationInfo" gorm:"column:location_info"` // 告警定位信息 - AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 0:clear, 1:active + AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 SpecificProblem string `json:"specificProblem" gorm:"column:specific_problem"` // 告警问题原因 SpecificProblemId string `json:"specificProblemId" gorm:"column:specific_problem_id"` // 告警问题原因ID AddInfo string `json:"addInfo" gorm:"column:add_info"` // 告警辅助信息 - ClearType int64 `json:"clearType" gorm:"column:clear_type"` // 清除状态 0: Unclear, 1: AutoClear, 2: ManualClear + ClearType string `json:"clearType" gorm:"column:clear_type"` // 清除状态 ClearTime int64 `json:"clearTime" gorm:"column:clear_time"` // 清除时间 ClearUser string `json:"clearUser" gorm:"column:clear_user"` // 清除用户 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 创建时间 @@ -34,8 +34,8 @@ type AlarmEventQuery struct { NeType string `json:"neType" form:"neType"` // 网元类型 NeID string `json:"neId" form:"neId"` // 网元ID AlarmCode string `json:"alarmCode" form:"alarmCode"` - AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=0 1"` // 告警状态 0:clear, 1:active - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time + AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=Clear Active"` // 告警状态 + BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time EndTime int64 `json:"endTime" form:"endTime"` SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段 SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc diff --git a/src/modules/network_data/model/alarm_forward_log.go b/src/modules/network_data/model/alarm_forward_log.go index a79c6d1b..93e9bb11 100644 --- a/src/modules/network_data/model/alarm_forward_log.go +++ b/src/modules/network_data/model/alarm_forward_log.go @@ -5,16 +5,16 @@ type AlarmForwardLog struct { ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeId string `json:"neId" gorm:"column:ne_id"` - AlarmSeq int64 `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 同网元类型连续递增 + AlarmSeq int64 `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 连续递增 AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID AlarmCode int64 `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码 AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题 - AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 0:clear, 1:active - AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5 - OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 秒级 + AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 + AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型 + OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度 + EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间 - Type string `json:"type" gorm:"column:type"` // 转发方式 SMS/EMAIL + Type string `json:"type" gorm:"column:type"` // 转发方式 SMS/EMAIL/SMSC Target string `json:"target" gorm:"column:target"` // 发送目标用户 Result string `json:"result" gorm:"column:result"` // 发送结果 } @@ -28,7 +28,7 @@ func (*AlarmForwardLog) TableName() string { type AlarmForwardLogQuery struct { NeType string `json:"neType" form:"neType"` // 网元类型 NeID string `json:"neId" form:"neId"` // 网元ID - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time + BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 EndTime int64 `json:"endTime" form:"endTime"` SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段 SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc diff --git a/src/modules/network_data/model/alarm_log.go b/src/modules/network_data/model/alarm_log.go index 8931daf4..841308bd 100644 --- a/src/modules/network_data/model/alarm_log.go +++ b/src/modules/network_data/model/alarm_log.go @@ -5,14 +5,14 @@ type AlarmLog struct { ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeId string `json:"neId" gorm:"column:ne_id"` - AlarmSeq int64 `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 同网元类型连续递增 + AlarmSeq int64 `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 连续递增 AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID AlarmCode int64 `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码 AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题 - AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 0:clear, 1:active - AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5 - OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 秒级 + AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态 + AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型 + OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度 + EventTime int64 `json:"eventTime" gorm:"column:event_time"` // 事件产生时间 CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间 } @@ -23,11 +23,11 @@ func (*AlarmLog) TableName() string { // AlarmLogQuery 告警日志数据查询参数结构体 type AlarmLogQuery struct { - NeType string `json:"neType" form:"neType"` // 网元类型 - NeID string `json:"neId" form:"neId"` // 网元ID - AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=0 1"` // 告警状态 0:clear, 1:active - OrigSeverity string `json:"origSeverity" form:"origSeverity"` // 告警类型 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time + NeType string `json:"neType" form:"neType"` // 网元类型 + NeID string `json:"neId" form:"neId"` // 网元ID + AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=Clear Active"` // 告警状态 + OrigSeverity string `json:"origSeverity" form:"origSeverity"` // 告警类型 + BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time EndTime int64 `json:"endTime" form:"endTime"` SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段 SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc diff --git a/src/modules/network_data/service/alarm.go b/src/modules/network_data/service/alarm.go index bb98a45a..737acb0b 100644 --- a/src/modules/network_data/service/alarm.go +++ b/src/modules/network_data/service/alarm.go @@ -5,6 +5,8 @@ import ( "strconv" "time" + "github.com/tsmask/go-oam" + "be.ems/src/framework/constants" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/date" @@ -65,8 +67,8 @@ func (s Alarm) FindAlarmSeqLast(neType, neId string) int64 { return s.alarmRepository.SelectAlarmSeqLast(neType, neId) } -// AlarmClearByIds 批量清除告警信息 -func (r Alarm) AlarmClearByIds(ids []int64, clearUser string) (int64, error) { +// ClearByIds 批量清除告警信息 +func (r Alarm) ClearByIds(ids []int64, clearUser, clearType string) (int64, error) { // 检查是否存在 arr := r.alarmRepository.SelectByIds(ids) if len(arr) <= 0 { @@ -80,21 +82,20 @@ func (r Alarm) AlarmClearByIds(ids []int64, clearUser string) (int64, error) { if v.AlarmCode == constants.ALARM_STATE_CHECK || v.AlarmCode == constants.ALARM_CMD_CHECK || v.AlarmCode == constants.ALARM_LICENSE_CHECK { v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) } - v.AlarmStatus = "0" + v.AlarmStatus = oam.ALARM_STATUS_CLEAR // 告警清除 - v.ClearType = 2 - v.ClearTime = time.Now().UnixMilli() + v.ClearType = clearType v.ClearUser = clearUser + v.ClearTime = time.Now().UnixMilli() rows += r.alarmRepository.Update(v) } return rows, nil } - // 清除失败! return 0, fmt.Errorf("clear fail") } -// AlarmAckByIds 批量确认清除告警信息 -func (r Alarm) AlarmAckByIds(ids []int64, ackUser string, ackState bool) (int64, error) { +// AckByIds 批量确认清除告警信息 +func (r Alarm) AckByIds(ids []int64, ackUser, ackState string) (int64, error) { // 检查是否存在 arr := r.alarmRepository.SelectByIds(ids) if len(arr) <= 0 { @@ -104,19 +105,13 @@ func (r Alarm) AlarmAckByIds(ids []int64, ackUser string, ackState bool) (int64, if len(arr) == len(ids) { var rows int64 = 0 for _, v := range arr { - // 确认清除 - if ackState { - v.AckState = 1 - } else { - v.AckState = 0 - } + v.AckState = ackState v.AckTime = time.Now().UnixMilli() v.AckUser = ackUser rows += r.alarmRepository.Update(v) } return rows, nil } - // 清除失败! return 0, fmt.Errorf("ack fail") } diff --git a/src/modules/network_data/service/alarm_event.go b/src/modules/network_data/service/alarm_event.go index e3413d81..4779e4b4 100644 --- a/src/modules/network_data/service/alarm_event.go +++ b/src/modules/network_data/service/alarm_event.go @@ -2,6 +2,9 @@ package service import ( "fmt" + "time" + + "github.com/tsmask/go-oam" "be.ems/src/modules/network_data/model" "be.ems/src/modules/network_data/repository" @@ -9,44 +12,44 @@ import ( // 实例化数据层 AlarmEvent 结构体 var NewAlarmEvent = &AlarmEvent{ - AlarmEventRepository: repository.NewAlarmEvent, + alarmEventRepository: repository.NewAlarmEvent, } // AlarmEvent 告警 服务层处理 type AlarmEvent struct { - AlarmEventRepository *repository.AlarmEvent // 告警数据信息 + alarmEventRepository *repository.AlarmEvent // 告警数据信息 } // FindByPage 根据条件分页查询 func (r AlarmEvent) FindByPage(query model.AlarmEventQuery) ([]model.AlarmEvent, int64) { - return r.AlarmEventRepository.SelectByPage(query) + return r.alarmEventRepository.SelectByPage(query) } // Find 查询 func (r AlarmEvent) Find(param model.AlarmEvent) []model.AlarmEvent { - return r.AlarmEventRepository.Select(param) + return r.alarmEventRepository.Select(param) } // Insert 新增信息 func (s AlarmEvent) Insert(param model.AlarmEvent) int64 { - return s.AlarmEventRepository.Insert(param) + return s.alarmEventRepository.Insert(param) } // Update 修改信息 func (s AlarmEvent) Update(param model.AlarmEvent) int64 { - return s.AlarmEventRepository.Update(param) + return s.alarmEventRepository.Update(param) } // DeleteByIds 批量删除信息 func (r AlarmEvent) DeleteByIds(ids []int64) (int64, error) { // 检查是否存在 - data := r.AlarmEventRepository.SelectByIds(ids) + data := r.alarmEventRepository.SelectByIds(ids) if len(data) <= 0 { return 0, fmt.Errorf("no data") } if len(data) == len(ids) { - rows := r.AlarmEventRepository.DeleteByIds(ids) + rows := r.alarmEventRepository.DeleteByIds(ids) return rows, nil } // 删除信息失败! @@ -55,5 +58,28 @@ func (r AlarmEvent) DeleteByIds(ids []int64) (int64, error) { // FindAlarmEventSeqLast 查询网元告警最后一条序号 func (s AlarmEvent) FindAlarmEventSeqLast(neType, neId string) int64 { - return s.AlarmEventRepository.SelectAlarmEventSeqLast(neType, neId) + return s.alarmEventRepository.SelectAlarmEventSeqLast(neType, neId) +} + +// ClearByIds 批量清除告警信息 +func (r AlarmEvent) ClearByIds(ids []int64, clearUser, clearType string) (int64, error) { + // 检查是否存在 + arr := r.alarmEventRepository.SelectByIds(ids) + if len(arr) <= 0 { + return 0, fmt.Errorf("no data") + } + + if len(arr) == len(ids) { + var rows int64 = 0 + for _, v := range arr { + v.AlarmStatus = oam.ALARM_STATUS_CLEAR + // 告警清除 + v.ClearType = clearType + v.ClearUser = clearUser + v.ClearTime = time.Now().UnixMilli() + rows += r.alarmEventRepository.Update(v) + } + return rows, nil + } + return 0, fmt.Errorf("clear fail") } diff --git a/src/modules/oam/service/alarm.go b/src/modules/oam/service/alarm.go new file mode 100644 index 00000000..0f28e935 --- /dev/null +++ b/src/modules/oam/service/alarm.go @@ -0,0 +1,310 @@ +package service + +import ( + "fmt" + + "be.ems/src/framework/config" + "be.ems/src/framework/constants" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + "github.com/tsmask/go-oam" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + notificationService "be.ems/src/modules/notification/service" + traceService "be.ems/src/modules/trace/service" + wsService "be.ems/src/modules/ws/service" +) + +// 实例化服务层 Alarm 结构体 +var NewAlarm = &Alarm{ + neInfoService: neService.NewNeInfo, + wsService: wsService.NewWSSend, + alarmService: neDataService.NewAlarm, + alarmEventService: neDataService.NewAlarmEvent, + alarmLogService: neDataService.NewAlarmLog, + alarmForwardLogService: neDataService.NewAlarmForwardLog, +} + +// Alarm 消息处理 +type Alarm struct { + neInfoService *neService.NeInfo + wsService *wsService.WSSend + alarmService *neDataService.Alarm + alarmEventService *neDataService.AlarmEvent + alarmLogService *neDataService.AlarmLog + alarmForwardLogService *neDataService.AlarmForwardLog + + alarm neDataModel.Alarm +} + +// Resolve 接收处理 +func (s *Alarm) Resolve(a oam.Alarm) error { + // 是否存在网元 + neInfo := s.neInfoService.FindByRmuid(a.NeUid) + if neInfo.NeType == "" || neInfo.RmUID != a.NeUid { + logger.Warnf("resolve alarm network element does not exist %s", a.NeUid) + return fmt.Errorf("resolve alarm network element does not exist %s", a.NeUid) + } + + // seq 告警序号 + lastSeq := neDataService.NewAlarm.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) + + // 告警信息 + s.alarm = neDataModel.Alarm{ + NeType: neInfo.NeType, + NeId: neInfo.NeId, + NeName: neInfo.NeName, + Province: neInfo.Province, + PvFlag: neInfo.PvFlag, + AlarmSeq: lastSeq + 1, + AlarmId: a.AlarmId, + AlarmTitle: a.AlarmTitle, + AlarmCode: int64(a.AlarmCode), + EventTime: a.AlarmTime, + AlarmType: a.AlarmType, + OrigSeverity: a.PerceivedSeverity, + PerceivedSeverity: a.PerceivedSeverity, + ObjectUid: neInfo.RmUID, + ObjectName: neInfo.NeName, + ObjectType: neInfo.NeType, + LocationInfo: a.LocationInfo, + AlarmStatus: a.AlarmStatus, + SpecificProblem: a.SpecificProblem, + SpecificProblemId: a.SpecificProblemID, + AddInfo: a.AddInfo, + } + + // 进行清除 + if a.AlarmStatus == oam.ALARM_STATUS_CLEAR { + if a.AlarmType == oam.ALARM_SEVERITY_EVENT { + if err := s.clearEvent(); err != nil { + logger.Warnf("resolve alarm clear event failed: %s", err.Error()) + return err + } + } else { + if err := s.clear(); err != nil { + logger.Warnf("resolve alarm clear failed: %s", err.Error()) + return err + } + } + + } + // 进行新增 + if a.AlarmStatus == oam.ALARM_STATUS_ACTIVE { + if a.AlarmType == oam.ALARM_SEVERITY_EVENT { + if err := s.addEvent(); err != nil { + logger.Warnf("resolve alarm add event failed: %s", err.Error()) + return err + } + } else { + if err := s.add(); err != nil { + logger.Warnf("resolve alarm add failed: %s", err.Error()) + return err + } + } + } + + // 记录日志 + if err := s.saveLog(); err != nil { + logger.Warnf("resolve alarm save log failed: %s", err.Error()) + return err + } + // 推送 + s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId), s.alarm) + // 通知 + go s.notify(neInfo.IP) + return nil +} + +// saveLog 记录日志 +func (s *Alarm) saveLog() error { + alarmLog := neDataModel.AlarmLog{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmSeq: s.alarm.AlarmSeq, + AlarmId: s.alarm.AlarmId, + AlarmTitle: s.alarm.AlarmTitle, + AlarmCode: s.alarm.AlarmCode, + AlarmStatus: s.alarm.AlarmStatus, + AlarmType: s.alarm.AlarmType, + OrigSeverity: s.alarm.PerceivedSeverity, + EventTime: s.alarm.EventTime, + } + insertId := s.alarmLogService.Insert(alarmLog) + if insertId <= 0 { + return fmt.Errorf("save alarm log fail") + } + return nil +} + +// add 新增告警 +func (s *Alarm) add() error { + // 检查网元告警ID是否唯一 + alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmId: s.alarm.AlarmId, + }) + if len(alarmIdArr) > 0 { + return fmt.Errorf("already exists alarmId:%s", s.alarm.AlarmId) + } + insertId := s.alarmService.Insert(s.alarm) + if insertId > 0 { + s.alarm.ID = insertId + return nil + } + return fmt.Errorf("add alarm fail") +} + +// clear 清除告警 +func (s *Alarm) clear() error { + // 检查网元告警ID是否唯一 + alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmId: s.alarm.AlarmId, + }) + if len(alarmIdArr) != 1 { + return fmt.Errorf("not exists alarmId:%s", s.alarm.AlarmId) + } + + // 告警清除 + rows, _ := s.alarmService.ClearByIds([]int64{alarmIdArr[0].ID}, s.alarm.ObjectUid, constants.ALARM_CLEAR_TYPE_AUTO_CLEAR) + if rows > 0 { + return nil + } + return fmt.Errorf("clear fail alarmId:%s", s.alarm.AlarmId) +} + +// addEvent 新增告警事件 +func (s *Alarm) addEvent() error { + // 检查网元告警ID是否唯一 + alarmIdArr := s.alarmEventService.Find(neDataModel.AlarmEvent{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmId: s.alarm.AlarmId, + }) + if len(alarmIdArr) > 0 { + return fmt.Errorf("event already exists alarmId:%s", s.alarm.AlarmId) + } + // seq 告警序号 + lastSeq := s.alarmEventService.FindAlarmEventSeqLast(s.alarm.NeType, s.alarm.NeId) + + alarmEvent := neDataModel.AlarmEvent{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmSeq: lastSeq + 1, + AlarmId: s.alarm.AlarmId, + AlarmTitle: s.alarm.AlarmTitle, + AlarmCode: s.alarm.AlarmCode, + EventTime: s.alarm.EventTime, + ObjectUid: s.alarm.ObjectUid, + ObjectName: s.alarm.ObjectName, + ObjectType: s.alarm.ObjectType, + LocationInfo: s.alarm.LocationInfo, + AlarmStatus: s.alarm.AlarmStatus, + SpecificProblem: s.alarm.SpecificProblem, + SpecificProblemId: s.alarm.SpecificProblemId, + AddInfo: s.alarm.AddInfo, + } + insertId := s.alarmEventService.Insert(alarmEvent) + if insertId > 0 { + alarmEvent.ID = insertId + // 网元重启后,清除活动告警 + if s.alarm.AlarmCode == constants.ALARM_EVENT_REBOOT { + rows := s.alarmService.Find(neDataModel.Alarm{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmStatus: oam.ALARM_STATUS_ACTIVE, + }) + ids := make([]int64, 0) + for _, v := range rows { + ids = append(ids, v.ID) + } + s.alarmService.ClearByIds(ids, s.alarm.ObjectUid, constants.ALARM_CLEAR_TYPE_AUTO_CLEAR) + } + // 网元重启后,有跟踪任务的需要重新补发启动任务 + if s.alarm.AlarmCode == constants.ALARM_EVENT_REBOOT { + traceService.NewTraceTask.RunUnstopped(s.alarm.NeType, s.alarm.NeId) + } + return nil + } + return fmt.Errorf("event add fail") +} + +// clearEvent 清除告警事件 +func (s *Alarm) clearEvent() error { + alarmEventService := neDataService.NewAlarmEvent + // 检查网元告警ID是否唯一 + alarmIdArr := alarmEventService.Find(neDataModel.AlarmEvent{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmId: s.alarm.AlarmId, + }) + if len(alarmIdArr) != 1 { + return fmt.Errorf("event not exists alarmId:%s", s.alarm.AlarmId) + } + + // 告警清除 + rows, _ := s.alarmEventService.ClearByIds([]int64{alarmIdArr[0].ID}, s.alarm.ObjectUid, constants.ALARM_CLEAR_TYPE_AUTO_CLEAR) + if rows > 0 { + return nil + } + return fmt.Errorf("event clear fail alarmId:%s", s.alarm.AlarmId) +} + +// notify 通知 +func (s *Alarm) notify(neIp string) { + // 邮箱 + emailEnable := parse.Boolean(config.Get("notification.email.enable")) + if emailEnable { + emailList := fmt.Sprint(config.Get("notification.email.emailList")) + emailResult := "Sent Successfully!" + emailErr := notificationService.EmailAlarm(s.alarm, neIp) + if emailErr != nil { + emailResult = emailErr.Error() + logger.Warnf("alarm notify email failed: %s", emailErr.Error()) + } + s.notifyLog("EMAIL", emailList, emailResult) + } + + // 短信 + smscEnable := parse.Boolean(config.Get("notification.smsc.enable")) + if smscEnable { + mobileList := fmt.Sprint(config.Get("notification.smsc.mobileList")) + smscResult := "Sent Successfully!" + smscErr := notificationService.SMSCAlarm(s.alarm, neIp) + if smscErr != nil { + smscResult = smscErr.Error() + logger.Warnf("alarm notify email failed: %s", smscErr.Error()) + } + s.notifyLog("SMSC", mobileList, smscResult) + } +} + +// notifyLog 通知日志 +func (s *Alarm) notifyLog(forwardBy, toUser, result string) error { + alarmForwardLog := neDataModel.AlarmForwardLog{ + NeType: s.alarm.NeType, + NeId: s.alarm.NeId, + AlarmSeq: s.alarm.AlarmSeq, + AlarmId: s.alarm.AlarmId, + AlarmTitle: s.alarm.AlarmTitle, + AlarmCode: s.alarm.AlarmCode, + AlarmStatus: s.alarm.AlarmStatus, + AlarmType: s.alarm.AlarmType, + OrigSeverity: s.alarm.OrigSeverity, + EventTime: s.alarm.EventTime, + Type: forwardBy, + Target: toUser, + Result: result, + } + // 记录日志 + insertId := s.alarmForwardLogService.Insert(alarmForwardLog) + if insertId <= 0 { + return fmt.Errorf("notify alarm log fail") + } + return nil +} From e67c0d6ba61bee75184f47e410a900925a7fb1c9 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:01:10 +0800 Subject: [PATCH 14/80] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Enssf/n3iwf?= =?UTF-8?q?=E7=9B=B4=E8=BF=9E=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/controller/n3iwf.go | 70 ++++++++++++ src/modules/network_data/controller/nssf.go | 107 ++++++++++++++++++ src/modules/network_data/network_data.go | 35 +++++- .../network_element/fetch_link/n3iwf.go | 64 +++++++++++ .../network_element/fetch_link/nssf.go | 95 ++++++++++++++++ 5 files changed, 365 insertions(+), 6 deletions(-) create mode 100644 src/modules/network_data/controller/n3iwf.go create mode 100644 src/modules/network_data/controller/nssf.go create mode 100644 src/modules/network_element/fetch_link/n3iwf.go create mode 100644 src/modules/network_element/fetch_link/nssf.go diff --git a/src/modules/network_data/controller/n3iwf.go b/src/modules/network_data/controller/n3iwf.go new file mode 100644 index 00000000..0750b082 --- /dev/null +++ b/src/modules/network_data/controller/n3iwf.go @@ -0,0 +1,70 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + neFetchlink "be.ems/src/modules/network_element/fetch_link" + neService "be.ems/src/modules/network_element/service" + + "github.com/gin-gonic/gin" +) + +// 实例化控制层 N3IWFController 结构体 +var NewN3IWF = &N3IWFController{ + neInfoService: neService.NewNeInfo, +} + +// 网元N3IWF +// +// PATH /n3iwf +type N3IWFController struct { + neInfoService *neService.NeInfo // 网元信息服务 +} + +// 在线订阅用户列表信息 +// +// GET /sub/list +// +// @Tags network_data/n3iwf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Param imsi query string false "imsi" +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Online session user list information +// @Description Online session user list information +// @Router /neData/n3iwf/sub/list [get] +func (s N3IWFController) SubUserList(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + IMSI string `form:"imsi"` + } + 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 + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("N3IWF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.N3IWFSubInfoList(neInfo, map[string]string{ + "imsi": query.IMSI, + }) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/network_data/controller/nssf.go b/src/modules/network_data/controller/nssf.go new file mode 100644 index 00000000..7bb0a5cd --- /dev/null +++ b/src/modules/network_data/controller/nssf.go @@ -0,0 +1,107 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + neFetchlink "be.ems/src/modules/network_element/fetch_link" + neService "be.ems/src/modules/network_element/service" + + "github.com/gin-gonic/gin" +) + +// 实例化控制层 NSSFController 结构体 +var NewNSSF = &NSSFController{ + neInfoService: neService.NewNeInfo, +} + +// 网元NSSF +// +// PATH /NSSF +type NSSFController struct { + neInfoService *neService.NeInfo // 网元信息服务 +} + +// 在线订阅用户列表信息 +// +// GET /sub/list +// +// @Tags network_data/nssf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Online session user list information +// @Description Online session user list information +// @Router /neData/nssf/sub/list [get] +func (s NSSFController) SubUserList(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + } + 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 + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("NSSF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.NSSFSubInfoList(neInfo) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + + c.JSON(200, resp.OkData(data)) +} + +// 可用AMF列表信息 +// +// GET /amf/list +// +// @Tags network_data/nssf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Online session user list information +// @Description Online session user list information +// @Router /neData/nssf/amf/list [get] +func (s NSSFController) AvailableList(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + } + 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 + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("NSSF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.NSSFAvailableAMFList(neInfo) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index d0a68959..2df1faab 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -100,7 +100,7 @@ func Setup(router *gin.Engine) { middleware.AuthorizeUser(nil), controller.NewNBState.List, ) - nbStateGroup.POST("/export", + nbStateGroup.GET("/export", middleware.AuthorizeUser(nil), controller.NewNBState.Export, ) @@ -118,7 +118,7 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewIMS.CDRRemove, ) - imsGroup.POST("/cdr/export", + imsGroup.GET("/cdr/export", middleware.AuthorizeUser(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewIMS.CDRExport, @@ -145,7 +145,7 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewSMSC.CDRRemove, ) - smscGroup.POST("/cdr/export", + smscGroup.GET("/cdr/export", middleware.AuthorizeUser(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewSMSC.CDRExport, @@ -164,7 +164,7 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewSMF.CDRRemove, ) - smfGroup.POST("/cdr/export", + smfGroup.GET("/cdr/export", middleware.AuthorizeUser(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewSMF.CDRExport, @@ -191,7 +191,7 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewAMF.UERemove, ) - amfGroup.POST("/ue/export", + amfGroup.GET("/ue/export", middleware.AuthorizeUser(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewAMF.UEExport, @@ -215,6 +215,29 @@ func Setup(router *gin.Engine) { ) } + // 网元N3IWF + n3iwfGroup := neDataGroup.Group("/n3iwf") + { + n3iwfGroup.GET("/sub/list", + middleware.AuthorizeUser(nil), + controller.NewN3IWF.SubUserList, + ) + } + + // 网元N3IWF + nssf := controller.NewNSSF + nssfGroup := neDataGroup.Group("/nssf") + { + nssfGroup.GET("/sub/list", + middleware.AuthorizeUser(nil), + nssf.SubUserList, + ) + nssfGroup.GET("/amf/list", + middleware.AuthorizeUser(nil), + nssf.AvailableList, + ) + } + // 备份数据 backupGroup := neDataGroup.Group("/backup") { @@ -452,7 +475,7 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewMME.UERemove, ) - mmeGroup.POST("/ue/export", + mmeGroup.GET("/ue/export", middleware.AuthorizeUser(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewMME.UEExport, diff --git a/src/modules/network_element/fetch_link/n3iwf.go b/src/modules/network_element/fetch_link/n3iwf.go new file mode 100644 index 00000000..598e4ef7 --- /dev/null +++ b/src/modules/network_element/fetch_link/n3iwf.go @@ -0,0 +1,64 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + "strings" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/fetch" + "be.ems/src/modules/network_element/model" +) + +// N3IWFSubInfoList N3IWF在线列表信息 +// +// 查询参数 {"imsi":"460302072701181"} +// +// 返回结果 {"rows":[],"total":0} +func N3IWFSubInfoList(neInfo model.NeInfo, data map[string]string) (map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/n3iwf/objectType/ueInfo", neInfo.IP, neInfo.Port) + // 查询参数拼接 + query := []string{} + if v, ok := data["imsi"]; ok && v != "" { + query = append(query, fmt.Sprintf("imsi=%s", v)) + } + if len(query) > 0 { + neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&")) + } + + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + logger.Warnf("N3IWFSubInfo Get \"%s\"", neUrl) + logger.Errorf("N3IWFSubInfo %s", err.Error()) + return nil, fmt.Errorf("NeService N3IWF API Error") + } + + // 序列化结果 + // { + // "data": [ + // { + // "activeTime": "2023-11-29 06:35:43", + // "imsi": "460302072701181", + // "nai": "0460302072701181@nai.epc.mnc030.mcc460.3gppnetwork.org", + // "regState": 1 + // } + // ] + // } + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("N3IWFSubInfo Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + resData["rows"] = v.([]any) + resData["total"] = len(v.([]any)) + delete(resData, "data") + } else { + resData["rows"] = []any{} + resData["total"] = 0 + } + return resData, nil +} diff --git a/src/modules/network_element/fetch_link/nssf.go b/src/modules/network_element/fetch_link/nssf.go new file mode 100644 index 00000000..c73a35d6 --- /dev/null +++ b/src/modules/network_element/fetch_link/nssf.go @@ -0,0 +1,95 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/fetch" + "be.ems/src/modules/network_element/model" +) + +// NSSFSubInfoList NSSF在线列表信息 +// +// 返回结果 {"rows":[],"total":0} +func NSSFSubInfoList(neInfo model.NeInfo) (map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/nssf/objectType/subscriptions", neInfo.IP, neInfo.Port) + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + logger.Warnf("NSSFSubInfo Get \"%s\"", neUrl) + logger.Errorf("NSSFSubInfo %s", err.Error()) + return nil, fmt.Errorf("NeService NSSF API Error") + } + + // 序列化结果 + // { + // "data": [ + // { + // "subscriptionId": "460302072701181", + // "event": "460302072701181", + // "nfNssaiAvailabilityUri": "0460302072701181@nai.epc.mnc030.mcc460.3gppnetwork.org" + // } + // ] + // } + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("NSSFSubInfo Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + resData["rows"] = v.([]any) + resData["total"] = len(v.([]any)) + delete(resData, "data") + } else { + resData["rows"] = []any{} + resData["total"] = 0 + } + return resData, nil +} + +// NSSFAvailableAMFList NSSF装载AMF信息 +// +// 返回结果 {"rows":[],"total":0} +func NSSFAvailableAMFList(neInfo model.NeInfo) (map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/nssf/objectType/availableAMFs", neInfo.IP, neInfo.Port) + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + logger.Warnf("NSSFAvailableAMFList Get \"%s\"", neUrl) + logger.Errorf("NSSFAvailableAMFList %s", err.Error()) + return nil, fmt.Errorf("NeService NSSF API Error") + } + + // 序列化结果 + // { + // "data": [ + // { + // "nfId": "001", + // "amfSetId": "001" + // }, + // { + // "nfId": "002", + // "amfSetId": "[001,002]" + // } + // ] + // } + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("NSSFAvailableAMFList Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + resData["rows"] = v.([]any) + resData["total"] = len(v.([]any)) + delete(resData, "data") + } else { + resData["rows"] = []any{} + resData["total"] = 0 + } + return resData, nil +} From b6d4879cb11ddbec66b12bb47c8191e33af5e88a Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:02:08 +0800 Subject: [PATCH 15/80] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E6=A8=A1=E5=9D=97=EF=BC=8C=E6=9A=82=E6=97=B6=E5=8F=AA?= =?UTF-8?q?=E6=9C=89=E9=82=AE=E4=BB=B6=E5=92=8Csmsc=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/notification/notification.go | 11 ++ src/modules/notification/service/email.go | 126 +++++++++++++++++ src/modules/notification/service/smsc.go | 164 ++++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 src/modules/notification/notification.go create mode 100644 src/modules/notification/service/email.go create mode 100644 src/modules/notification/service/smsc.go diff --git a/src/modules/notification/notification.go b/src/modules/notification/notification.go new file mode 100644 index 00000000..cda49a9c --- /dev/null +++ b/src/modules/notification/notification.go @@ -0,0 +1,11 @@ +package notification + +import ( + "be.ems/src/framework/logger" + "github.com/gin-gonic/gin" +) + +// 模块路由注册 +func Setup(router *gin.Engine) { + logger.Infof("开始加载 ====> notification 模块路由") +} diff --git a/src/modules/notification/service/email.go b/src/modules/notification/service/email.go new file mode 100644 index 00000000..d9a42add --- /dev/null +++ b/src/modules/notification/service/email.go @@ -0,0 +1,126 @@ +package service + +import ( + "bytes" + "crypto/tls" + "fmt" + ht "html/template" + "strings" + "time" + + "github.com/wneessen/go-mail" + + "be.ems/src/framework/config" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/parse" + neDataModel "be.ems/src/modules/network_data/model" +) + +// EmailAlarm 发告警邮件 +func EmailAlarm(a neDataModel.Alarm, neIP string) error { + emailList := fmt.Sprint(config.Get("notification.email.list")) + if len(emailList) == 0 { + return fmt.Errorf("email list is empty") + } + + // 模板 + htmlBodyTemplate := ` + Alarm information +

Sequence: {{.AlarmSeq}}

+

NE Name: {{.NeName}}

+

NE IP: {{.NeIp}}

+

Title: {{.AlarmTitle}}

+

Severity: {{.OrigSeverity}}

+

Event Time: {{.AlarmTime}}

+

Alarm Status: {{.AlarmStatus}}

+ Automatic sent by OMC, please do not reply! + ` + htmlTpl, err := ht.New("htmltpl").Parse(htmlBodyTemplate) + if err != nil { + return fmt.Errorf("EmailAlarm Parse alarmId:%s fail %s", a.AlarmId, err.Error()) + } + // 参数值 + data := map[string]any{ + "AlarmSeq": a.AlarmSeq, + "NeName": a.NeName, + "NeIp": neIP, + "AlarmTitle": a.AlarmTitle, + "OrigSeverity": a.OrigSeverity, + "AlarmTime": date.ParseDateToStr(a.EventTime, time.RFC3339), + "AlarmStatus": a.AlarmStatus, + } + buffer := bytes.NewBuffer(nil) + if err := htmlTpl.Execute(buffer, data); err != nil { + return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error()) + } + htmlStr := buffer.String() + + // 发送邮件 + err = EmailSendHTML(htmlStr, strings.Split(emailList, ",")) + if err != nil { + return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error()) + } + return err +} + +// EmailSendHTML 发送HTML邮件 +func EmailSendHTML(htmlStr string, toEmailArr []string) error { + // QQ 邮箱: + // SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25) + // 163 邮箱: + // SMTP 服务器地址:smtp.163.com(端口:25) + // host := "mail.agrandtech.com" + // port := 25 + // userName := "smtpext@agrandtech.com" + // password := "1000smtp@omc!" + + emailConf := config.Get("notification.email").(map[string]any) + enable := parse.Boolean(emailConf["enable"]) + if !enable { + return fmt.Errorf("email notification not enable") + } + title := fmt.Sprint(emailConf["title"]) + smtp := fmt.Sprint(emailConf["smtp"]) + port := parse.Number(emailConf["port"]) + user := fmt.Sprint(emailConf["user"]) + password := fmt.Sprint(emailConf["password"]) + + message := mail.NewMsg() + // 发件人 + if err := message.From(user); err != nil { + return fmt.Errorf("failed to set From address: %s", err) + } + // 收件人 + hasTo := false + for _, v := range toEmailArr { + if err := message.AddTo(v); err != nil { + logger.Errorf("failed to set To address: %v %s", v, err) + continue + } + hasTo = true + } + if !hasTo { + return fmt.Errorf("failed to set To address not has") + } + // 邮件主题 + message.Subject(title) + // 邮件HTML内容 + message.SetBodyString(mail.TypeTextHTML, htmlStr) + // 连接到邮件SMTP服务器 + client, err := mail.NewClient(smtp, + mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover), + mail.WithUsername(user), + mail.WithPort(int(port)), + mail.WithPassword(password), + mail.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}), + ) + if err != nil { + return fmt.Errorf("failed to create mail client: %s", err) + } + // 发送 + if err := client.DialAndSend(message); err != nil { + return fmt.Errorf("failed to send mail: %s", err) + } + return nil +} diff --git a/src/modules/notification/service/smsc.go b/src/modules/notification/service/smsc.go new file mode 100644 index 00000000..be039b31 --- /dev/null +++ b/src/modules/notification/service/smsc.go @@ -0,0 +1,164 @@ +package service + +import ( + "bytes" + "fmt" + "strings" + tt "text/template" + "time" + + "github.com/linxGnu/gosmpp" + "github.com/linxGnu/gosmpp/data" + "github.com/linxGnu/gosmpp/pdu" + + "be.ems/src/framework/config" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/parse" + neDataModel "be.ems/src/modules/network_data/model" +) + +var smscSession *gosmpp.Session + +// connSM 连接smsc +func connSM() *gosmpp.Session { + if smscSession != nil { + return smscSession + } + smscAddr := fmt.Sprint(config.Get("notification.smsc.addr")) + systemType := fmt.Sprint(config.Get("notification.smsc.systemtype")) + systemID := fmt.Sprint(config.Get("notification.smsc.systemid")) + password := fmt.Sprint(config.Get("notification.smsc.password")) + // 建立连接 + session, err := gosmpp.NewSession( + gosmpp.TXConnector(gosmpp.NonTLSDialer, gosmpp.Auth{ + SMSC: smscAddr, + SystemID: systemID, + Password: password, + SystemType: systemType, + }), + gosmpp.Settings{ + ReadTimeout: 2 * time.Second, + OnSubmitError: func(_ pdu.PDU, err error) { + logger.Errorf("failed to smpp submit error: %s", err.Error()) + }, + OnRebindingError: func(err error) { + logger.Errorf("failed to smpp rebinding error: %s", err.Error()) + }, + }, -1) + if err != nil { + logger.Errorf("failed to create smpp new session error: %s", err.Error()) + return nil + } + // defer session.Close() + smscSession = session + return smscSession +} + +// newSubmitSM 构建短信提交 +func newSubmitSM(destSM string, message string) (*pdu.SubmitSM, error) { + dataCoding := parse.Number(config.Get("notification.smsc.coding")) + enc := data.FromDataCoding(byte(dataCoding)) + srcSM := fmt.Sprint(config.Get("notification.smsc.servicenumber")) + // 源地址 + srcAddr := pdu.NewAddress() + srcAddr.SetTon(5) + srcAddr.SetNpi(0) + err := srcAddr.SetAddress(srcSM) + if err != nil { + return nil, err + } + destAddr := pdu.NewAddress() + destAddr.SetTon(1) + destAddr.SetNpi(1) + err = destAddr.SetAddress(destSM) + if err != nil { + return nil, err + } + // build up submitSM + submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM) + submitSM.SourceAddr = srcAddr + submitSM.DestAddr = destAddr + if err = submitSM.Message.SetMessageWithEncoding(message, enc); err != nil { + return nil, err + } + submitSM.ProtocolID = 0 + submitSM.RegisteredDelivery = 1 + submitSM.ReplaceIfPresentFlag = 0 + submitSM.EsmClass = 0 + return submitSM, nil +} + +// SMSCAlarm 发告警短信 +func SMSCAlarm(a neDataModel.Alarm, neIP string) error { + mobileList := fmt.Sprint(config.Get("notification.smsc.list")) + if len(mobileList) == 0 { + return fmt.Errorf("smsc list is empty") + } + + // 模板 + textBodyTemplate := `Alarm Notification + Sequence: {{.AlarmSeq}}, + NE Name: {{.NeName}} + NE IP: {{.NeIp}} + Title: {{.AlarmTitle}} + Severity: {{.OrigSeverity}} + Event Time: {{.AlarmTime}} + Alarm Status: {{.AlarmStatus}} + Automatic sent by OMC, please do not reply!` + textTpl, err := tt.New("texttpl").Parse(textBodyTemplate) + if err != nil { + return fmt.Errorf("SMSCAlarm alarmId:%s fail %s", a.AlarmId, err.Error()) + } + // 参数值 + data := map[string]any{ + "AlarmSeq": a.AlarmSeq, + "NeName": a.NeName, + "NeIp": neIP, + "AlarmTitle": a.AlarmTitle, + "OrigSeverity": a.OrigSeverity, + "AlarmTime": date.ParseDateToStr(a.EventTime, time.RFC3339), + "AlarmStatus": a.AlarmStatus, + } + buffer := bytes.NewBuffer(nil) + if err := textTpl.Execute(buffer, data); err != nil { + return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error()) + } + textStr := buffer.String() + + // 发送短信 + err = SMSCSendText(textStr, strings.Split(mobileList, ",")) + if err != nil { + return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error()) + } + return err +} + +// SMSCSendText 发送文本短信 +func SMSCSendText(textStr string, toMobileArr []string) error { + enable := parse.Boolean(config.Get("notification.smsc.enable")) + if !enable { + return fmt.Errorf("smsc notification not enable") + } + sm := connSM() + if sm == nil { + return fmt.Errorf("smpp new session create failed") + } + + errArr := []string{} + for _, v := range toMobileArr { + submitSM, err := newSubmitSM(v, textStr) + if err != nil { + errArr = append(errArr, err.Error()) + continue + } + if err = sm.Transceiver().Submit(submitSM); err != nil { + errArr = append(errArr, err.Error()) + continue + } + } + if len(errArr) > 0 { + return fmt.Errorf("%s", strings.Join(errArr, ",")) + } + return nil +} From 40f178a1cdb6afb0766eda237e6f64b01d1b6fb0 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:04:41 +0800 Subject: [PATCH 16/80] =?UTF-8?q?fix:=20udm=E5=A4=84=E7=90=86=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E8=BF=94=E5=9B=9E=E5=80=BC=E7=BB=9F=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/controller/all_nb_state.go | 4 ++-- src/modules/network_data/controller/udm_auth.go | 6 +++--- src/modules/network_data/controller/udm_sub.go | 6 +++--- src/modules/network_data/controller/udm_voip.go | 6 +++--- src/modules/network_data/controller/udm_volte_ims.go | 6 +++--- src/modules/network_data/repository/udm_auth.go | 6 +++--- src/modules/network_data/repository/udm_sub.go | 6 +++--- src/modules/network_data/repository/udm_voip.go | 6 +++--- src/modules/network_data/repository/udm_volte_ims.go | 6 +++--- src/modules/network_data/service/udm_auth.go | 2 +- src/modules/network_data/service/udm_sub.go | 2 +- src/modules/network_data/service/udm_voip.go | 2 +- src/modules/network_data/service/udm_volte_ims.go | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/modules/network_data/controller/all_nb_state.go b/src/modules/network_data/controller/all_nb_state.go index 2813d405..5c00ec47 100644 --- a/src/modules/network_data/controller/all_nb_state.go +++ b/src/modules/network_data/controller/all_nb_state.go @@ -72,7 +72,7 @@ func (s NBStateController) List(c *gin.Context) { // 历史记录列表导出 // -// POST /export +// GET /export // // @Tags network_data/amf,network_data/mme // @Accept json @@ -82,7 +82,7 @@ func (s NBStateController) List(c *gin.Context) { // @Security TokenAuth // @Summary Base Station Status List Export // @Description Base Station Status List Export -// @Router /nb-state/export [post] +// @Router /nb-state/export [get] func (s NBStateController) Export(c *gin.Context) { language := reqctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 diff --git a/src/modules/network_data/controller/udm_auth.go b/src/modules/network_data/controller/udm_auth.go index f2e62e98..900245ef 100644 --- a/src/modules/network_data/controller/udm_auth.go +++ b/src/modules/network_data/controller/udm_auth.go @@ -77,8 +77,8 @@ func (s *UDMAuthController) ResetData(c *gin.Context) { // @Router /neData/udm/auth/list [get] func (s *UDMAuthController) List(c *gin.Context) { query := reqctx.QueryMap(c) - total, rows := s.udmAuthService.FindByPage(query) - c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows})) + rows, total := s.udmAuthService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } // UDM鉴权用户信息 @@ -478,7 +478,7 @@ func (s *UDMAuthController) Export(c *gin.Context) { } query := reqctx.QueryMap(c) - total, rows := s.udmAuthService.FindByPage(query) + rows, total := s.udmAuthService.FindByPage(query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) diff --git a/src/modules/network_data/controller/udm_sub.go b/src/modules/network_data/controller/udm_sub.go index 6a1d40a1..1772ddae 100644 --- a/src/modules/network_data/controller/udm_sub.go +++ b/src/modules/network_data/controller/udm_sub.go @@ -77,8 +77,8 @@ func (s *UDMSubController) ResetData(c *gin.Context) { // @Router /neData/udm/sub/list [get] func (s *UDMSubController) List(c *gin.Context) { query := reqctx.QueryMap(c) - total, rows := s.udmSubService.FindByPage(query) - c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows})) + rows, total := s.udmSubService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } // UDM签约用户信息 @@ -484,7 +484,7 @@ func (s *UDMSubController) Export(c *gin.Context) { } query := reqctx.QueryMap(c) - total, rows := s.udmSubService.FindByPage(query) + rows, total := s.udmSubService.FindByPage(query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) diff --git a/src/modules/network_data/controller/udm_voip.go b/src/modules/network_data/controller/udm_voip.go index 933092fb..40768d25 100644 --- a/src/modules/network_data/controller/udm_voip.go +++ b/src/modules/network_data/controller/udm_voip.go @@ -76,8 +76,8 @@ func (s *UDMVOIPController) ResetData(c *gin.Context) { // @Router /neData/udm/voip/list [get] func (s *UDMVOIPController) List(c *gin.Context) { query := reqctx.QueryMap(c) - total, rows := s.udmVOIPService.FindByPage(query) - c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows})) + rows, total := s.udmVOIPService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } // UDMVOIP用户信息 @@ -416,7 +416,7 @@ func (s *UDMVOIPController) Export(c *gin.Context) { } query := reqctx.QueryMap(c) - total, rows := s.udmVOIPService.FindByPage(query) + rows, total := s.udmVOIPService.FindByPage(query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) diff --git a/src/modules/network_data/controller/udm_volte_ims.go b/src/modules/network_data/controller/udm_volte_ims.go index 1a034553..881c0593 100644 --- a/src/modules/network_data/controller/udm_volte_ims.go +++ b/src/modules/network_data/controller/udm_volte_ims.go @@ -76,8 +76,8 @@ func (s *UDMVolteIMSController) ResetData(c *gin.Context) { // @Router /neData/udm/volte-ims/list [get] func (s *UDMVolteIMSController) List(c *gin.Context) { query := reqctx.QueryMap(c) - total, rows := s.udmVolteIMSService.FindByPage(query) - c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows})) + rows, total := s.udmVolteIMSService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } // UDMVolteIMS用户信息 @@ -462,7 +462,7 @@ func (s *UDMVolteIMSController) Export(c *gin.Context) { } query := reqctx.QueryMap(c) - total, rows := s.udmVolteIMSService.FindByPage(query) + rows, total := s.udmVolteIMSService.FindByPage(query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) diff --git a/src/modules/network_data/repository/udm_auth.go b/src/modules/network_data/repository/udm_auth.go index 4a9565a5..c665b9de 100644 --- a/src/modules/network_data/repository/udm_auth.go +++ b/src/modules/network_data/repository/udm_auth.go @@ -27,7 +27,7 @@ func (r *UDMAuthUser) ClearAndInsert(neId string, uArr []model.UDMAuthUser) int6 } // SelectPage 根据条件分页查询 -func (r *UDMAuthUser) SelectPage(query map[string]string) (int64, []model.UDMAuthUser) { +func (r *UDMAuthUser) SelectPage(query map[string]string) ([]model.UDMAuthUser, int64) { tx := db.DB("").Model(&model.UDMAuthUser{}) // 查询条件拼接 if v, ok := query["imsi"]; ok && v != "" { @@ -48,7 +48,7 @@ func (r *UDMAuthUser) SelectPage(query map[string]string) (int64, []model.UDMAut // 查询数量 长度为0直接返回 if err := tx.Count(&total).Error; err != nil || total <= 0 { - return total, rows + return rows, total } // 分页 @@ -73,7 +73,7 @@ func (r *UDMAuthUser) SelectPage(query map[string]string) (int64, []model.UDMAut logger.Errorf("query err => %v", err) } - return total, rows + return rows, total } // SelectList 根据实体查询 diff --git a/src/modules/network_data/repository/udm_sub.go b/src/modules/network_data/repository/udm_sub.go index 5e7d2a14..2a939045 100644 --- a/src/modules/network_data/repository/udm_sub.go +++ b/src/modules/network_data/repository/udm_sub.go @@ -27,7 +27,7 @@ func (r *UDMSubUser) ClearAndInsert(neId string, u []model.UDMSubUser) int64 { } // SelectPage 根据条件分页查询字典类型 -func (r *UDMSubUser) SelectPage(query map[string]string) (int64, []model.UDMSubUser) { +func (r *UDMSubUser) SelectPage(query map[string]string) ([]model.UDMSubUser, int64) { tx := db.DB("").Model(&model.UDMSubUser{}) // 查询条件拼接 if v, ok := query["imsi"]; ok && v != "" { @@ -51,7 +51,7 @@ func (r *UDMSubUser) SelectPage(query map[string]string) (int64, []model.UDMSubU // 查询数量 长度为0直接返回 if err := tx.Count(&total).Error; err != nil || total <= 0 { - return total, rows + return rows, total } // 分页 @@ -76,7 +76,7 @@ func (r *UDMSubUser) SelectPage(query map[string]string) (int64, []model.UDMSubU logger.Errorf("query err => %v", err) } - return total, rows + return rows, total } // SelectList 根据实体查询 diff --git a/src/modules/network_data/repository/udm_voip.go b/src/modules/network_data/repository/udm_voip.go index e0fe4a93..ada692aa 100644 --- a/src/modules/network_data/repository/udm_voip.go +++ b/src/modules/network_data/repository/udm_voip.go @@ -27,7 +27,7 @@ func (r UDMVOIPUser) ClearAndInsert(neId string, uArr []model.UDMVOIPUser) int64 } // SelectPage 根据条件分页查询 -func (r UDMVOIPUser) SelectPage(query map[string]string) (int64, []model.UDMVOIPUser) { +func (r UDMVOIPUser) SelectPage(query map[string]string) ([]model.UDMVOIPUser, int64) { tx := db.DB("").Model(&model.UDMVOIPUser{}) // 查询条件拼接 if v, ok := query["username"]; ok && v != "" { @@ -48,7 +48,7 @@ func (r UDMVOIPUser) SelectPage(query map[string]string) (int64, []model.UDMVOIP // 查询数量 长度为0直接返回 if err := tx.Count(&total).Error; err != nil || total <= 0 { - return total, rows + return rows, total } // 分页 @@ -75,7 +75,7 @@ func (r UDMVOIPUser) SelectPage(query map[string]string) (int64, []model.UDMVOIP logger.Errorf("query err => %v", err) } - return total, rows + return rows, total } // SelectList 根据实体查询 diff --git a/src/modules/network_data/repository/udm_volte_ims.go b/src/modules/network_data/repository/udm_volte_ims.go index b4fc935d..984ccc4c 100644 --- a/src/modules/network_data/repository/udm_volte_ims.go +++ b/src/modules/network_data/repository/udm_volte_ims.go @@ -27,7 +27,7 @@ func (r UDMVolteIMSUser) ClearAndInsert(neId string, uArr []model.UDMVolteIMSUse } // SelectPage 根据条件分页查询 -func (r UDMVolteIMSUser) SelectPage(query map[string]string) (int64, []model.UDMVolteIMSUser) { +func (r UDMVolteIMSUser) SelectPage(query map[string]string) ([]model.UDMVolteIMSUser, int64) { tx := db.DB("").Model(&model.UDMVolteIMSUser{}) // 查询条件拼接 if v, ok := query["imsi"]; ok && v != "" { @@ -57,7 +57,7 @@ func (r UDMVolteIMSUser) SelectPage(query map[string]string) (int64, []model.UDM // 查询数量 长度为0直接返回 if err := tx.Count(&total).Error; err != nil || total <= 0 { - return total, rows + return rows, total } // 分页 @@ -84,7 +84,7 @@ func (r UDMVolteIMSUser) SelectPage(query map[string]string) (int64, []model.UDM logger.Errorf("query err => %v", err) } - return total, rows + return rows, total } // SelectList 根据实体查询 diff --git a/src/modules/network_data/service/udm_auth.go b/src/modules/network_data/service/udm_auth.go index 73e94c7d..c8fcdc60 100644 --- a/src/modules/network_data/service/udm_auth.go +++ b/src/modules/network_data/service/udm_auth.go @@ -99,7 +99,7 @@ func (r *UDMAuthUser) ParseInfo(imsi, neId string, data map[string]string) model } // FindByPage 分页查询数据库 -func (r *UDMAuthUser) FindByPage(query map[string]string) (int64, []model.UDMAuthUser) { +func (r *UDMAuthUser) FindByPage(query map[string]string) ([]model.UDMAuthUser, int64) { return r.udmAuthRepository.SelectPage(query) } diff --git a/src/modules/network_data/service/udm_sub.go b/src/modules/network_data/service/udm_sub.go index 8da74756..76cc5c76 100644 --- a/src/modules/network_data/service/udm_sub.go +++ b/src/modules/network_data/service/udm_sub.go @@ -180,7 +180,7 @@ func (r *UDMSubUser) ParseInfo(imsi, neId string, data map[string]string) model. } // FindByPage 分页查询数据库 -func (r *UDMSubUser) FindByPage(query map[string]string) (int64, []model.UDMSubUser) { +func (r *UDMSubUser) FindByPage(query map[string]string) ([]model.UDMSubUser, int64) { return r.udmSubRepository.SelectPage(query) } diff --git a/src/modules/network_data/service/udm_voip.go b/src/modules/network_data/service/udm_voip.go index 10c95d92..e03eed9c 100644 --- a/src/modules/network_data/service/udm_voip.go +++ b/src/modules/network_data/service/udm_voip.go @@ -89,7 +89,7 @@ func (r UDMVOIPUser) ParseInfo(neId string, data map[string]string) model.UDMVOI } // FindByPage 分页查询数据库 -func (r UDMVOIPUser) FindByPage(query map[string]string) (int64, []model.UDMVOIPUser) { +func (r UDMVOIPUser) FindByPage(query map[string]string) ([]model.UDMVOIPUser, int64) { return r.udmVOIPRepository.SelectPage(query) } diff --git a/src/modules/network_data/service/udm_volte_ims.go b/src/modules/network_data/service/udm_volte_ims.go index a489933e..3d3032b9 100644 --- a/src/modules/network_data/service/udm_volte_ims.go +++ b/src/modules/network_data/service/udm_volte_ims.go @@ -110,7 +110,7 @@ func (r UDMVolteIMSUser) ParseInfo(neId string, data map[string]string) model.UD } // FindByPage 分页查询数据库 -func (r UDMVolteIMSUser) FindByPage(query map[string]string) (int64, []model.UDMVolteIMSUser) { +func (r UDMVolteIMSUser) FindByPage(query map[string]string) ([]model.UDMVolteIMSUser, int64) { return r.udmVolteIMSRepository.SelectPage(query) } From 24a91572898244e02716bb83ee9728e62ae4d7bb Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:06:25 +0800 Subject: [PATCH 17/80] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Emml=E5=88=B0?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/tool/controller/mml.go | 98 +++++++++++++++++++ src/modules/tool/model/mml_subscriber.go | 19 ++++ src/modules/tool/model/mml_system.go | 20 ++++ src/modules/tool/repository/mml_subscriber.go | 44 +++++++++ src/modules/tool/repository/mml_system.go | 44 +++++++++ src/modules/tool/service/mml_subscriber.go | 21 ++++ src/modules/tool/service/mml_system.go | 21 ++++ src/modules/tool/tool.go | 19 ++++ 8 files changed, 286 insertions(+) create mode 100644 src/modules/tool/controller/mml.go create mode 100644 src/modules/tool/model/mml_subscriber.go create mode 100644 src/modules/tool/model/mml_system.go create mode 100644 src/modules/tool/repository/mml_subscriber.go create mode 100644 src/modules/tool/repository/mml_system.go create mode 100644 src/modules/tool/service/mml_subscriber.go create mode 100644 src/modules/tool/service/mml_system.go diff --git a/src/modules/tool/controller/mml.go b/src/modules/tool/controller/mml.go new file mode 100644 index 00000000..079ae666 --- /dev/null +++ b/src/modules/tool/controller/mml.go @@ -0,0 +1,98 @@ +package controller + +import ( + "fmt" + "strings" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + neService "be.ems/src/modules/network_element/service" + "be.ems/src/modules/tool/service" + + "github.com/gin-gonic/gin" +) + +// 实例化控制层 MMLController 结构体 +var NewMML = &MMLController{ + neInfoService: neService.NewNeInfo, + mmlSystemService: service.NewMMLSystem, + mmlSubscriberService: service.NewMMLSubscriber, +} + +// MML 网元MML +// +// PATH /tool/mml +type MMLController struct { + neInfoService *neService.NeInfo // 网元信息服务 + mmlSystemService *service.MMLSystem + mmlSubscriberService *service.MMLSubscriber +} + +// SystemList MML网元列表 +// +// GET /system/list +func (s MMLController) SystemList(c *gin.Context) { + query := reqctx.QueryMap(c) + rows, total := s.mmlSystemService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} + +// SubscriberList MML网元UDM列表 +// +// GET /subscriber/list +func (s MMLController) SubscriberList(c *gin.Context) { + query := reqctx.QueryMap(c) + rows, total := s.mmlSubscriberService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} + +// Command MML命令执行 +// +// POST /command +func (s MMLController) Command(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body struct { + NeType string `json:"neType" binding:"required"` // 网元类型 + NeId string `json:"neId" binding:"required"` // 网元ID + Command []string `json:"command" binding:"required"` // 命令 + Type string `json:"type" binding:"required,oneof=General Standard"` // 类型UPF标准版 General Standard + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + // 网元主机的Telnet客户端 + num := 1 + if body.Type == "Standard" { + num = 2 + } + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, num) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + if body.Type == "Standard" { + telnetClient.WindowChange(1024, 1024) + } + // 发送MML + result := []string{} + for _, v := range body.Command { + output, err := telnetClient.RunCMD(v + "\r\r") + if err != nil { + result = append(result, err.Error()) + continue + } + result = append(result, strings.TrimSpace(output)) + } + c.JSON(200, resp.OkData(result)) +} diff --git a/src/modules/tool/model/mml_subscriber.go b/src/modules/tool/model/mml_subscriber.go new file mode 100644 index 00000000..a514c922 --- /dev/null +++ b/src/modules/tool/model/mml_subscriber.go @@ -0,0 +1,19 @@ +package model + +// MMLSubscriber MML网元UDM命令 +type MMLSubscriber struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + Category string `json:"category" gorm:"column:category"` + CatDisplay string `json:"catDisplay" gorm:"column:cat_display"` + Operation string `json:"operation" gorm:"column:operation"` + Object string `json:"object" gorm:"column:object"` + MmlDisplay string `json:"mmlDisplay" gorm:"column:mml_display"` + ParamJson string `json:"paramJson" gorm:"column:param_json"` + Status string `json:"status" gorm:"column:status"` // 激活: Active 未激活: Inactive +} + +// TableName 表名称 +func (*MMLSubscriber) TableName() string { + return "mml_subscriber" +} diff --git a/src/modules/tool/model/mml_system.go b/src/modules/tool/model/mml_system.go new file mode 100644 index 00000000..7ad0a6d1 --- /dev/null +++ b/src/modules/tool/model/mml_system.go @@ -0,0 +1,20 @@ +package model + +// MMLSystem MML网元命令 +type MMLSystem struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + Category string `json:"category" gorm:"column:category"` + CatDisplay string `json:"catDisplay" gorm:"column:cat_display"` + Operation string `json:"operation" gorm:"column:operation"` // 操作行为 + Object string `json:"object" gorm:"column:object"` // 操作对象 + MmlDisplay string `json:"mmlDisplay" gorm:"column:mml_display"` // 显示 + ObjectType string `json:"objectType" gorm:"column:object_type"` + ParamJson string `json:"paramJson" gorm:"column:param_json"` + Status string `json:"status" gorm:"column:status"` // 激活: Active 未激活: Inactive +} + +// TableName 表名称 +func (*MMLSystem) TableName() string { + return "mml_system" +} diff --git a/src/modules/tool/repository/mml_subscriber.go b/src/modules/tool/repository/mml_subscriber.go new file mode 100644 index 00000000..a899c41f --- /dev/null +++ b/src/modules/tool/repository/mml_subscriber.go @@ -0,0 +1,44 @@ +package repository + +import ( + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/tool/model" +) + +// 实例化数据层 MMLSubscriber 结构体 +var NewMMLSubscriber = &MMLSubscriber{} + +// MMLSubscriber MML网元UDM命令 数据层处理 +type MMLSubscriber struct{} + +// SelectByPage 分页查询集合 +func (r MMLSubscriber) SelectByPage(query map[string]string) ([]model.MMLSubscriber, int64) { + tx := db.DB("").Model(&model.MMLSubscriber{}) + // 查询条件拼接 + if v, ok := query["neType"]; ok && v != "" { + tx = tx.Where("ne_type = ?", v) + } + if v, ok := query["status"]; ok && v != "" { + tx = tx.Where("status = ?", v) + } + + // 查询结果 + var total int64 = 0 + rows := []model.MMLSubscriber{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 查询数据分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error + if err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows, total + } + return rows, total +} diff --git a/src/modules/tool/repository/mml_system.go b/src/modules/tool/repository/mml_system.go new file mode 100644 index 00000000..834590b1 --- /dev/null +++ b/src/modules/tool/repository/mml_system.go @@ -0,0 +1,44 @@ +package repository + +import ( + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/tool/model" +) + +// 实例化数据层 MMLSystem 结构体 +var NewMMLSystem = &MMLSystem{} + +// MMLSystem MML网元命令 数据层处理 +type MMLSystem struct{} + +// SelectByPage 分页查询集合 +func (r MMLSystem) SelectByPage(query map[string]string) ([]model.MMLSystem, int64) { + tx := db.DB("").Model(&model.MMLSystem{}) + // 查询条件拼接 + if v, ok := query["neType"]; ok && v != "" { + tx = tx.Where("ne_type = ?", v) + } + if v, ok := query["status"]; ok && v != "" { + tx = tx.Where("status = ?", v) + } + + // 查询结果 + var total int64 = 0 + rows := []model.MMLSystem{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 查询数据分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error + if err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows, total + } + return rows, total +} diff --git a/src/modules/tool/service/mml_subscriber.go b/src/modules/tool/service/mml_subscriber.go new file mode 100644 index 00000000..8b4c28b3 --- /dev/null +++ b/src/modules/tool/service/mml_subscriber.go @@ -0,0 +1,21 @@ +package service + +import ( + "be.ems/src/modules/tool/model" + "be.ems/src/modules/tool/repository" +) + +// 实例化数据层 MMLSubscriber 结构体 +var NewMMLSubscriber = &MMLSubscriber{ + mmlSubscriberRepository: repository.NewMMLSubscriber, +} + +// MMLSubscriber MML网元命令 服务层处理 +type MMLSubscriber struct { + mmlSubscriberRepository *repository.MMLSubscriber +} + +// FindByPage 分页查询列表数据 +func (s MMLSubscriber) FindByPage(query map[string]string) ([]model.MMLSubscriber, int64) { + return s.mmlSubscriberRepository.SelectByPage(query) +} diff --git a/src/modules/tool/service/mml_system.go b/src/modules/tool/service/mml_system.go new file mode 100644 index 00000000..021c0439 --- /dev/null +++ b/src/modules/tool/service/mml_system.go @@ -0,0 +1,21 @@ +package service + +import ( + "be.ems/src/modules/tool/model" + "be.ems/src/modules/tool/repository" +) + +// 实例化数据层 MMLSystem 结构体 +var NewMMLSystem = &MMLSystem{ + mmlSystemRepository: repository.NewMMLSystem, +} + +// MMLSystem MML网元命令 服务层处理 +type MMLSystem struct { + mmlSystemRepository *repository.MMLSystem +} + +// FindByPage 分页查询列表数据 +func (s MMLSystem) FindByPage(query map[string]string) ([]model.MMLSystem, int64) { + return s.mmlSystemRepository.SelectByPage(query) +} diff --git a/src/modules/tool/tool.go b/src/modules/tool/tool.go index ce37e8c1..de8243d6 100644 --- a/src/modules/tool/tool.go +++ b/src/modules/tool/tool.go @@ -54,4 +54,23 @@ func Setup(router *gin.Engine) { controller.NewPing.Run, ) } + + // MML 网元MML + mml := controller.NewMML + mmlGroup := router.Group("/tool/mml") + { + mmlGroup.GET("/system/list", + middleware.AuthorizeUser(nil), + mml.SystemList, + ) + mmlGroup.GET("/subscriber/list", + middleware.AuthorizeUser(nil), + mml.SubscriberList, + ) + mmlGroup.POST("/command", + middleware.AuthorizeUser(nil), + mml.Command, + ) + } + } From 88a6375b1816f34e9453c849e5ad15d688df4c36 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:07:16 +0800 Subject: [PATCH 18/80] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Eoam=E5=AF=B9?= =?UTF-8?q?=E5=A4=96=E5=BC=80=E6=94=BE=E6=97=A0=E9=99=90=E5=88=B6=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/controller/api_rest.go | 672 +++++++++++++++++++++++++ src/modules/oam/oam.go | 40 ++ src/modules/oam/service/kpi.go | 236 +++++++++ src/modules/oam/service/nb_state.go | 67 +++ 4 files changed, 1015 insertions(+) create mode 100644 src/modules/oam/controller/api_rest.go create mode 100644 src/modules/oam/oam.go create mode 100644 src/modules/oam/service/kpi.go create mode 100644 src/modules/oam/service/nb_state.go diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go new file mode 100644 index 00000000..1da4e89a --- /dev/null +++ b/src/modules/oam/controller/api_rest.go @@ -0,0 +1,672 @@ +package controller + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/tsmask/go-oam" + + "be.ems/src/framework/logger" + "be.ems/src/framework/resp" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/parse" + neFetchlink "be.ems/src/modules/network_element/fetch_link" + neModel "be.ems/src/modules/network_element/model" + neService "be.ems/src/modules/network_element/service" + oamService "be.ems/src/modules/oam/service" +) + +// NewAPIRest 实例化控制层 +var NewAPIRest = &APIRestController{} + +// APIRestController 北向定义 控制层处理 +// +// PATH /api/rest +type APIRestController struct{} + +// ResolveAlarm 接收告警 +// +// POST /faultManagement/v1/elementType/:elementTypeValue/objectType/alarms +func (s APIRestController) ResolveAlarm(c *gin.Context) { + var body []struct { + AlarmSeq int `json:"alarmSeq"` + AlarmId string `json:"alarmId"` + NeId string `json:"neId"` // 收到实际是rmUID + AlarmCode int `json:"alarmCode"` + AlarmTitle string `json:"alarmTitle"` + EventTime string `json:"eventTime"` + AlarmType string `json:"alarmType"` + OrigSeverity string `json:"origSeverity"` + PerceivedSeverity string `json:"perceivedSeverity"` + PVFlag string `json:"pvFlag"` + NeName string `json:"neName"` + NeType string `json:"neType"` + ObjectUid string `json:"objectUid"` + ObjectName string `json:"objectName"` + ObjectType string `json:"objectType"` + LocationInfo string `json:"locationInfo"` + Province string `json:"province"` + AlarmStatus int `json:"alarmStatus"` + SpecificProblem string `json:"specificProblem"` + SpecificProblemID string `json:"specificProblemID"` + AddInfo string `json:"addInfo"` + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + elementTypeValue := c.Param("elementTypeValue") + + // alarmTypeValue 映射值 + alarmTypeValue := func(str string) string { + arr := []string{ + oam.ALARM_TYPE_COMMUNICATION_ALARM, + oam.ALARM_TYPE_EQUIPMENT_ALARM, + oam.ALARM_TYPE_PROCESSING_FAILURE, + oam.ALARM_TYPE_ENVIRONMENTAL_ALARM, + oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM, + } + for k, v := range arr { + if v == str { + return v + } + if fmt.Sprint(k+1) == str { + return v + } + } + return str + } + + // origSeverityValue 映射值 + origSeverityValue := func(str string) string { + arr := []string{ + oam.ALARM_SEVERITY_CRITICAL, + oam.ALARM_SEVERITY_MAJOR, + oam.ALARM_SEVERITY_MINOR, + oam.ALARM_SEVERITY_WARNING, + oam.ALARM_SEVERITY_EVENT, + } + for k, v := range arr { + if v == str { + return v + } + if fmt.Sprint(k+1) == str { + return v + } + } + return str + } + + // alarmStatusValue 映射值 + alarmStatusValue := func(value int) string { + arr := []string{ + oam.ALARM_STATUS_CLEAR, + oam.ALARM_STATUS_ACTIVE, + } + for k, v := range arr { + if k == value { + return v + } + } + return oam.ALARM_STATUS_ACTIVE + } + + alarmArr := make([]oam.Alarm, 0) + for _, v := range body { + if !strings.EqualFold(v.NeType, elementTypeValue) { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType")) + return + } + // 产生时间 + eventTime := date.ParseStrToDate(v.EventTime, time.RFC3339) + // 创建告警 + alarm := oam.Alarm{ + NeUid: v.NeId, // 网元唯一标识 + AlarmTime: eventTime.UnixMilli(), // 事件产生时间 + AlarmId: v.AlarmId, // 告警ID 唯一,清除时对应 + AlarmCode: v.AlarmCode, // 告警状态码 + AlarmType: alarmTypeValue(v.AlarmType), // 告警类型 + AlarmTitle: v.AlarmTitle, // 告警标题 + PerceivedSeverity: origSeverityValue(v.OrigSeverity), // 告警级别 + AlarmStatus: alarmStatusValue(v.AlarmStatus), // 告警状态 + SpecificProblem: v.SpecificProblem, // 告警问题原因 + SpecificProblemID: v.SpecificProblemID, // 告警问题原因ID + AddInfo: v.AddInfo, // 告警辅助信息 + LocationInfo: v.LocationInfo, // 告警定位信息 + } + alarmArr = append(alarmArr, alarm) + } + + errArr := make([]string, 0) + for _, alarm := range alarmArr { + if err := oamService.NewAlarm.Resolve(alarm); err != nil { + errArr = append(errArr, err.Error()) + } + } + + if len(errArr) > 0 { + c.JSON(200, resp.ErrData(errArr)) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// ResolveCDR 接收话单 +// +// POST /cdrManagement/v1/elementType/:elementTypeValue/objectType/cdrEvent +func (s APIRestController) ResolveCDR(c *gin.Context) { + var body struct { + NeType string `json:"neType" ` + NeName string `json:"neName" ` + RmUID string `json:"rmUID" ` + Timestamp int `json:"timestamp" ` + CDR map[string]any `json:"CDR" ` + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + elementTypeValue := c.Param("elementTypeValue") + if !strings.EqualFold(body.NeType, elementTypeValue) { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType")) + return + } + + recordTime := time.Now() + if body.Timestamp > 1e12 { + recordTime = time.UnixMilli(int64(body.Timestamp)) + } else if body.Timestamp > 1e9 { + recordTime = time.Unix(int64(body.Timestamp), 0) + } + // 创建CDR + cdr := oam.CDR{ + NeUid: body.RmUID, // 网元唯一标识 + RecordTime: recordTime.UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充 + Data: body.CDR, // 话单信息 + } + if err := oamService.NewCDR.Resolve(cdr); err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// ResolveKPI 接收KPI +// +// POST /performanceManagement/v1/elementType/:elementTypeValue/objectType/kpiReport/:index +func (s APIRestController) ResolveKPI(c *gin.Context) { + var body struct { + Timestamp string `json:"TimeStamp" binding:"required"` + Task struct { + Period struct { + StartTime string `json:"StartTime"` + EndTime string `json:"EndTime"` + } `json:"Period" binding:"required"` + NE struct { + NEName string `json:"NEName"` + RmUID string `json:"rmUID"` + NeType string `json:"NeType"` + KPIs []struct { + KPIID string `json:"KPIID"` + Value int64 `json:"Value"` + Err string `json:"Err"` + } `json:"KPIs" binding:"required"` + } `json:"NE" binding:"required"` + } `json:"Task" binding:"required"` + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + elementTypeValue := c.Param("elementTypeValue") + if !strings.EqualFold(body.Task.NE.NeType, elementTypeValue) { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType")) + return + } + // index := c.Param("index") + + timestamp := body.Timestamp + taskPeriod := body.Task.Period + taskNeKPIs := body.Task.NE.KPIs + // 时间数据处理 + receiverTime := date.ParseStrToDate(timestamp, date.YYYY_MM_DDTHH_MM_SSZ) + startTime := date.ParseStrToDate(taskPeriod.StartTime, date.YYYY_MM_DDTHH_MM_SSZ) + endTime := date.ParseStrToDate(taskPeriod.EndTime, date.YYYY_MM_DDTHH_MM_SSZ) + granularity := parse.Number(endTime.Sub(startTime).Seconds()) + // kpi data数据 + KpiValues := make(map[string]float64, 0) + for _, v := range taskNeKPIs { + KpiValues[v.KPIID] = float64(v.Value) + } + + // 创建KPI + kpi := oam.KPI{ + NeUid: body.Task.NE.RmUID, // 网元唯一标识 + RecordTime: receiverTime.UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充 + Granularity: granularity, // 时间间隔 5/10/.../60/300 (秒) + Data: KpiValues, // 指标信息 + } + if err := oamService.NewKPI.Resolve(kpi); err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// ResolveNBState 接收基站状态变更 +// +// POST /ueManagement/v1/elementType/:elementTypeValue/objectType/nbState +func (s APIRestController) ResolveNBState(c *gin.Context) { + var body struct { + NeType string `json:"neType" ` + NeName string `json:"neName" ` + RmUID string `json:"rmUID"` + StateList []struct { + Address string `json:"address" ` + Name string `json:"name" ` + Position string `json:"position" ` + NbName string `json:"nbName" ` + State string `json:"state" ` // "OFF" or "ON" + OffTime string `json:"offTime" ` //if State=OFF, will set it + OnTime string `json:"onTime" ` //if State=ON , will set it + } + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + elementTypeValue := c.Param("elementTypeValue") + if !strings.EqualFold(body.NeType, elementTypeValue) { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType")) + return + } + + if len(body.StateList) == 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "no stateList")) + return + } + + nbStateArr := make([]oam.NBState, 0) + for _, v := range body.StateList { + if v.Address == "" || v.State == "" { + continue + } + stateTime := date.ParseStrToDate(v.OffTime, time.RFC3339) + stateStr := oam.NB_STATE_OFF + if v.State == "ON" { + stateTime = date.ParseStrToDate(v.OnTime, time.RFC3339) + stateStr = oam.NB_STATE_ON + } + + // 创建NbState + nbState := oam.NBState{ + NeUid: body.RmUID, // 网元唯一标识 + RecordTime: time.Now().UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充 + Address: v.Address, // 基站地址 + DeviceName: v.NbName, // 基站设备名称 + State: stateStr, // 基站状态 ON/OFF + StateTime: stateTime.UnixMilli(), // 基站状态时间 时间戳毫秒 + Name: v.Name, // 基站名称 网元标记 + Position: v.Position, // 基站位置 网元标记 + } + nbStateArr = append(nbStateArr, nbState) + } + + errArr := make([]string, 0) + for _, nbState := range nbStateArr { + if err := oamService.NewNBState.Resolve(nbState); err != nil { + errArr = append(errArr, err.Error()) + } + } + + if len(errArr) > 0 { + c.JSON(200, resp.ErrData(errArr)) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// ResolveUENB 接收终端接入基站 +// +// POST /logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent +func (s APIRestController) ResolveUENB(c *gin.Context) { + var body struct { + NeType string `json:"neType" ` + NeName string `json:"neName" ` + RmUID string `json:"rmUID" ` + Timestamp int64 `json:"timestamp" ` + EventType string `json:"eventType" ` + EventJson map[string]any `json:"eventJSON" ` + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + elementTypeValue := c.Param("elementTypeValue") + if !strings.EqualFold(body.NeType, elementTypeValue) { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType")) + return + } + + // 记录时间 + recordTime := time.Now() + if body.Timestamp > 1e12 { + recordTime = time.UnixMilli(int64(body.Timestamp)) + } else if body.Timestamp > 1e9 { + recordTime = time.Unix(int64(body.Timestamp), 0) + } + + // 创建UENB + uenb := oam.UENB{ + NeUid: body.RmUID, // 网元唯一标识 + RecordTime: recordTime.UnixMilli(), // 记录时间 + NBId: "0", // 基站ID + CellId: "0", // 小区ID + TAC: "", // TAC + IMSI: "", // IMSI + Result: oam.UENB_RESULT_AUTH_SUCCESS, // 结果值 + Type: oam.UENB_TYPE_DETACH, // 终端接入基站类型 + } + + // 基站ID + if v, ok := body.EventJson["eNBID"]; ok && v != nil { + uenb.NBId = fmt.Sprint(v) + } + if v, ok := body.EventJson["gNBID"]; ok && v != nil { + uenb.NBId = fmt.Sprint(v) + } + // 小区ID + if v, ok := body.EventJson["cellID"]; ok && v != nil { + uenb.CellId = fmt.Sprint(v) + } + // TAC + if v, ok := body.EventJson["tacID"]; ok && v != nil { + uenb.TAC = fmt.Sprint(v) + } + // IMSI + if v, ok := body.EventJson["imsi"]; ok && v != nil { + uenb.IMSI = fmt.Sprint(v) + } + // 结果值 + if v, ok := body.EventJson["result"]; ok && v != nil { + uenb.Result = fmt.Sprint(v) + } + // 终端接入基站类型 + if v, ok := body.EventJson["type"]; ok && v != nil { + switch v := fmt.Sprint(v); v { + case "detach": + uenb.Type = oam.UENB_TYPE_DETACH + case "auth-result": + uenb.Type = oam.UENB_TYPE_AUTH + case "cm-state": + uenb.Type = oam.UENB_TYPE_CM + } + } + + if err := oamService.NewUENB.Resolve(uenb); err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// ResolveUENBByAMF 接收终端接入基站-AMF +// +// POST /upload-ue/v1/:eventType +func (s APIRestController) ResolveUENBByAMF(c *gin.Context) { + var body map[string]any + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 创建UENB + uenb := oam.UENB{ + NeUid: "4400HXAMF001", // 网元唯一标识 + RecordTime: 0, // 记录时间 + NBId: "0", // 基站ID + CellId: "0", // 小区ID + TAC: "", // TAC + IMSI: "", // IMSI + Result: oam.UENB_RESULT_AUTH_SUCCESS, // 结果值 + Type: oam.UENB_TYPE_DETACH, // 终端接入基站类型 + } + + // 从eventJson中获取rmUID + if v, ok := body["rmUID"]; ok { + uenb.NeUid = fmt.Sprint(v) + } + + // 统一格式 + eventType := c.Param("eventType") + switch eventType { + case "auth-result": + // {"authCode":"200","authMessage":"成功","authTime":"2024-12-07 16:48:37","cellID":"3","gNBID":"1","imsi":"460002082100000","onlineNumber":1,"tacID":"81"} + if v, ok := body["imsi"]; ok { + uenb.IMSI = fmt.Sprint(v) + } + if v, ok := body["cellID"]; ok { + uenb.CellId = fmt.Sprint(v) + } + if v, ok := body["gNBID"]; ok { + uenb.NBId = fmt.Sprint(v) + } + if v, ok := body["tacID"]; ok { + uenb.TAC = fmt.Sprint(v) + } + + if v, ok := body["authCode"]; ok { + uenb.Result = fmt.Sprint(v) + } + if v, ok := body["authTime"]; ok { + authTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) + uenb.RecordTime = authTime.UnixMilli() + } + uenb.Type = oam.UENB_TYPE_AUTH + case "detach": + // {"detachResult":0,"detachTime":"2024-12-07 18:00:47","imsi":"460002082100000"} + if v, ok := body["imsi"]; ok { + uenb.IMSI = fmt.Sprint(v) + } + if v, ok := body["detachResult"]; ok { + if v == "0" { + uenb.Result = oam.UENB_RESULT_AUTH_SUCCESS + } else { + uenb.Result = fmt.Sprint(v) + } + } + if v, ok := body["detachTime"]; ok { + detachTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) + uenb.RecordTime = detachTime.UnixMilli() + } + uenb.Type = oam.UENB_TYPE_DETACH + case "cm-state": + // {"changeTime":"2024-12-07 17:07:52","imsi":"460002082100000","onlineNumber":1,"status":2} + if v, ok := body["imsi"]; ok { + uenb.IMSI = fmt.Sprint(v) + } + if v, ok := body["status"]; ok { + uenb.Result = fmt.Sprint(v) + } + if v, ok := body["changeTime"]; ok { + changeTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) + uenb.RecordTime = changeTime.UnixMilli() + } + uenb.Type = oam.UENB_TYPE_CM + } + + if err := oamService.NewUENB.Resolve(uenb); err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// ResolveAlarmHistory 拉取告警历史 +// +// GET /faultManagement/v1/elementType/:elementTypeValue/objectType/alarms +func (s APIRestController) ResolveAlarmHistory(c *gin.Context) { + elementTypeValue := c.Param("elementTypeValue") + + // Get alarms from OMC return 204 + if strings.ToLower(elementTypeValue) == "omc" { + c.JSON(200, resp.OkMsg("omc alarms no content")) + return + } + + // alarmTypeValue 映射值 + alarmTypeValue := func(str string) string { + arr := []string{ + oam.ALARM_TYPE_COMMUNICATION_ALARM, + oam.ALARM_TYPE_EQUIPMENT_ALARM, + oam.ALARM_TYPE_PROCESSING_FAILURE, + oam.ALARM_TYPE_ENVIRONMENTAL_ALARM, + oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM, + } + for k, v := range arr { + if v == str { + return v + } + if fmt.Sprint(k+1) == str { + return v + } + } + return str + } + + // origSeverityValue 映射值 + origSeverityValue := func(str string) string { + arr := []string{ + oam.ALARM_SEVERITY_CRITICAL, + oam.ALARM_SEVERITY_MAJOR, + oam.ALARM_SEVERITY_MINOR, + oam.ALARM_SEVERITY_WARNING, + oam.ALARM_SEVERITY_EVENT, + } + for k, v := range arr { + if v == str { + return v + } + if fmt.Sprint(k+1) == str { + return v + } + } + return str + } + + // alarmStatusValue 映射值 + alarmStatusValue := func(value int) string { + arr := []string{ + oam.ALARM_STATUS_CLEAR, + oam.ALARM_STATUS_ACTIVE, + } + for k, v := range arr { + if k == value { + return v + } + } + return oam.ALARM_STATUS_ACTIVE + } + + alarmArr := make([]oam.Alarm, 0) + type body struct { + AlarmSeq int `json:"alarmSeq"` + AlarmId string `json:"alarmId"` + NeId string `json:"neId"` // 收到实际是rmUID + AlarmCode int `json:"alarmCode"` + AlarmTitle string `json:"alarmTitle"` + EventTime string `json:"eventTime"` + AlarmType string `json:"alarmType"` + OrigSeverity string `json:"origSeverity"` + PerceivedSeverity string `json:"perceivedSeverity"` + PVFlag string `json:"pvFlag"` + NeName string `json:"neName"` + NeType string `json:"neType"` + ObjectUid string `json:"objectUid"` + ObjectName string `json:"objectName"` + ObjectType string `json:"objectType"` + LocationInfo string `json:"locationInfo"` + Province string `json:"province"` + AlarmStatus int `json:"alarmStatus"` + SpecificProblem string `json:"specificProblem"` + SpecificProblemID string `json:"specificProblemID"` + AddInfo string `json:"addInfo"` + } + parseItem := func(v body) oam.Alarm { + // 产生时间 + eventTime := date.ParseStrToDate(v.EventTime, time.RFC3339) + // 创建告警 + alarm := oam.Alarm{ + NeUid: v.NeId, // 网元唯一标识 + AlarmTime: eventTime.UnixMilli(), // 事件产生时间 + AlarmId: v.AlarmId, // 告警ID 唯一,清除时对应 + AlarmCode: v.AlarmCode, // 告警状态码 + AlarmType: alarmTypeValue(v.AlarmType), // 告警类型 + AlarmTitle: v.AlarmTitle, // 告警标题 + PerceivedSeverity: origSeverityValue(v.OrigSeverity), // 告警级别 + AlarmStatus: alarmStatusValue(v.AlarmStatus), // 告警状态 + SpecificProblem: v.SpecificProblem, // 告警问题原因 + SpecificProblemID: v.SpecificProblemID, // 告警问题原因ID + AddInfo: v.AddInfo, // 告警辅助信息 + LocationInfo: v.LocationInfo, // 告警定位信息 + } + return alarm + } + var neInfos []neModel.NeInfo + if elementTypeValue == "all" { + neInfos = neService.NewNeInfo.Find(neModel.NeInfo{}, false, false) + } else { + neInfos = neService.NewNeInfo.FindByNeType(strings.ToUpper(elementTypeValue)) + } + for _, neInfo := range neInfos { + data, err := neFetchlink.AlarmHistory(neInfo) + if err != nil { + logger.Errorf("failed to fetch alarm history:%s", err.Error()) + continue + } + if len(data) == 0 { + logger.Warnf("not found sync alarms %s", neInfo.RmUID) + continue + } + + bodyArr := make([]body, 0) + // 将 []map[string]any 序列化为 JSON 字符串 + jsonData, err := json.Marshal(data) + if err != nil { + logger.Errorf("marshal error: %s", err.Error()) + continue + } + // 反序列化到结构体 + err = json.Unmarshal(jsonData, &bodyArr) + if err != nil { + logger.Errorf("Error unmarshal error: %s", err.Error()) + continue + } + + for _, v := range bodyArr { + alarmArr = append(alarmArr, parseItem(v)) + } + } + + errArr := make([]string, 0) + for _, alarm := range alarmArr { + if err := oamService.NewAlarm.Resolve(alarm); err != nil { + errArr = append(errArr, err.Error()) + } + } + + if len(errArr) > 0 { + c.JSON(200, resp.ErrData(errArr)) + return + } + c.JSON(200, resp.Ok(nil)) +} diff --git a/src/modules/oam/oam.go b/src/modules/oam/oam.go new file mode 100644 index 00000000..5a116ecf --- /dev/null +++ b/src/modules/oam/oam.go @@ -0,0 +1,40 @@ +package oam + +import ( + "github.com/gin-gonic/gin" + "github.com/tsmask/go-oam" + + "be.ems/src/framework/logger" + "be.ems/src/modules/oam/controller" + "be.ems/src/modules/oam/service" +) + +// Setup 模块路由注册 +func Setup(router *gin.Engine) { + logger.Infof("开始加载 ====> oam 模块路由") + + // 网管接收端收告警 + oam.AlarmReceiveRoute(router, service.NewAlarm.Resolve) + // 网管接收端收终端接入基站 + oam.UENBReceiveRoute(router, service.NewUENB.Resolve) + // 网管接收端收基站状态 + oam.NBStateReceiveRoute(router, service.NewNBState.Resolve) + // 网管接收端收话单 + oam.CDRReceiveRoute(router, service.NewCDR.Resolve) + // 网管接收端收KPI + oam.KPIReceiveRoute(router, service.NewKPI.Resolve) + + // APIRest 北向接收 + aprRest := controller.NewAPIRest + aprRestGroup := router.Group("/api/rest") + { + aprRestGroup.GET("/faultManagement/v1/elementType/:elementTypeValue/objectType/alarms", aprRest.ResolveAlarmHistory) + aprRestGroup.POST("/faultManagement/v1/elementType/:elementTypeValue/objectType/alarms", aprRest.ResolveAlarm) + 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("/logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent", aprRest.ResolveUENB) + router.POST("/upload-ue/v1/:eventType", aprRest.ResolveUENBByAMF) // AMF特殊上报 + } + +} diff --git a/src/modules/oam/service/kpi.go b/src/modules/oam/service/kpi.go new file mode 100644 index 00000000..3d73d8c4 --- /dev/null +++ b/src/modules/oam/service/kpi.go @@ -0,0 +1,236 @@ +package service + +import ( + "encoding/json" + "fmt" + "time" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/expr" + "be.ems/src/framework/utils/parse" + "github.com/tsmask/go-oam" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neModel "be.ems/src/modules/network_element/model" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +// 实例化服务层 KPI 结构体 +var NewKPI = &KPI{ + neInfoService: neService.NewNeInfo, + wsService: wsService.NewWSSend, + kpiReportService: neDataService.NewKpiReport, + kpiCReportService: neDataService.NewKpiCReport, +} + +// KPI 消息处理 +type KPI struct { + neInfoService *neService.NeInfo + wsService *wsService.WSSend + kpiReportService *neDataService.KpiReport + kpiCReportService *neDataService.KpiCReport + neInfo neModel.NeInfo +} + +// Resolve 接收处理 +func (s *KPI) Resolve(k oam.KPI) error { + if len(k.Data) == 0 { + return fmt.Errorf("kpi data is nil") + } + // 是否存在网元 + s.neInfo = s.neInfoService.FindByRmuid(k.NeUid) + if s.neInfo.NeType == "" || s.neInfo.RmUID != k.NeUid { + logger.Warnf("resolve kpi network element does not exist %s", k.NeUid) + return fmt.Errorf("resolve kpi network element does not exist %s", k.NeUid) + } + + // 时间片 + curTime := time.Now() + curSeconds := curTime.Hour()*3600 + curTime.Minute()*60 + curTime.Second() + index := int64(curSeconds) / k.Granularity + + if err := s.saveKPIData(k, index); err != nil { + logger.Warnf("resolve kpi data fail %s", k.NeUid) + return err + } + if err := s.saveKPIDataC(k, index); err != nil { + logger.Warnf("resolve kpic data fail %s", k.NeUid) + return err + } + return nil +} + +// saveKPIData 存储KPI数据并推送到ws订阅组 +func (s *KPI) saveKPIData(k oam.KPI, index int64) error { + // 时间数据处理 + recordTime := time.Now() + if k.RecordTime > 1e12 { + recordTime = time.UnixMilli(k.RecordTime) + } else if k.RecordTime > 1e9 { + recordTime = time.Unix(k.RecordTime, 0) + } + recordDate := date.ParseDateToStr(recordTime, "2006-01-02") + recordEndTime := date.ParseDateToStr(recordTime, "15:04:05") + startTime := recordTime.Add(-time.Duration(k.Granularity) * time.Second) + recordStartTime := date.ParseDateToStr(startTime, "15:04:05") + + // kpi data数据json + kpiTitles := s.kpiReportService.FindTitle(s.neInfo.NeType) + KpiValues := make([]map[string]any, 0) + for _, kt := range kpiTitles { + item := map[string]any{ + "kpiId": kt.KpiId, + "value": 0, + "err": "", + } + // 匹配指标记录 + for k, v := range k.Data { + if k == kt.KpiId { + item["value"] = v + } + } + KpiValues = append(KpiValues, item) + } + + KpiValuesByte, _ := json.Marshal(KpiValues) + + // KPI 信息 + kpiData := neDataModel.KpiReport{ + NeType: s.neInfo.NeType, + NeName: s.neInfo.NeName, + RmUid: s.neInfo.RmUID, + Date: recordDate, + StartTime: recordStartTime, + EndTime: recordEndTime, + Index: index, + Granularity: k.Granularity, + KpiValues: string(KpiValuesByte), + CreatedAt: k.RecordTime, + } + insertId := s.kpiReportService.Insert(kpiData) + if insertId <= 0 { + return fmt.Errorf("add kpi data fail") + } + kpiData.ID = insertId + + // 指标事件对象 + data := map[string]any{ + "neType": kpiData.NeType, + "neName": kpiData.NeName, + "rmUID": kpiData.RmUid, + "startIndex": kpiData.Index, + "timeGroup": kpiData.CreatedAt, + // kip_id ... + } + for _, v := range KpiValues { + data[fmt.Sprint(v["kpiId"])] = v["value"] + } + + // 推送到ws订阅组 + s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, s.neInfo.NeType, s.neInfo.NeId), data) + // 更新UPF总流量 + if s.neInfo.NeType == "UPF" { + upValue := parse.Number(data["UPF.03"]) + downValue := parse.Number(data["UPF.06"]) + s.kpiReportService.UPFTodayFlowUpdate(s.neInfo.RmUID, upValue, downValue) + } + return nil +} + +// saveKPIDataC 存储自定义KPI数据并推送到ws订阅组 +func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { + // 时间数据处理 + recordTime := time.Now() + if k.RecordTime > 1e12 { + recordTime = time.UnixMilli(k.RecordTime) + } else if k.RecordTime > 1e9 { + recordTime = time.Unix(k.RecordTime, 0) + } + recordDate := date.ParseDateToStr(recordTime, "2006-01-02") + recordEndTime := date.ParseDateToStr(recordTime, "15:04:05") + startTime := recordTime.Add(-time.Duration(k.Granularity) * time.Second) + recordStartTime := date.ParseDateToStr(startTime, "15:04:05") + + // kpi data数据json + kpiCTitles := s.kpiCReportService.FindTitle(s.neInfo.NeType) + KpiValues := make([]map[string]any, 0) + // 自定义指标的表达式环境变量 + KpiExprEnv := make(map[string]any, 0) + for k, v := range k.Data { + KpiExprEnv[k] = v + } + // 自定义指标的计算 + for _, v := range kpiCTitles { + item := map[string]any{ + "kpiId": v.KpiId, + "value": 0, + "err": "", + } + + // 匹配指标记录 + if envValue, envOk := KpiExprEnv[v.KpiId]; envOk { + item["value"] = envValue + } + + // 计算结果 + exprStr, exprEnv := expr.ParseExprEnv(v.Expression, KpiExprEnv) + result, err := expr.Eval(exprStr, exprEnv) + if err != nil { + item["value"] = 0 + item["err"] = err.Error() + } else { + if v.Unit == "%" { + resultInt64 := parse.Number(result) + if resultInt64 > 100 { + result = 100 + } + if resultInt64 < 0 { + result = 0 + } + } + + item["value"] = result + } + KpiValues = append(KpiValues, item) + } + KpiValuesByte, _ := json.Marshal(KpiValues) + + // KPI 信息 + kpiCData := neDataModel.KpiCReport{ + NeType: s.neInfo.NeType, + NeName: s.neInfo.NeName, + RmUid: s.neInfo.RmUID, + Date: recordDate, + StartTime: recordStartTime, + EndTime: recordEndTime, + Index: index, + Granularity: k.Granularity, + KpiValues: string(KpiValuesByte), + CreatedAt: k.RecordTime, + } + insertId := s.kpiCReportService.Insert(kpiCData) + if insertId <= 0 { + return fmt.Errorf("add kpic data fail") + } + kpiCData.ID = insertId + + // 指标事件对象 + data := map[string]any{ + "neType": kpiCData.NeType, + "neName": kpiCData.NeName, + "rmUID": kpiCData.RmUid, + "startIndex": kpiCData.Index, + "timeGroup": kpiCData.CreatedAt, + // kip_id ... + } + for _, v := range KpiValues { + data[fmt.Sprint(v["kpiId"])] = v["value"] + } + + // 推送到ws订阅组 + s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, s.neInfo.NeType, s.neInfo.NeId), data) + return nil +} diff --git a/src/modules/oam/service/nb_state.go b/src/modules/oam/service/nb_state.go new file mode 100644 index 00000000..bc283a54 --- /dev/null +++ b/src/modules/oam/service/nb_state.go @@ -0,0 +1,67 @@ +package service + +import ( + "fmt" + "time" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "github.com/tsmask/go-oam" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +// 实例化服务层 NBState 结构体 +var NewNBState = &NBState{ + neInfoService: neService.NewNeInfo, + wsService: wsService.NewWSSend, + nbStateService: neDataService.NewNBState, +} + +// NBState 消息处理 +type NBState struct { + neInfoService *neService.NeInfo + wsService *wsService.WSSend + nbStateService *neDataService.NBState +} + +// Resolve 接收处理 +func (s *NBState) Resolve(n oam.NBState) error { + // 是否存在网元 + neInfo := s.neInfoService.FindByRmuid(n.NeUid) + if neInfo.NeType == "" || neInfo.RmUID != n.NeUid { + logger.Warnf("resolve nb_state network element does not exist %s", n.NeUid) + return fmt.Errorf("resolve nb_state network element does not exist %s", n.NeUid) + } + + nbState := neDataModel.NBState{ + NeType: neInfo.NeType, + NeId: neInfo.NeId, + RmUid: neInfo.RmUID, + Address: n.Address, + Name: n.Name, + Position: n.Position, + NbName: n.DeviceName, + State: n.State, + Time: date.ParseDateToStr(n.StateTime, time.RFC3339), + } + insertId := s.nbStateService.Insert(nbState) + if insertId <= 0 { + return fmt.Errorf("add nb_state data fail") + } + nbState.ID = insertId + + // 推送到ws订阅组 + switch neInfo.NeType { + case "AMF": + s.wsService.ByGroupID(wsService.GROUP_AMF_NB, nbState) + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_AMF_NB, neInfo.NeId), nbState) + case "MME": + s.wsService.ByGroupID(wsService.GROUP_MME_NB, nbState) + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_MME_NB, neInfo.NeId), nbState) + } + return nil +} From 9f6a7f3bb7170086270b7804fc86fd1a9d8b3998 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:14:05 +0800 Subject: [PATCH 19/80] =?UTF-8?q?feat:=20OMC=E9=85=8D=E7=BD=AE=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E9=80=9A=E7=9F=A5=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/config/expand.go | 30 ++++ .../network_element/controller/ne_config.go | 21 --- .../network_element/service/ne_config_omc.go | 146 +++++++++++++++--- 3 files changed, 153 insertions(+), 44 deletions(-) create mode 100644 src/framework/config/expand.go diff --git a/src/framework/config/expand.go b/src/framework/config/expand.go new file mode 100644 index 00000000..2941e7bf --- /dev/null +++ b/src/framework/config/expand.go @@ -0,0 +1,30 @@ +package config + +import ( + "fmt" + "os" + "regexp" +) + +// SedReplace 替换文件内容,文件来自外部文件配置config传入 +// +// sed 's/port: [0-9]\+ # trace port/port: 6964 # trace port/' /usr/local/etc/omc/omc.yaml +func SedReplace(pattern, replacement string) error { + // 外部文件配置 + externalConfig := conf.GetString("config") + if externalConfig == "" { + return fmt.Errorf("config file path not found") + } + // 读取文件内容 + data, err := os.ReadFile(externalConfig) + if err != nil { + return err + } + + // 定义正则表达式 + re := regexp.MustCompile(pattern) + // 使用正则替换,将匹配到的部分替换为新的内容 + replacedData := re.ReplaceAll(data, []byte(replacement)) + // 写回文件 + return os.WriteFile(externalConfig, replacedData, 0644) +} diff --git a/src/modules/network_element/controller/ne_config.go b/src/modules/network_element/controller/ne_config.go index 3fd08c2e..d33df1be 100644 --- a/src/modules/network_element/controller/ne_config.go +++ b/src/modules/network_element/controller/ne_config.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" - cm_omc "be.ems/features/cm/omc" "be.ems/src/framework/i18n" "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" @@ -215,16 +214,6 @@ func (s NeConfigController) DataInfo(c *gin.Context) { } if query.NeType == "OMC" { - if query.ParamName == "alarmEmailForward" || query.ParamName == "alarmSMSForward" { - var o *cm_omc.ConfigOMC - resData, err := o.Query(query.ParamName) - if err != nil { - c.JSON(200, resp.ErrMsg(err.Error())) - return - } - c.JSON(200, resp.OkData(resData)) - return - } resData := s.neConfigService.GetOMCYaml(query.ParamName) c.JSON(200, resp.OkData(resData)) return @@ -274,16 +263,6 @@ func (s NeConfigController) DataEdit(c *gin.Context) { return } if body.NeType == "OMC" { - if body.ParamName == "alarmEmailForward" || body.ParamName == "alarmSMSForward" { - var o *cm_omc.ConfigOMC - resData, err := o.Modify(body.ParamName, body.ParamData) - if err != nil { - c.JSON(200, resp.ErrMsg(err.Error())) - return - } - c.JSON(200, resp.OkData(resData)) - return - } err := s.neConfigService.ModifyOMCYaml(body.ParamName, body.Loc, body.ParamData) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) diff --git a/src/modules/network_element/service/ne_config_omc.go b/src/modules/network_element/service/ne_config_omc.go index 4d288d0c..7243c3e2 100644 --- a/src/modules/network_element/service/ne_config_omc.go +++ b/src/modules/network_element/service/ne_config_omc.go @@ -2,15 +2,32 @@ package service import ( "fmt" - "runtime" "strings" - "be.ems/src/framework/cmd" "be.ems/src/framework/config" + "github.com/tsmask/go-oam/src/framework/utils/parse" ) -// GetOMCYaml 获取OMC网元配置文件 /usr/local/etc/omc/omc.yaml +// GetOMCYaml 获取OMC网元配置文件 func (r NeConfig) GetOMCYaml(paramName string) []map[string]any { + if paramName == "notificationEmail" { + notificationEmailData := config.Get("notification.email").(map[string]any) + for k, v := range notificationEmailData { + if k == "password" && v != nil { + notificationEmailData[k] = parse.SafeContent(fmt.Sprint(v)) + } + } + return []map[string]any{notificationEmailData} + } + if paramName == "notificationSMSC" { + notificationSMSCData := config.Get("notification.smsc").(map[string]any) + for k, v := range notificationSMSCData { + if k == "password" && v != nil { + notificationSMSCData[k] = parse.SafeContent(fmt.Sprint(v)) + } + } + return []map[string]any{notificationSMSCData} + } if paramName == "trace" { traceData := config.Get("trace").(map[string]any) return []map[string]any{traceData} @@ -18,30 +35,113 @@ func (r NeConfig) GetOMCYaml(paramName string) []map[string]any { return []map[string]any{} } -// ModifyOMCYaml 修改OMC网元配置文件 /usr/local/etc/omc/omc.yaml +// ModifyOMCYaml 修改OMC网元配置文件 func (r NeConfig) ModifyOMCYaml(paramName, loc string, paramData any) error { neConfig := r.FindByNeTypeAndParamName("OMC", paramName) if neConfig.ParamType == "list" { + if paramName == "notificationEmail" { + notificationEmailData := config.Get("notification.email").(map[string]any) + for k, v := range paramData.(map[string]any) { + keyLower := strings.ToLower(k) + // 改程序内 + notificationEmailData[keyLower] = v + // 改文件 + switch keyLower { + case "enabled": + pattern := `enabled: (true|false) # email enable` + replacement := fmt.Sprintf(`enabled: %v # email enable`, v) + return config.SedReplace(pattern, replacement) + case "list": + pattern := `list: ".*" # toEmail` + replacement := fmt.Sprintf(`list: "%v" # toEmail`, v) + return config.SedReplace(pattern, replacement) + case "title": + pattern := `title: ".*" # email title` + replacement := fmt.Sprintf(`title: "%v" # email title`, v) + return config.SedReplace(pattern, replacement) + case "smtp": + pattern := `smtp: ".*" # email smtp` + replacement := fmt.Sprintf(`smtp: "%v" # email smtp`, v) + return config.SedReplace(pattern, replacement) + case "port": + pattern := `port: [0-9]+ # email port` + replacement := fmt.Sprintf(`port: %v # email port`, v) + return config.SedReplace(pattern, replacement) + case "user": + pattern := `user: ".*" # email user` + replacement := fmt.Sprintf(`user: "%v" # email user`, v) + return config.SedReplace(pattern, replacement) + case "password": + pattern := `password: ".*" # email password` + replacement := fmt.Sprintf(`password: "%v" # email password`, v) + return config.SedReplace(pattern, replacement) + } + } + } + if paramName == "notificationSMSC" { + notificationSMSCData := config.Get("notification.smsc").(map[string]any) + for k, v := range paramData.(map[string]any) { + keyLower := strings.ToLower(k) + // 改程序内 + notificationSMSCData[keyLower] = v + // 改文件 + switch keyLower { + case "enabled": + pattern := `enabled: (true|false) # smsc enable` + replacement := fmt.Sprintf(`enabled: %v # smsc enable`, v) + return config.SedReplace(pattern, replacement) + case "list": + pattern := `list: ".*" # toMobile` + replacement := fmt.Sprintf(`list: "%v" # toMobile`, v) + return config.SedReplace(pattern, replacement) + case "addr": + pattern := `addr: ".*" # smsc addr` + replacement := fmt.Sprintf(`addr: "%v" # smsc addr`, v) + return config.SedReplace(pattern, replacement) + case "systemid": + pattern := `systemid: ".*" # smsc system id` + replacement := fmt.Sprintf(`systemid: "%v" # smsc system id`, v) + return config.SedReplace(pattern, replacement) + case "systemtype": + pattern := `systemtype: ".*" # smsc system type` + replacement := fmt.Sprintf(`systemtype: "%v" # smsc system type`, v) + return config.SedReplace(pattern, replacement) + case "password": + pattern := `password: ".*" # smsc password` + replacement := fmt.Sprintf(`password: "%v" # smsc password`, v) + return config.SedReplace(pattern, replacement) + case "coding": + pattern := `coding: [0-9]+ # smsc codingMap` + replacement := fmt.Sprintf(`coding: %v # smsc codingMap`, v) + return config.SedReplace(pattern, replacement) + case "servicenumber": + pattern := `servicenumber: ".*" # smsc service number` + replacement := fmt.Sprintf(`servicenumber: "%v" # smsc service number`, v) + return config.SedReplace(pattern, replacement) + + } + } + } if paramName == "trace" { - configPath := fmt.Sprint(config.Get("config")) // 获取配置文件路径 - paramDataMap := paramData.(map[string]any) - for k, v := range paramDataMap { - config.Set(fmt.Sprintf("trace.%s", strings.ToLower(k)), v) - if runtime.GOOS == "windows" { - continue // Windows系统不支持sed命令 - } - // 修改参数较少,直接命令改文件内容 - if k == "enabled" { - // sed 's/enabled: \(true\|false\) # trace enabled/enabled: true # trace enabled/' /usr/local/etc/omc/omc.yaml - cmd.Execf("sed -i 's/enabled: \\(true\\|false\\) # trace enabled/enabled: %v # trace enabled/' %s", v, configPath) - } - if k == "host" { - // sed 's/host: ".*" # trace host/host: "127.2.2.2" # trace host/' /usr/local/etc/omc/omc.yaml - cmd.Execf("sed -i 's/host: \".*\" # trace host/host: \"%v\" # trace host/' %s", v, configPath) - } - if k == "port" { - // sed 's/port: [0-9]\+ # trace port/port: 6964 # trace port/' /usr/local/etc/omc/omc.yaml - cmd.Execf("sed -i 's/port: [0-9]\\+ # trace port/port: %v # trace port/' %s", v, configPath) + traceData := config.Get("trace").(map[string]any) + for k, v := range paramData.(map[string]any) { + keyLower := strings.ToLower(k) + // 改程序内 + traceData[keyLower] = v + // 改文件 + switch keyLower { + case "enabled": + pattern := `enabled: (true|false) # trace enabled` + replacement := fmt.Sprintf(`enabled: %v # trace enabled`, v) + return config.SedReplace(pattern, replacement) + case "host": + pattern := `host: ".*" # trace host` + replacement := fmt.Sprintf(`host: "%v" # trace host`, v) + return config.SedReplace(pattern, replacement) + case "port": + pattern := `port: [0-9]+ # trace port` + replacement := fmt.Sprintf(`port: %v # trace port`, v) + return config.SedReplace(pattern, replacement) } } // 重开跟踪任务信令数据通道UDP From 150551accea053c8fa5a8d05be59e87d1044daa2 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 15:16:44 +0800 Subject: [PATCH 20/80] =?UTF-8?q?fix:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.go | 6 + src/framework/telnet/telnet.go | 25 +++- src/framework/utils/date/date.go | 4 +- src/framework/utils/expr/expr.go | 44 +++++++ .../backup_export_table.go | 75 +++++------ src/modules/monitor/service/monitor_test.go | 119 +++++++++--------- src/modules/monitor/service/sys_job.go | 5 +- .../network_element/service/ne_license.go | 5 +- .../network_element/service/ne_version.go | 7 +- src/modules/trace/service/trace_task.go | 24 ++-- src/modules/ws/service/ws_receive.go | 14 +-- src/modules/ws/service/ws_send.go | 4 + 12 files changed, 202 insertions(+), 130 deletions(-) create mode 100644 src/framework/utils/expr/expr.go diff --git a/src/app.go b/src/app.go index e7168a73..da30bf86 100644 --- a/src/app.go +++ b/src/app.go @@ -15,6 +15,8 @@ import ( "be.ems/src/modules/monitor" networkdata "be.ems/src/modules/network_data" networkelement "be.ems/src/modules/network_element" + "be.ems/src/modules/notification" + "be.ems/src/modules/oam" "be.ems/src/modules/oauth2" "be.ems/src/modules/system" "be.ems/src/modules/tool" @@ -84,6 +86,8 @@ func ModulesRoute(app *gin.Engine) { auth.Setup(app) // 开放客户端模块 oauth2.Setup(app) + // 网元OAM对接 + oam.Setup(app) // 通用模块 common.Setup(app) @@ -92,6 +96,8 @@ func ModulesRoute(app *gin.Engine) { // 网元数据模块 networkdata.Setup(app) + // 通知模块 + notification.Setup(app) // 跟踪模块 trace.Setup(app) // 图表模块 diff --git a/src/framework/telnet/telnet.go b/src/framework/telnet/telnet.go index c72a46bd..478c301a 100644 --- a/src/framework/telnet/telnet.go +++ b/src/framework/telnet/telnet.go @@ -42,10 +42,14 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) { } // 进行登录 - time.Sleep(100 * time.Millisecond) - client.Write([]byte(c.User + "\r\n")) - time.Sleep(100 * time.Millisecond) - client.Write([]byte(c.Password + "\r\n")) + if c.User != "" { + time.Sleep(100 * time.Millisecond) + client.Write([]byte(c.User + "\r\n")) + } + if c.Password != "" { + time.Sleep(100 * time.Millisecond) + client.Write([]byte(c.Password + "\r\n")) + } // fmt.Fprintln(client, c.User) // fmt.Fprintln(client, c.Password) @@ -103,6 +107,19 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) { return c.LastResult, nil } +// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. +func (s *ConnTelnet) WindowChange(h, w int) error { + if s.Client == nil { + return fmt.Errorf("client is nil to content write failed") + } + conn := *s.Client + + // 需要确保接收方理解并正确处理发送窗口大小设置命令 + conn.Write([]byte{255, 251, 31}) + conn.Write([]byte{255, 250, 31, byte(w >> 8), byte(w & 0xFF), byte(h >> 8), byte(h & 0xFF), 255, 240}) + return nil +} + // NewClient 创建Telnet客户端会话对象 func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) { if c.Client == nil { diff --git a/src/framework/utils/date/date.go b/src/framework/utils/date/date.go index a1006bbe..7e9d3abd 100644 --- a/src/framework/utils/date/date.go +++ b/src/framework/utils/date/date.go @@ -54,9 +54,9 @@ func ParseDateToStr(date any, formatStr string) string { if v == 0 { return "" } - if v > 9999999999 { + if v > 1e12 { t = time.UnixMilli(v) - } else if v > 999999999 { + } else if v > 1e9 { t = time.Unix(v, 0) } else { logger.Infof("utils ParseDateToStr err %v", "Invalid timestamp") diff --git a/src/framework/utils/expr/expr.go b/src/framework/utils/expr/expr.go new file mode 100644 index 00000000..cd7ba420 --- /dev/null +++ b/src/framework/utils/expr/expr.go @@ -0,0 +1,44 @@ +package expr + +import ( + "fmt" + "regexp" + "strings" + + "github.com/expr-lang/expr" +) + +// Eval 计算表达式返回结果 +func Eval(exprStr string, env map[string]any) (any, error) { + return expr.Eval(exprStr, env) +} + +// ParseExprEnv 解析表达式环境变量 +// 比如 "('SMF.03'/'SMF.04')*100" +// 变量传入"SMF.03": 3 +func ParseExprEnv(exprStr string, env map[string]any) (string, map[string]any) { + // 使用正则表达式匹配带单引号的变量名 + re := regexp.MustCompile(`'([^']+)'`) + tempEnv := make(map[string]any) + tempExpr := exprStr + varCount := 0 + matches := re.FindAllStringSubmatch(exprStr, -1) + for _, match := range matches { + paramName := match[1] + tempVarName := fmt.Sprintf("var%d", varCount) + tempEnv[tempVarName] = env[paramName] + tempExpr = strings.Replace(tempExpr, match[0], tempVarName, 1) + varCount++ + } + + // 合并临时环境变量和原环境变量 + combinedEnv := make(map[string]any) + for k, v := range env { + combinedEnv[k] = v + } + for k, v := range tempEnv { + combinedEnv[k] = v + } + + return tempExpr, combinedEnv +} diff --git a/src/modules/crontask/processor/backup_export_table/backup_export_table.go b/src/modules/crontask/processor/backup_export_table/backup_export_table.go index 554eb4dd..d540038f 100644 --- a/src/modules/crontask/processor/backup_export_table/backup_export_table.go +++ b/src/modules/crontask/processor/backup_export_table/backup_export_table.go @@ -15,21 +15,22 @@ import ( "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" - neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" systemModel "be.ems/src/modules/system/model" systemService "be.ems/src/modules/system/service" ) var NewProcessor = &BackupExportTableProcessor{ - backupService: neDataService.NewBackup, - count: 0, + backupService: neDataService.NewBackup, + cdrEventService: neDataService.NewCDREvent, + count: 0, } // BackupExportTable 备份导出数据表 type BackupExportTableProcessor struct { - backupService *neDataService.Backup // 备份相关服务 - count int // 执行次数 + backupService *neDataService.Backup // 备份相关服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 + count int // 执行次数 } func (s *BackupExportTableProcessor) Execute(data any) (any, error) { @@ -197,13 +198,13 @@ func (s BackupExportTableProcessor) exportSMF(hour int, columns []string, filePa start := end.Add(-time.Duration(hour) * time.Hour) // 查询数据 - rows := []neDataModel.CDREventSMF{} - tx := db.DB("").Model(&neDataModel.CDREventSMF{}) - tx = tx.Where("created_at >= ? and created_at <= ?", start.UnixMilli(), end.UnixMilli()) - if err := tx.Find(&rows).Error; err != nil { - return 0, err - } - if len(rows) <= 0 { + rows, total := s.cdrEventService.FindByPage("SMF", map[string]string{ + "sortField": "created_at", + "sortOrder": "asc", + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + }) + if total <= 0 { return 0, nil } @@ -417,7 +418,7 @@ func (s BackupExportTableProcessor) exportSMF(hour int, columns []string, filePa err := file.WriterFileCSV(data, filePath) - return tx.RowsAffected, err + return total, err } // exportIMS 导出csv @@ -428,13 +429,13 @@ func (s BackupExportTableProcessor) exportIMS(hour int, columns []string, filePa start := end.Add(-time.Duration(hour) * time.Hour) // 查询数据 - rows := []neDataModel.CDREventIMS{} - tx := db.DB("").Model(&neDataModel.CDREventIMS{}) - tx = tx.Where("created_at >= ? and created_at <= ?", start.UnixMilli(), end.UnixMilli()) - if err := tx.Find(&rows).Error; err != nil { - return 0, err - } - if len(rows) <= 0 { + rows, total := s.cdrEventService.FindByPage("IMS", map[string]string{ + "sortField": "created_at", + "sortOrder": "asc", + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + }) + if total <= 0 { return 0, nil } @@ -561,7 +562,7 @@ func (s BackupExportTableProcessor) exportIMS(hour int, columns []string, filePa err := file.WriterFileCSV(data, filePath) - return tx.RowsAffected, err + return total, err } // exportSMSC 导出csv @@ -572,13 +573,13 @@ func (s BackupExportTableProcessor) exportSMSC(hour int, columns []string, fileP start := end.Add(-time.Duration(hour) * time.Hour) // 查询数据 - rows := []neDataModel.CDREventSMSC{} - tx := db.DB("").Model(&neDataModel.CDREventSMSC{}) - tx = tx.Where("created_at >= ? and created_at <= ?", start.UnixMilli(), end.UnixMilli()) - if err := tx.Find(&rows).Error; err != nil { - return 0, err - } - if len(rows) <= 0 { + rows, total := s.cdrEventService.FindByPage("SMS", map[string]string{ + "sortField": "created_at", + "sortOrder": "asc", + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + }) + if total <= 0 { return 0, nil } @@ -686,7 +687,7 @@ func (s BackupExportTableProcessor) exportSMSC(hour int, columns []string, fileP err := file.WriterFileCSV(data, filePath) - return tx.RowsAffected, err + return total, err } // exportSGWC 导出csv @@ -697,13 +698,13 @@ func (s BackupExportTableProcessor) exportSGWC(hour int, columns []string, fileP start := end.Add(-time.Duration(hour) * time.Hour) // 查询数据 - rows := []neDataModel.CDREventSMSC{} - tx := db.DB("").Model(&neDataModel.CDREventSMSC{}) - tx = tx.Where("created_at >= ? and created_at <= ?", start.UnixMilli(), end.UnixMilli()) - if err := tx.Find(&rows).Error; err != nil { - return 0, err - } - if len(rows) <= 0 { + rows, total := s.cdrEventService.FindByPage("SGWC", map[string]string{ + "sortField": "created_at", + "sortOrder": "asc", + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + }) + if total <= 0 { return 0, nil } @@ -923,5 +924,5 @@ func (s BackupExportTableProcessor) exportSGWC(hour int, columns []string, fileP err := file.WriterFileCSV(data, filePath) - return tx.RowsAffected, err + return total, err } diff --git a/src/modules/monitor/service/monitor_test.go b/src/modules/monitor/service/monitor_test.go index 44dd2a72..cd64a3d8 100644 --- a/src/modules/monitor/service/monitor_test.go +++ b/src/modules/monitor/service/monitor_test.go @@ -2,6 +2,7 @@ package service import ( "fmt" + "sync" "testing" "time" @@ -14,7 +15,7 @@ import ( func TestInfo(t *testing.T) { s := MonitorInfo{} - s.load(0.5) // 0.5 半分钟 + s.Load(5 * time.Second) // 0.5 半分钟 fmt.Println(s) select {} @@ -28,34 +29,22 @@ type MonitorInfo struct { } // load 执行资源获取 -func (m *MonitorInfo) load(interval float64) { - var itemBase MonitorBase - itemBase.CreateTime = time.Now().UnixMilli() - - loadInfo, _ := load.Avg() - itemBase.CPULoad1 = loadInfo.Load1 - itemBase.CPULoad5 = loadInfo.Load5 - itemBase.CPULoad15 = loadInfo.Load15 - - totalPercent, _ := cpu.Percent(3*time.Second, false) - if len(totalPercent) > 0 { - itemBase.CPU = totalPercent[0] - } - cpuCount, _ := cpu.Counts(false) - cpuAvg := (float64(cpuCount*2) * 0.75) * 100 - itemBase.LoadUsage = 0 - if cpuAvg > 0 { - itemBase.LoadUsage = loadInfo.Load1 / cpuAvg - } - - memoryInfo, _ := mem.VirtualMemory() - itemBase.Memory = memoryInfo.UsedPercent - - m.MonitorBase = itemBase - - // 求平均 - m.MonitorIO = loadDiskIO(interval) - m.MonitorNetwork = loadNetIO(interval) +func (m *MonitorInfo) Load(duration time.Duration) { + var wg sync.WaitGroup + wg.Add(3) + go func() { + defer wg.Done() + m.MonitorBase = loadCPUMem(duration) + }() + go func() { + defer wg.Done() + m.MonitorIO = loadDiskIO(duration) + }() + go func() { + defer wg.Done() + m.MonitorNetwork = loadNetIO(duration) + }() + wg.Wait() } // MonitorBase 监控_基本信息 monitor_base @@ -73,25 +62,49 @@ type MonitorBase struct { type MonitorIO struct { CreateTime int64 `json:"createTime"` // 创建时间 Name string `json:"name"` // 磁盘名 - Read int64 `json:"read"` // 读取K - Write int64 `json:"write"` // 写入K - Count int64 `json:"count"` // 次数 - Time int64 `json:"time"` // 耗时 + Read uint64 `json:"read"` // 读取 Bytes + Write uint64 `json:"write"` // 写入 Bytes + Count uint64 `json:"count"` // 次数 + Time uint64 `json:"time"` // 耗时 } // MonitorNetwork 监控_网络IO monitor_network type MonitorNetwork struct { - CreateTime int64 `json:"createTime"` // 创建时间 - Name string `json:"name"` // 网卡名 - Up float64 `json:"up"` // 上行 - Down float64 `json:"down"` // 下行 + CreateTime int64 `json:"createTime"` // 创建时间 + Name string `json:"name"` // 网卡名 + Up uint64 `json:"up"` // 上行 bytes + Down uint64 `json:"down"` // 下行 bytes +} + +// loadCPUMem CPU内存使用率,interval表示采集的平均值(分钟) +func loadCPUMem(duration time.Duration) MonitorBase { + var itemBase MonitorBase + itemBase.CreateTime = time.Now().UnixMilli() + + loadInfo, _ := load.Avg() + itemBase.CPULoad1 = loadInfo.Load1 + itemBase.CPULoad5 = loadInfo.Load5 + itemBase.CPULoad15 = loadInfo.Load15 + totalPercent, _ := cpu.Percent(duration, false) + if len(totalPercent) > 0 { + itemBase.CPU = totalPercent[0] + } + if cpuCount, _ := cpu.Counts(false); cpuCount > 0 { + itemBase.LoadUsage = loadInfo.Load1 / float64(cpuCount) + } else { + itemBase.LoadUsage = 0 + } + + memoryInfo, _ := mem.VirtualMemory() + itemBase.Memory = memoryInfo.UsedPercent + return itemBase } // loadDiskIO 磁盘读写,interval表示采集的平均值(分钟) -func loadDiskIO(interval float64) []MonitorIO { +func loadDiskIO(duration time.Duration) []MonitorIO { ioStat, _ := disk.IOCounters() - time.Sleep(time.Duration(interval) * time.Minute) + time.Sleep(duration) ioStat2, _ := disk.IOCounters() var ioList []MonitorIO @@ -104,32 +117,24 @@ func loadDiskIO(interval float64) []MonitorIO { itemIO.Name = io1.Name if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes { - itemIO.Read = int64(float64(io2.ReadBytes-io1.ReadBytes) / interval / 60) + itemIO.Read = io2.ReadBytes - io1.ReadBytes } if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes { - itemIO.Write = int64(float64(io2.WriteBytes-io1.WriteBytes) / interval / 60) + itemIO.Write = io2.WriteBytes - io1.WriteBytes } if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount { - itemIO.Count = int64(float64(io2.ReadCount-io1.ReadCount) / interval / 60) + itemIO.Count = io2.ReadCount - io1.ReadCount } - writeCount := int64(0) if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount { - writeCount = int64(float64(io2.WriteCount-io1.WriteCount) / interval * 60) - } - if writeCount > itemIO.Count { - itemIO.Count = writeCount + itemIO.Count += io2.WriteCount - io1.WriteCount } if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime { - itemIO.Time = int64(float64(io2.ReadTime-io1.ReadTime) / interval / 60) + itemIO.Time = io2.ReadTime - io1.ReadTime } - writeTime := int64(0) if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime { - writeTime = int64(float64(io2.WriteTime-io1.WriteTime) / interval / 60) - } - if writeTime > itemIO.Time { - itemIO.Time = writeTime + itemIO.Time += io2.WriteTime - io1.WriteTime } ioList = append(ioList, itemIO) break @@ -140,7 +145,7 @@ func loadDiskIO(interval float64) []MonitorIO { } // loadNetIO 网络接口(包括虚拟接口),interval表示采集的平均值(分钟) -func loadNetIO(interval float64) []MonitorNetwork { +func loadNetIO(duration time.Duration) []MonitorNetwork { // 获取当前时刻 netStat, _ := net.IOCounters(true) netStatAll, _ := net.IOCounters(false) @@ -148,7 +153,7 @@ func loadNetIO(interval float64) []MonitorNetwork { netStatList = append(netStatList, netStat...) netStatList = append(netStatList, netStatAll...) - time.Sleep(time.Duration(interval) * time.Minute) + time.Sleep(duration) // 获取结束时刻 netStat2, _ := net.IOCounters(true) @@ -168,10 +173,10 @@ func loadNetIO(interval float64) []MonitorNetwork { // 如果结束时刻发送字节数和当前时刻发送字节数都不为零,并且结束时刻发送字节数大于当前时刻发送字节数 if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent { - itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / interval / 60 + itemNet.Up = net2.BytesSent - net1.BytesSent } if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv { - itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / interval / 60 + itemNet.Down = net2.BytesRecv - net1.BytesRecv } netList = append(netList, itemNet) break diff --git a/src/modules/monitor/service/sys_job.go b/src/modules/monitor/service/sys_job.go index 3ddb6a1d..7f1cb62b 100644 --- a/src/modules/monitor/service/sys_job.go +++ b/src/modules/monitor/service/sys_job.go @@ -199,9 +199,10 @@ func (s SysJob) ExportData(rows []model.SysJob, fileName string) (string, error) } } misfirePolicy := "放弃执行" - if row.MisfirePolicy == "1" { + switch row.MisfirePolicy { + case "1": misfirePolicy = "立即执行" - } else if row.MisfirePolicy == "2" { + case "2": misfirePolicy = "执行一次" } concurrent := "禁止" diff --git a/src/modules/network_element/service/ne_license.go b/src/modules/network_element/service/ne_license.go index 59db136f..4daea13b 100644 --- a/src/modules/network_element/service/ne_license.go +++ b/src/modules/network_element/service/ne_license.go @@ -185,9 +185,10 @@ func (r *NeLicense) UploadLicense(neLicense model.NeLicense) error { // 重启服务 if neLicense.Reload { cmdStr := fmt.Sprintf("sudo systemctl restart %s", neTypeLower) - if neTypeLower == "ims" { + switch neTypeLower { + case "ims": cmdStr = "ims-stop || true && ims-start" - } else if neTypeLower == "omc" { + case "omc": cmdStr = "sudo systemctl restart omc" } sshClient.RunCMD(cmdStr) diff --git a/src/modules/network_element/service/ne_version.go b/src/modules/network_element/service/ne_version.go index 793e6663..a8662650 100644 --- a/src/modules/network_element/service/ne_version.go +++ b/src/modules/network_element/service/ne_version.go @@ -245,7 +245,8 @@ func (r NeVersion) operateCommand(action, neType string, neFilePaths []string) ( // 组合命令输入 cmdStrArr := []string{} - if neType == "OMC" { + switch neType { + case "OMC": omcStrArr := []string{} if action == "install" { // 安装软件包 @@ -270,7 +271,7 @@ func (r NeVersion) operateCommand(action, neType string, neFilePaths []string) ( cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 2s && %s\" > /tmp/operate_run_%s_omc.out 2>&1 & \n", strings.Join(omcStrArr, " && "), action)) cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr)) return okFlagStr, cmdStrArr, nil - } else if neType == "IMS" { + case "IMS": if action == "install" { para5GData := r.neInfoService.Para5GData cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") @@ -312,7 +313,7 @@ func (r NeVersion) operateCommand(action, neType string, neFilePaths []string) ( cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") cmdStrArr = append(cmdStrArr, "ims-start \n") } - } else { + default: if action == "install" { para5GData := r.neInfoService.Para5GData cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") diff --git a/src/modules/trace/service/trace_task.go b/src/modules/trace/service/trace_task.go index 2085f282..be335142 100644 --- a/src/modules/trace/service/trace_task.go +++ b/src/modules/trace/service/trace_task.go @@ -6,9 +6,10 @@ import ( "net" "strings" + "github.com/tsmask/go-oam/src/framework/socket" + "be.ems/src/framework/config" "be.ems/src/framework/logger" - "be.ems/src/framework/socket" "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/parse" neFetchlink "be.ems/src/modules/network_element/fetch_link" @@ -21,16 +22,14 @@ import ( // 实例化数据层 TraceTask 结构体 var NewTraceTask = &TraceTask{ - udpService: socket.SocketUDP{}, - tcpService: socket.SocketTCP{}, traceTaskRepository: repository.NewTraceTask, traceDataRepository: repository.NewTraceData, } // TraceTask 跟踪任务 服务层处理 type TraceTask struct { - udpService socket.SocketUDP // UDP服务对象 - tcpService socket.SocketTCP // 测试用,后续调整TODO + udpService socket.ServerUDP // UDP服务对象 + tcpService socket.ServerTCP // 测试用,后续调整TODO traceTaskRepository *repository.TraceTask // 跟踪_任务数据信息 traceDataRepository *repository.TraceData // 跟踪_数据信息 } @@ -48,8 +47,8 @@ func (r *TraceTask) CreateUDP(reload bool) error { } // 初始化UDP服务 - r.udpService = socket.SocketUDP{Addr: host, Port: port} - if _, err := r.udpService.New(); err != nil { + r.udpService = socket.ServerUDP{Addr: host, Port: fmt.Sprint(port)} + if err := r.udpService.Listen(); err != nil { return err } @@ -87,21 +86,20 @@ func (r *TraceTask) CreateUDP(reload bool) error { // ============ 本地测试接收网元UDP发过来的数据 后续调整TODO if config.Env() == "local" { // 初始化TCP服务 - r.tcpService = socket.SocketTCP{Addr: host, Port: port + 1} - if _, err := r.tcpService.New(); err != nil { + r.tcpService = socket.ServerTCP{Addr: host, Port: fmt.Sprint(port + 1)} + if err := r.tcpService.Listen(); err != nil { return err } // 接收处理TCP数据 - go r.tcpService.Resolve(func(conn *net.Conn, err error) { + go r.tcpService.Resolve(func(conn net.Conn, err error) { if err != nil { logger.Errorf("TCP Resolve %s", err.Error()) return } - c := (*conn) // 读取数据 buf := make([]byte, 2048) - n, err := c.Read(buf) + n, err := conn.Read(buf) if err != nil { logger.Errorf("TCP Resolve Read Error: %s", err.Error()) return @@ -117,7 +115,7 @@ func (r *TraceTask) CreateUDP(reload bool) error { } // 发送响应 - if _, err = c.Write([]byte("tcp>")); err != nil { + if _, err = conn.Write([]byte("tcp>")); err != nil { logger.Errorf("TCP Resolve Write Error: %s", err.Error()) } buf = nil diff --git a/src/modules/ws/service/ws_receive.go b/src/modules/ws/service/ws_receive.go index 4a1720f1..ad224f35 100644 --- a/src/modules/ws/service/ws_receive.go +++ b/src/modules/ws/service/ws_receive.go @@ -63,16 +63,10 @@ func (s *WSReceive) Commont(client *model.WSClient, reqMsg model.WSRequest) { resByte, err = processor.GetProcessData(reqMsg.RequestID, reqMsg.Data) case "net": resByte, err = processor.GetNetConnections(reqMsg.RequestID, reqMsg.Data) - case "ims_cdr": - resByte, err = processor.GetCDRConnectByIMS(reqMsg.RequestID, reqMsg.Data) - case "smf_cdr": - resByte, err = processor.GetCDRConnectBySMF(reqMsg.RequestID, reqMsg.Data) - case "smsc_cdr": - resByte, err = processor.GetCDRConnectBySMSC(reqMsg.RequestID, reqMsg.Data) - case "amf_ue": - resByte, err = processor.GetUEConnectByAMF(reqMsg.RequestID, reqMsg.Data) - case "mme_ue": - resByte, err = processor.GetUEConnectByMME(reqMsg.RequestID, reqMsg.Data) + case "ims_cdr", "smf_cdr", "smsc_cdr", "sgwc_cdr": + resByte, err = processor.GetCDRConnect(reqMsg.RequestID, reqMsg.Data) + case "amf_ue", "mme_ue": + resByte, err = processor.GetUEConnect(reqMsg.RequestID, reqMsg.Data) case "upf_tf": resByte, err = processor.GetUPFTotalFlow(reqMsg.RequestID, reqMsg.Data) case "ne_state": diff --git a/src/modules/ws/service/ws_send.go b/src/modules/ws/service/ws_send.go index adcccaef..b419e1fa 100644 --- a/src/modules/ws/service/ws_send.go +++ b/src/modules/ws/service/ws_send.go @@ -34,6 +34,10 @@ const ( GROUP_AMF_UE = "1010" // 组号-MME_UE会话事件 1011_neId GROUP_MME_UE = "1011" + // 组号-AMF_NB状态事件 1014_neId + GROUP_AMF_NB = "1014" + // 组号-MME_NB状态事件 1015_neId + GROUP_MME_NB = "1015" // 组号-告警 2000_neType_neId GROUP_ALARM = "2000" // 组号-告警事件 2002_neType_neId From be7da5717156c4745837f7c7963437d8ab8cc958 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 16:13:34 +0800 Subject: [PATCH 21/80] =?UTF-8?q?fix:=20=E6=9C=8D=E5=8A=A1=E7=9B=91?= =?UTF-8?q?=E5=90=AC=E5=A4=B1=E8=B4=A5=E6=AF=8F5=E7=A7=92=E9=87=8D?= =?UTF-8?q?=E8=AF=95=E6=9C=80=E5=A4=9A10=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 10 +-- main.go | 210 ++++++++++++++++++++------------------------ 2 files changed, 98 insertions(+), 122 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f549ed53..498a7341 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,14 +12,6 @@ "program": "main.go", "console": "integratedTerminal", "args": ["--env", "local", "-c", "./local/omc.yaml"] - }, - { - "name": "debug sshsvc", - "type": "go", - "request": "launch", - "mode": "debug", - "program": "sshsvc/sshsvc.go", - "console": "integratedTerminal" - } + } ] } \ No newline at end of file diff --git a/main.go b/main.go index 1a632049..9f070bf7 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "sync" + "time" _ "net/http/pprof" @@ -14,22 +15,17 @@ import ( swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" - "be.ems/features" - "be.ems/features/event" - "be.ems/features/mml" - featuresCfg "be.ems/lib/config" - "be.ems/lib/log" - "be.ems/lib/routes" "be.ems/src" "be.ems/src/framework/config" "be.ems/src/framework/logger" - "be.ems/src/framework/middleware" "be.ems/src/framework/utils/machine" "be.ems/src/framework/utils/parse" _ "be.ems/swagger_docs" ) -var wg sync.WaitGroup +var wg sync.WaitGroup // 等待服务 +var maxRetries = 10 // 最大重试次数 +var retryInterval = 5 * time.Second // 重试间隔时间 // @title OMC Swagger API // @version 1.0.8 @@ -156,9 +152,7 @@ func main() { src.ModulesRoute(app) - loadFeatures(app) - - loadServer(app) + loadServerRoute(app) loadServerWeb() @@ -167,33 +161,6 @@ func main() { wg.Wait() } -// loadFeatures mux路由模块 -func loadFeatures(app *gin.Engine) { - conf := featuresCfg.GetYamlConfig() - - log.InitLogger(conf.Logger.File, conf.Logger.Duration, conf.Logger.Count, "omc:restagent", featuresCfg.GetLogLevel()) - // fmt.Printf("OMC Version: %s\n", config.Version) - // log.Infof("========================= OMC Startup =========================") - // log.Infof("OMC Version: %s %s %s", config.Version, config.BuildTime, config.GoVer) - - mml.InitMML() - - // 将 mux.Router 注册到 gin.Engine - - // 默认路由组 - defaultUriGroup := app.Group(featuresCfg.DefaultUriPrefix) - defaultUriGroup.Use(middleware.AuthorizeUser(nil)) - defaultUriGroup.Any("/*any", gin.WrapH(routes.NewRouter())) - // 可配置前缀路由组 - uriGroup := app.Group(featuresCfg.UriPrefix) - uriGroup.Any("/*any", gin.WrapH(routes.NewRouter())) - // AMF上报的UE事件, 无前缀,暂时特殊处理 - app.POST(event.UriUEEventAMF, event.PostUEEventFromAMF) - - // register feature service gin.Engine - features.InitServiceEngine(app) -} - // loadGlobalPre 全局预加载 func loadGlobalPre(app *gin.Engine) { // Swagger 接口文档 @@ -217,61 +184,61 @@ func loadGlobalPre(app *gin.Engine) { wg.Add(1) go func(addr string) { defer wg.Done() - fmt.Println(http.ListenAndServe(addr, nil)) + for i := range maxRetries { + if err := http.ListenAndServe(addr, nil); err != nil { + logger.Errorf("pprof run err:%v", err) + time.Sleep(retryInterval) // 重试间隔时间 + logger.Warnf("trying to restart HTTP server on %s (Attempt %d)", addr, i) + } + } }(pprofAddr) } } -// loadServer 多个HTTP服务启动 -func loadServer(app *gin.Engine) { - httpArr := config.Get("server") - if httpArr == nil { - logger.Errorf("server config not found") +// loadServerRoute 多个HTTP服务启动-API服务 +func loadServerRoute(app *gin.Engine) { + routeArr := config.Get("routeServer") + if routeArr == nil { + logger.Errorf("routeServer config not found") return } - for _, v := range httpArr.([]any) { + for _, v := range routeArr.([]any) { item := v.(map[string]any) - port := parse.Number(item["port"]) - ipv4 := fmt.Sprint(item["ipv4"]) - ipv6 := fmt.Sprint(item["ipv6"]) + addr := fmt.Sprint(item["addr"]) + if addr == "" || addr == "" { + continue + } schema := fmt.Sprint(item["schema"]) if schema == "https" && schema != "" { certFile := fmt.Sprint(item["certfile"]) keyFile := fmt.Sprint(item["keyfile"]) - addr := "" - if ipv4 != "" && ipv4 != "" { - addr = fmt.Sprintf("%s:%d", ipv4, port) - } - if ipv6 != "" && ipv6 != "" { - addr = fmt.Sprintf("[%s]:%d", ipv6, port) - } - if addr == "" { + if certFile == "" || certFile == "" || keyFile == "" || keyFile == "" { continue } // 启动HTTPS服务 wg.Add(1) go func(addr string, certFile string, keyFile string) { defer wg.Done() - err := app.RunTLS(addr, certFile, keyFile) - logger.Errorf("run tls err:%v", err) + for i := range maxRetries { + if err := app.RunTLS(addr, certFile, keyFile); err != nil { + logger.Errorf("routeServer run tls err:%v", err) + time.Sleep(retryInterval) // 重试间隔时间 + logger.Warnf("trying to restart HTTPS server on %s (Attempt %d)", addr, i) + } + } }(addr, certFile, keyFile) } else { - addr := "" - if ipv4 != "" && ipv4 != "" { - addr = fmt.Sprintf("%s:%d", ipv4, port) - } - if ipv6 != "" && ipv6 != "" { - addr = fmt.Sprintf("[%s]:%d", ipv6, port) - } - if addr == "" { - continue - } // 启动HTTP服务 wg.Add(1) go func(addr string) { defer wg.Done() - err := app.Run(addr) - logger.Errorf("run err:%v", err) + for i := range maxRetries { + if err := app.Run(addr); err != nil { + logger.Errorf("routeServer run err:%v", err) + time.Sleep(retryInterval) // 重试间隔时间 + logger.Warnf("trying to restart HTTP server on %s (Attempt %d)", addr, i) + } + } }(addr) } } @@ -279,52 +246,69 @@ func loadServer(app *gin.Engine) { // loadServerWeb 多个HTTP服务启动-前端静态资源 func loadServerWeb() { - webEnabled := config.Get("webServer.enabled") - if webEnabled == nil { - logger.Errorf("webServer config not found") + webEnabled := parse.Boolean(config.Get("webServer.enabled")) + if !webEnabled { + logger.Warnf("webServer config not found") return } - if webEnabled.(bool) { - rootDir := config.Get("webServer.rootDir").(string) - if rootDir != "" { - var web *gin.Engine - gin.SetMode(gin.ReleaseMode) - web = gin.New() - web.Use(gin.Recovery()) - gin.DisableConsoleColor() - web.StaticFS("/", http.Dir(rootDir)) - // 多个HTTP服务启动 - listenArr := config.Get("webServer.listen") - for _, v := range listenArr.([]any) { - listen := v.(map[string]any) - addr := fmt.Sprint(listen["addr"]) - schema := fmt.Sprint(listen["schema"]) - if schema == "https" && schema != "" { - certFile := fmt.Sprint(listen["certfile"]) - keyFile := fmt.Sprint(listen["keyfile"]) - if addr == "" || addr == "" { - continue - } - // 启动HTTPS服务 - wg.Add(1) - go func(addr string, certFile string, keyFile string) { - defer wg.Done() - err := web.RunTLS(addr, certFile, keyFile) - logger.Errorf("web run tls err:%v", err) - }(addr, certFile, keyFile) - } else { - if addr == "" || addr == "" { - continue - } - // 启动HTTP服务 - wg.Add(1) - go func(addr string) { - defer wg.Done() - err := web.Run(addr) - logger.Errorf("web run err:%v", err) - }(addr) - } + rootDir := fmt.Sprint(config.Get("webServer.rootDir")) + if rootDir == "" || rootDir == "" { + logger.Warnf("webServer rootDir config not found") + return + } + + var web *gin.Engine = gin.New() + gin.SetMode(gin.ReleaseMode) + gin.DisableConsoleColor() + web.Use(gin.Recovery()) + web.StaticFS("/", http.Dir(rootDir)) + // 多个HTTP服务启动 + listenArr := config.Get("webServer.listen") + if listenArr == nil { + logger.Errorf("webServer listen config not found") + return + } + for _, v := range listenArr.([]any) { + listen := v.(map[string]any) + addr := fmt.Sprint(listen["addr"]) + if addr == "" || addr == "" { + continue + } + schema := fmt.Sprint(listen["schema"]) + if schema == "https" && schema != "" { + certFile := fmt.Sprint(listen["certfile"]) + keyFile := fmt.Sprint(listen["keyfile"]) + if certFile == "" || certFile == "" || keyFile == "" || keyFile == "" { + continue } + // 启动HTTPS服务 + wg.Add(1) + go func(addr string, certFile string, keyFile string) { + defer wg.Done() + for i := range maxRetries { + if err := web.RunTLS(addr, certFile, keyFile); err != nil { + logger.Errorf("webServer run tls err:%v", err) + time.Sleep(retryInterval) // 重试间隔时间 + logger.Warnf("trying to restart HTTPS server on %s (Attempt %d)", addr, i) + } + } + }(addr, certFile, keyFile) + } else { + if addr == "" || addr == "" { + continue + } + // 启动HTTP服务 + wg.Add(1) + go func(addr string) { + defer wg.Done() + for i := range maxRetries { + if err := web.Run(addr); err != nil { + logger.Errorf("webServer run err:%v", err) + time.Sleep(retryInterval) // 重试间隔时间 + logger.Warnf("trying to restart HTTP server on %s (Attempt %d)", addr, i) + } + } + }(addr) } } } From 45098970b654f90a4dfe906a4962898de4424b25 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 18:53:04 +0800 Subject: [PATCH 22/80] =?UTF-8?q?sql:=20=E6=9B=B4=E6=96=B0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/alarm.sql | 19 +- build/database/lite/install/alarm_event.sql | 11 +- .../lite/install/alarm_forward_log.sql | 4 +- build/database/lite/install/alarm_log.sql | 6 +- build/database/lite/install/sys_dict_data.sql | 36 +-- build/database/lite/install/sys_job.sql | 6 +- build/database/lite/install/sys_menu.sql | 4 +- build/database/lite/install/sys_role_menu.sql | 1 - build/database/lite/upgrade/upg_alarm.sql | 75 +++++ .../database/lite/upgrade/upg_alarm_event.sql | 53 ++++ .../lite/upgrade/upg_alarm_forward_log.sql | 40 +++ build/database/lite/upgrade/upg_alarm_log.sql | 37 +++ .../lite/upgrade/upg_sys_dict_data.sql | 194 ++++++++++++ build/database/lite/upgrade/upg_sys_job.sql | 50 +++ build/database/lite/upgrade/upg_sys_menu.sql | 201 ++++++++++++ .../lite/upgrade/upg_sys_role_menu.sql | 291 ++++++++++++++++++ build/database/std/install/alarm.sql | 24 +- build/database/std/install/alarm_event.sql | 10 +- .../std/install/alarm_forward_log.sql | 12 +- build/database/std/install/alarm_log.sql | 10 +- build/database/std/install/sys_dict_data.sql | 36 +-- build/database/std/install/sys_job.sql | 6 +- build/database/std/install/sys_menu.sql | 4 +- build/database/std/install/sys_role_menu.sql | 1 - build/database/std/install/ue_event.sql | 4 +- build/database/std/install/ue_event_amf.sql | 4 +- build/database/std/install/ue_event_mme.sql | 4 +- build/database/std/upgrade/upg_alarm.sql | 66 ++-- .../database/std/upgrade/upg_alarm_event.sql | 30 +- .../std/upgrade/upg_alarm_forward_log.sql | 37 ++- build/database/std/upgrade/upg_alarm_log.sql | 33 +- .../std/upgrade/upg_sys_dict_data.sql | 36 +-- build/database/std/upgrade/upg_sys_job.sql | 6 +- build/database/std/upgrade/upg_sys_menu.sql | 4 +- .../std/upgrade/upg_sys_role_menu.sql | 1 - build/database/std/upgrade/upg_ue_event.sql | 8 +- .../database/std/upgrade/upg_ue_event_amf.sql | 12 +- .../database/std/upgrade/upg_ue_event_mme.sql | 12 +- 38 files changed, 1193 insertions(+), 195 deletions(-) create mode 100644 build/database/lite/upgrade/upg_alarm.sql create mode 100644 build/database/lite/upgrade/upg_alarm_event.sql create mode 100644 build/database/lite/upgrade/upg_alarm_forward_log.sql create mode 100644 build/database/lite/upgrade/upg_alarm_log.sql create mode 100644 build/database/lite/upgrade/upg_sys_dict_data.sql create mode 100644 build/database/lite/upgrade/upg_sys_job.sql create mode 100644 build/database/lite/upgrade/upg_sys_menu.sql create mode 100644 build/database/lite/upgrade/upg_sys_role_menu.sql diff --git a/build/database/lite/install/alarm.sql b/build/database/lite/install/alarm.sql index 094631bd..31dd1b40 100644 --- a/build/database/lite/install/alarm.sql +++ b/build/database/lite/install/alarm.sql @@ -15,22 +15,22 @@ CREATE TABLE "alarm" ( "alarm_code" integer(11), "event_time" integer(20), "alarm_type" text(64), - "orig_severity" text(10), - "perceived_severity" text(10), + "orig_severity" text(64), + "perceived_severity" text(64), "object_uid" text(64), "object_name" text(64), "object_type" text(20), "location_info" text(2048), - "alarm_status" text(10), + "alarm_status" text(64), "specific_problem" text(255), "specific_problem_id" text(100), "add_info" text(2048), - "ack_state" integer(11), + "ack_state" text(64), "ack_time" integer(20), - "ack_user" text(16), - "clear_type" integer(11), + "ack_user" text(64), + "clear_type" text(64), "clear_time" integer(20), - "clear_user" text(16), + "clear_user" text(64), "timestamp" integer(20), PRIMARY KEY ("id") ); @@ -44,12 +44,11 @@ ON "alarm" ( "orig_severity" ASC, "event_time" ASC ); -CREATE UNIQUE INDEX "uk_uni_aid_ne_aseq" +CREATE UNIQUE INDEX "uk_uni_ne_aid" ON "alarm" ( "ne_type" ASC, "ne_id" ASC, - "alarm_id" ASC, - "alarm_seq" ASC + "alarm_id" ASC ); -- ---------------------------- diff --git a/build/database/lite/install/alarm_event.sql b/build/database/lite/install/alarm_event.sql index 8a398a66..8145b4ab 100644 --- a/build/database/lite/install/alarm_event.sql +++ b/build/database/lite/install/alarm_event.sql @@ -15,13 +15,13 @@ CREATE TABLE "alarm_event" ( "object_name" text(64), "object_type" text(20), "location_info" text(2048), - "alarm_status" text(10), + "alarm_status" text(64), "specific_problem" text(255), "specific_problem_id" text(100), "add_info" text(2048), - "clear_type" integer(11), + "clear_type" text(64), "clear_time" integer(20), - "clear_user" text(16), + "clear_user" text(64), "timestamp" integer(20), PRIMARY KEY ("id") ); @@ -34,12 +34,11 @@ ON "alarm_event" ( "alarm_status" ASC, "event_time" ASC ); -CREATE UNIQUE INDEX "uk_ti_aid_aseq" +CREATE UNIQUE INDEX "uk_ti_aid" ON "alarm_event" ( "ne_type" ASC, "ne_id" ASC, - "alarm_id" ASC, - "alarm_seq" ASC + "alarm_id" ASC ); -- ---------------------------- diff --git a/build/database/lite/install/alarm_forward_log.sql b/build/database/lite/install/alarm_forward_log.sql index 6235f395..86eafc94 100644 --- a/build/database/lite/install/alarm_forward_log.sql +++ b/build/database/lite/install/alarm_forward_log.sql @@ -10,8 +10,8 @@ CREATE TABLE "alarm_forward_log" ( "alarm_id" text(32), "alarm_code" integer(11), "alarm_title" text(255), - "alarm_status" text(10), - "alarm_type" text(10), + "alarm_status" text(64), + "alarm_type" text(64), "orig_severity" text(10), "event_time" integer(20), "created_at" integer(20), diff --git a/build/database/lite/install/alarm_log.sql b/build/database/lite/install/alarm_log.sql index 0e942b41..9bb727a3 100644 --- a/build/database/lite/install/alarm_log.sql +++ b/build/database/lite/install/alarm_log.sql @@ -10,9 +10,9 @@ CREATE TABLE "alarm_log" ( "alarm_id" text(32), "alarm_code" integer(11), "alarm_title" text(255), - "alarm_status" text(10), - "alarm_type" text(10), - "orig_severity" text(10), + "alarm_status" text(64), + "alarm_type" text(64), + "orig_severity" text(64), "event_time" integer(20), "created_at" integer(20), PRIMARY KEY ("id") diff --git a/build/database/lite/install/sys_dict_data.sql b/build/database/lite/install/sys_dict_data.sql index 9e7049ca..de9062dc 100644 --- a/build/database/lite/install/sys_dict_data.sql +++ b/build/database/lite/install/sys_dict_data.sql @@ -60,21 +60,21 @@ INSERT INTO "sys_dict_data" VALUES (34, 'sys_role_datascope', 'dictData.datascop INSERT INTO "sys_dict_data" VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (36, 'sys_role_datascope', 'dictData.datascope.deptAndChid', '4', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (37, 'sys_role_datascope', 'dictData.datascope.self', '5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', '2', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', '3', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', '4', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', '5', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', '0', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', '2', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', '0', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', '2', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', '3', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', '4', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', '5', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', 'CommunicationAlarm', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', 'EquipmentAlarm', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', 'ProcessingFailure', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', 'EnvironmentalAlarm', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', 'QualityOfServiceAlarm', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', 'NotClear', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', 'AutoClear', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', 'ManualClear', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', 'NotAck', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', 'Ack', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', 'Critical', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', 'Major', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', 'Minor', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', 'Warning', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', 'Event', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (53, 'index_status', 'dictType.index_status.normal', 'normal', 1, '#91cc75', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (54, 'index_status', 'dictType.index_status.abnormal', 'abnormal', 2, '#ee6666', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (55, 'cdr_sip_code', 'dictData.cdr_sip_code.200', '200', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); @@ -91,9 +91,9 @@ INSERT INTO "sys_dict_data" VALUES (65, 'ue_auth_code', 'dictData.ue_auth_code.0 INSERT INTO "sys_dict_data" VALUES (66, 'ue_auth_code', 'dictData.ue_auth_code.005', '005', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (67, 'ue_auth_code', 'dictData.ue_auth_code.006', '006', 6, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (68, 'ue_auth_code', 'dictData.ue_auth_code.007', '007', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'auth-result', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'cm-state', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'Auth', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'Detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'CM', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (72, 'ue_event_cm_state', 'dictData.ue_event_cm_state.connected', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (73, 'ue_event_cm_state', 'dictData.ue_event_cm_state.idle', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (74, 'ue_event_cm_state', 'dictData.ue_event_cm_state.inactive', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/lite/install/sys_job.sql b/build/database/lite/install/sys_job.sql index 1c9a85b4..0e16f7b4 100644 --- a/build/database/lite/install/sys_job.sql +++ b/build/database/lite/install/sys_job.sql @@ -41,9 +41,9 @@ INSERT INTO "sys_job" VALUES (10, 'job.delete_ne_config_backup', 'SYSTEM', 'dele INSERT INTO "sys_job" VALUES (11, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{"storeDays":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); INSERT INTO "sys_job" VALUES (12, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{"storeDays":7,"neList":["IMS","AMF","UDM","UPF","MME","SMSC","SMF","MME"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); -INSERT INTO "sys_job" VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{"alarmTitle":"NE State Check Alarm","alarmType":"2","origSeverity":"2","specificProblem":"alarm cause: the system state of target NE has not been received","specificProblemId":"AC10000","addInfo":""}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); -INSERT INTO "sys_job" VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{"alarmTitle":"NE State Check Alarm CPU/Menory/Disk","alarmType":"2","origSeverity":"2","specificProblem":"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold","specificProblemId":"AC10100","addInfo":"","cpuUseGt":70,"memUseGt":70,"diskUseGt":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); -INSERT INTO "sys_job" VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{"alarmTitle":"NE State Check Alarm License","alarmType":"2","origSeverity":"2","specificProblem":"Alarm Cause: License received from target NE is about to expire","specificProblemId":"AC10200","addInfo":"","dayLt":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); +INSERT INTO "sys_job" VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{"alarmTitle":"NE State Check Alarm","alarmType":"EquipmentAlarm","origSeverity":"Major","specificProblem":"alarm cause: the system state of target NE has not been received","specificProblemId":"AC10000","addInfo":""}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); +INSERT INTO "sys_job" VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{"alarmTitle":"NE State Check Alarm CPU/Menory/Disk","alarmType":"EquipmentAlarm","origSeverity":"Major","specificProblem":"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold","specificProblemId":"AC10100","addInfo":"","cpuUseGt":70,"memUseGt":70,"diskUseGt":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); +INSERT INTO "sys_job" VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{"alarmTitle":"NE State Check Alarm License","alarmType":"EquipmentAlarm","origSeverity":"Major","specificProblem":"Alarm Cause: License received from target NE is about to expire","specificProblemId":"AC10200","addInfo":"","dayLt":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); INSERT INTO "sys_job" VALUES (30, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{"backupPath":"/udm_data/auth","storeDays":30},{"backupPath":"/udm_data/sub","storeDays":30},{"backupPath":"/udm_data/voip","storeDays":30},{"backupPath":"/udm_data/volte","storeDays":30},{"backupPath":"/cdr/ims_cdr_event","storeDays":30},{"backupPath":"/cdr/smsc_cdr_event","storeDays":30},{"backupPath":"/cdr/smf_cdr_event","storeDays":30},{"backupPath":"/cdr/sgwc_cdr_event","storeDays":30},{"backupPath":"/log/sys_log_operate","storeDays":30,"storeNum":7},{"backupPath":"/log/sys_log_login","storeDays":30,"storeNum":7}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); INSERT INTO "sys_job" VALUES (31, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{"dataType":["auth","sub","voip","volte"],"fileType":"txt"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); diff --git a/build/database/lite/install/sys_menu.sql b/build/database/lite/install/sys_menu.sql index 410e77b6..fd85055a 100644 --- a/build/database/lite/install/sys_menu.sql +++ b/build/database/lite/install/sys_menu.sql @@ -146,8 +146,8 @@ INSERT INTO "sys_menu" VALUES (2106, 'menu.perf.kpiKeyTarget', 2099, 12, 'kpiKey INSERT INTO "sys_menu" VALUES (2107, 'menu.mml', 0, 8, 'mmlManage', '', '1', '0', 'D', '1', '1', '', 'icon-zhizuoliucheng', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mmlRemark'); INSERT INTO "sys_menu" VALUES (2108, 'menu.mml.ne', 2107, 1, 'neOperate', 'mmlManage/neOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:neOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.neRemark'); INSERT INTO "sys_menu" VALUES (2109, 'menu.mml.udm', 2107, 2, 'udmOperate', 'mmlManage/udmOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:udmOperate:index', 'icon-gonggaodayi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.udmRemark'); -INSERT INTO "sys_menu" VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '1', '1', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.setRemark'); -INSERT INTO "sys_menu" VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.omcRemark'); +INSERT INTO "sys_menu" VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '0', '0', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.setRemark'); +INSERT INTO "sys_menu" VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '0', '0', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.omcRemark'); INSERT INTO "sys_menu" VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'sgwc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2113, 'menu.security', 0, 14, 'security', '', '1', '0', 'D', '1', '1', '', 'icon-suofang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.securityRemark'); INSERT INTO "sys_menu" VALUES (2114, 'menu.system.systemSet', 1, 60, 'setting', 'system/setting/index', '1', '1', 'M', '1', '1', 'system:setting:index', 'icon-piliang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemSetRemark'); diff --git a/build/database/lite/install/sys_role_menu.sql b/build/database/lite/install/sys_role_menu.sql index fb6c3455..a73b884f 100644 --- a/build/database/lite/install/sys_role_menu.sql +++ b/build/database/lite/install/sys_role_menu.sql @@ -198,7 +198,6 @@ INSERT INTO "sys_role_menu" VALUES (3, 2097); INSERT INTO "sys_role_menu" VALUES (3, 2107); INSERT INTO "sys_role_menu" VALUES (3, 2108); INSERT INTO "sys_role_menu" VALUES (3, 2109); -INSERT INTO "sys_role_menu" VALUES (3, 2111); INSERT INTO "sys_role_menu" VALUES (3, 2113); INSERT INTO "sys_role_menu" VALUES (3, 2114); INSERT INTO "sys_role_menu" VALUES (3, 2115); diff --git a/build/database/lite/upgrade/upg_alarm.sql b/build/database/lite/upgrade/upg_alarm.sql new file mode 100644 index 00000000..dbb993b7 --- /dev/null +++ b/build/database/lite/upgrade/upg_alarm.sql @@ -0,0 +1,75 @@ +-- ---------------------------- +-- Table structure for alarm +-- ---------------------------- +UPDATE "alarm" SET "alarm_type" = 'CommunicationAlarm' WHERE "alarm_type" = '1'; +UPDATE "alarm" SET "alarm_type" = 'EquipmentAlarm' WHERE "alarm_type" = '2'; +UPDATE "alarm" SET "alarm_type" = 'ProcessingFailure' WHERE "alarm_type" = '3'; +UPDATE "alarm" SET "alarm_type" = 'EnvironmentalAlarm' WHERE "alarm_type" = '4'; +UPDATE "alarm" SET "alarm_type" = 'QualityOfServiceAlarm' WHERE "alarm_type" = '5'; +UPDATE "alarm" SET "orig_severity" = 'Critical', "perceived_severity" = 'Critical' WHERE "orig_severity" = '1'; +UPDATE "alarm" SET "orig_severity" = 'Major', "perceived_severity" = 'Major' WHERE "orig_severity" = '2'; +UPDATE "alarm" SET "orig_severity" = 'Minor', "perceived_severity" = 'Minor' WHERE "orig_severity" = '3'; +UPDATE "alarm" SET "orig_severity" = 'Warning', "perceived_severity" = 'Warning' WHERE "orig_severity" = '4'; +UPDATE "alarm" SET "orig_severity" = 'Event', "perceived_severity" = 'Event' WHERE "orig_severity" = '5'; +UPDATE "alarm" SET "alarm_status" = 'Clear' WHERE "alarm_status" = '0'; +UPDATE "alarm" SET "alarm_status" = 'Active' WHERE "alarm_status" = '1'; +UPDATE "alarm" SET "ack_state" = 'NotAck' WHERE "ack_state" = '0'; +UPDATE "alarm" SET "ack_state" = 'Ack' WHERE "ack_state" = '1'; +UPDATE "alarm" SET "clear_type" = 'NotClear' WHERE "clear_type" = '0'; +UPDATE "alarm" SET "clear_type" = 'AutoClear' WHERE "clear_type" = '1'; +UPDATE "alarm" SET "clear_type" = 'ManualClear' WHERE "clear_type" = '2'; +ALTER TABLE "alarm" RENAME TO "alarm_old"; +CREATE TABLE "alarm" ( + "id" integer NOT NULL, + "ne_type" text(32) NOT NULL, + "ne_id" text(64) NOT NULL, + "ne_name" text(32), + "province" text(32), + "pv_flag" text(10), + "alarm_seq" integer(11), + "alarm_id" text(32) NOT NULL, + "alarm_title" text(255), + "alarm_code" integer(11), + "event_time" integer(20), + "alarm_type" text(64), + "orig_severity" text(64), + "perceived_severity" text(64), + "object_uid" text(64), + "object_name" text(64), + "object_type" text(20), + "location_info" text(2048), + "alarm_status" text(64), + "specific_problem" text(255), + "specific_problem_id" text(100), + "add_info" text(2048), + "ack_state" text(64), + "ack_time" integer(20), + "ack_user" text(64), + "clear_type" text(64), + "clear_time" integer(20), + "clear_user" text(64), + "timestamp" integer(20), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Indexes structure for table alarm +-- ---------------------------- +CREATE INDEX IF NOT EXISTS "idx_status_severity_time" +ON "alarm" ( + "alarm_status" ASC, + "orig_severity" ASC, + "event_time" ASC +); +CREATE UNIQUE INDEX IF NOT EXISTS "uk_uni_ne_aid" +ON "alarm" ( + "ne_type" ASC, + "ne_id" ASC, + "alarm_id" ASC +); + +-- ---------------------------- +-- Records of alarm +-- ---------------------------- +INSERT INTO "alarm" ("id", "ne_type", "ne_id", "ne_name", "province", "pv_flag", "alarm_seq", "alarm_id", "alarm_title", "alarm_code", "event_time", "alarm_type", "orig_severity", "perceived_severity", "object_uid", "object_name", "object_type", "location_info", "alarm_status", "specific_problem", "specific_problem_id", "add_info", "ack_state", "ack_time", "ack_user", "clear_type", "clear_time", "clear_user", "timestamp") SELECT "id", "ne_type", "ne_id", "ne_name", "province", "pv_flag", "alarm_seq", "alarm_id", "alarm_title", "alarm_code", "event_time", "alarm_type", "orig_severity", "perceived_severity", "object_uid", "object_name", "object_type", "location_info", "alarm_status", "specific_problem", "specific_problem_id", "add_info", "ack_state", "ack_time", "ack_user", "clear_type", "clear_time", "clear_user", "timestamp" FROM "alarm_old"; +DROP TABLE IF EXISTS "alarm_old"; diff --git a/build/database/lite/upgrade/upg_alarm_event.sql b/build/database/lite/upgrade/upg_alarm_event.sql new file mode 100644 index 00000000..b8e5a583 --- /dev/null +++ b/build/database/lite/upgrade/upg_alarm_event.sql @@ -0,0 +1,53 @@ +-- ---------------------------- +-- Table structure for alarm_event +-- ---------------------------- +UPDATE "alarm_event" SET "alarm_status" = 'Clear' WHERE "alarm_status" = '0'; +UPDATE "alarm_event" SET "alarm_status" = 'Active' WHERE "alarm_status" = '1'; +UPDATE "alarm_event" SET "clear_type" = 'NotClear' WHERE "clear_type" = '0'; +UPDATE "alarm_event" SET "clear_type" = 'AutoClear' WHERE "clear_type" = '1'; +UPDATE "alarm_event" SET "clear_type" = 'ManualClear' WHERE "clear_type" = '2'; +ALTER TABLE "alarm_event" RENAME TO "alarm_event_old"; +CREATE TABLE "alarm_event" ( + "id" integer NOT NULL, + "ne_type" text(32) NOT NULL, + "ne_id" text(64) NOT NULL, + "alarm_seq" integer(11), + "alarm_id" text(32) NOT NULL, + "alarm_title" text(255), + "alarm_code" integer(11), + "event_time" integer(20), + "object_uid" text(64), + "object_name" text(64), + "object_type" text(20), + "location_info" text(2048), + "alarm_status" text(64), + "specific_problem" text(255), + "specific_problem_id" text(100), + "add_info" text(2048), + "clear_type" text(64), + "clear_time" integer(20), + "clear_user" text(64), + "timestamp" integer(20), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Indexes structure for table alarm_event +-- ---------------------------- +CREATE INDEX IF NOT EXISTS "idx_astatus_etime" +ON "alarm_event" ( + "alarm_status" ASC, + "event_time" ASC +); +CREATE UNIQUE INDEX IF NOT EXISTS "uk_ti_aid" +ON "alarm_event" ( + "ne_type" ASC, + "ne_id" ASC, + "alarm_id" ASC +); + +-- ---------------------------- +-- Records of alarm_event +-- ---------------------------- +INSERT INTO "alarm_event" ("id", "ne_type", "ne_id", "alarm_seq", "alarm_id", "alarm_title", "alarm_code", "event_time", "object_uid", "object_name", "object_type", "location_info", "alarm_status", "specific_problem", "specific_problem_id", "add_info", "clear_type", "clear_time", "clear_user", "timestamp") SELECT "id", "ne_type", "ne_id", "alarm_seq", "alarm_id", "alarm_title", "alarm_code", "event_time", "object_uid", "object_name", "object_type", "location_info", "alarm_status", "specific_problem", "specific_problem_id", "add_info", "clear_type", "clear_time", "clear_user", "timestamp" FROM "alarm_event_old"; +DROP TABLE IF EXISTS "alarm_event_old"; diff --git a/build/database/lite/upgrade/upg_alarm_forward_log.sql b/build/database/lite/upgrade/upg_alarm_forward_log.sql new file mode 100644 index 00000000..93e5a7e7 --- /dev/null +++ b/build/database/lite/upgrade/upg_alarm_forward_log.sql @@ -0,0 +1,40 @@ +-- ---------------------------- +-- Table structure for alarm_forward_log +-- ---------------------------- +UPDATE "alarm_forward_log" SET "alarm_type" = 'CommunicationAlarm' WHERE "alarm_type" = '1'; +UPDATE "alarm_forward_log" SET "alarm_type" = 'EquipmentAlarm' WHERE "alarm_type" = '2'; +UPDATE "alarm_forward_log" SET "alarm_type" = 'ProcessingFailure' WHERE "alarm_type" = '3'; +UPDATE "alarm_forward_log" SET "alarm_type" = 'EnvironmentalAlarm' WHERE "alarm_type" = '4'; +UPDATE "alarm_forward_log" SET "alarm_type" = 'QualityOfServiceAlarm' WHERE "alarm_type" = '5'; +UPDATE "alarm_forward_log" SET "orig_severity" = 'Critical' WHERE "orig_severity" = '1'; +UPDATE "alarm_forward_log" SET "orig_severity" = 'Major' WHERE "orig_severity" = '2'; +UPDATE "alarm_forward_log" SET "orig_severity" = 'Minor' WHERE "orig_severity" = '3'; +UPDATE "alarm_forward_log" SET "orig_severity" = 'Warning' WHERE "orig_severity" = '4'; +UPDATE "alarm_forward_log" SET "orig_severity" = 'Event' WHERE "orig_severity" = '5'; +UPDATE "alarm_forward_log" SET "alarm_status" = 'Clear' WHERE "alarm_status" = '0'; +UPDATE "alarm_forward_log" SET "alarm_status" = 'Active' WHERE "alarm_status" = '1'; +ALTER TABLE "alarm_forward_log" RENAME TO "alarm_forward_log_old"; +CREATE TABLE "alarm_forward_log" ( + "id" integer NOT NULL, + "ne_type" text(16), + "ne_id" text(64) NOT NULL, + "alarm_seq" integer(11), + "alarm_id" text(32), + "alarm_code" integer(11), + "alarm_title" text(255), + "alarm_status" text(64), + "alarm_type" text(64), + "orig_severity" text(10), + "event_time" integer(20), + "created_at" integer(20), + "type" text(255), + "target" text(255), + "result" text(255), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Records of alarm_forward_log +-- ---------------------------- +INSERT INTO "alarm_forward_log" ("id", "ne_type", "ne_id", "alarm_seq", "alarm_id", "alarm_code", "alarm_title", "alarm_status", "alarm_type", "orig_severity", "event_time", "created_at", "type", "target", "result") SELECT "id", "ne_type", "ne_id", "alarm_seq", "alarm_id", "alarm_code", "alarm_title", "alarm_status", "alarm_type", "orig_severity", "event_time", "created_at", "type", "target", "result" FROM "alarm_forward_log_old"; +DROP TABLE IF EXISTS "alarm_forward_log_old"; diff --git a/build/database/lite/upgrade/upg_alarm_log.sql b/build/database/lite/upgrade/upg_alarm_log.sql new file mode 100644 index 00000000..66b78694 --- /dev/null +++ b/build/database/lite/upgrade/upg_alarm_log.sql @@ -0,0 +1,37 @@ +-- ---------------------------- +-- Table structure for alarm_log +-- ---------------------------- +UPDATE "alarm_log" SET "alarm_type" = 'CommunicationAlarm' WHERE "alarm_type" = '1'; +UPDATE "alarm_log" SET "alarm_type" = 'EquipmentAlarm' WHERE "alarm_type" = '2'; +UPDATE "alarm_log" SET "alarm_type" = 'ProcessingFailure' WHERE "alarm_type" = '3'; +UPDATE "alarm_log" SET "alarm_type" = 'EnvironmentalAlarm' WHERE "alarm_type" = '4'; +UPDATE "alarm_log" SET "alarm_type" = 'QualityOfServiceAlarm' WHERE "alarm_type" = '5'; +UPDATE "alarm_log" SET "orig_severity" = 'Critical' WHERE "orig_severity" = '1'; +UPDATE "alarm_log" SET "orig_severity" = 'Major' WHERE "orig_severity" = '2'; +UPDATE "alarm_log" SET "orig_severity" = 'Minor' WHERE "orig_severity" = '3'; +UPDATE "alarm_log" SET "orig_severity" = 'Warning' WHERE "orig_severity" = '4'; +UPDATE "alarm_log" SET "orig_severity" = 'Event' WHERE "orig_severity" = '5'; +UPDATE "alarm_log" SET "alarm_status" = 'Clear' WHERE "alarm_status" = '0'; +UPDATE "alarm_log" SET "alarm_status" = 'Active' WHERE "alarm_status" = '1'; +ALTER TABLE "alarm_log" RENAME TO "alarm_log_old"; +CREATE TABLE "alarm_log" ( + "id" integer NOT NULL, + "ne_type" text(16), + "ne_id" text(64) NOT NULL, + "alarm_seq" integer(11), + "alarm_id" text(32), + "alarm_code" integer(11), + "alarm_title" text(255), + "alarm_status" text(64), + "alarm_type" text(64), + "orig_severity" text(64), + "event_time" integer(20), + "created_at" integer(20), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Records of alarm_log +-- ---------------------------- +INSERT INTO "alarm_log" ("id", "ne_type", "ne_id", "alarm_seq", "alarm_id", "alarm_code", "alarm_title", "alarm_status", "alarm_type", "orig_severity", "event_time", "created_at") SELECT "id", "ne_type", "ne_id", "alarm_seq", "alarm_id", "alarm_code", "alarm_title", "alarm_status", "alarm_type", "orig_severity", "event_time", "created_at" FROM "alarm_log_old"; +DROP TABLE IF EXISTS "alarm_log_old"; diff --git a/build/database/lite/upgrade/upg_sys_dict_data.sql b/build/database/lite/upgrade/upg_sys_dict_data.sql new file mode 100644 index 00000000..5cc0ad84 --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_dict_data.sql @@ -0,0 +1,194 @@ +-- ---------------------------- +-- Table structure for sys_dict_data +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_dict_data" ( + "data_id" integer NOT NULL, + "dict_type" text(64) NOT NULL, + "data_label" text(255) NOT NULL, + "data_value" text(512) NOT NULL, + "data_sort" integer(11), + "tag_class" text(64), + "tag_type" text(12), + "status_flag" text(1), + "del_flag" text(1), + "create_by" text(64), + "create_time" integer(20), + "update_by" text(64), + "update_time" integer(20), + "remark" text(500), + PRIMARY KEY ("data_id") +); + +-- ---------------------------- +-- Records of sys_dict_data +-- ---------------------------- +REPLACE INTO "sys_dict_data" VALUES (1, 'sys_user_sex', 'dictData.sex.un', '0', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (2, 'sys_user_sex', 'dictData.sex.male', '1', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (3, 'sys_user_sex', 'dictData.sex.female', '2', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (4, 'sys_show_hide', 'dictData.show', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (5, 'sys_show_hide', 'dictData.hide', '0', 2, '', 'error', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (6, 'sys_normal_disable', 'dictData.normal', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (7, 'sys_normal_disable', 'dictData.disable', '0', 2, '', 'error', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (8, 'sys_yes_no', 'dictData.yes', 'Y', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (9, 'sys_yes_no', 'dictData.no', 'N', 2, '', 'error', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (10, 'sys_common_status', 'dictData.success', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (11, 'sys_common_status', 'dictData.fail', '0', 2, '', 'error', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (12, 'sys_job_status', 'dictData.jobStatus.normal', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (13, 'sys_job_status', 'dictData.jobStatus.pause', '0', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (14, 'sys_job_group', 'dictData.jobGroup.Default', 'DEFAULT', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (15, 'sys_job_group', 'dictData.jobGroup.System', 'SYSTEM', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (16, 'sys_oper_type', 'dictData.operType.other', '0', 1, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (17, 'sys_oper_type', 'dictData.operType.add', '1', 2, '', 'blue', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (18, 'sys_oper_type', 'dictData.operType.edit', '2', 3, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (19, 'sys_oper_type', 'dictData.operType.delete', '3', 4, '', 'red', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (20, 'sys_oper_type', 'dictData.operType.auth', '4', 5, '', '#108ee9', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (21, 'sys_oper_type', 'dictData.operType.export', '5', 6, '', 'orange', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (22, 'sys_oper_type', 'dictData.operType.import', '6', 7, '', 'orange', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (23, 'sys_oper_type', 'dictData.operType.forced quit', '7', 8, '', 'default', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (24, 'sys_oper_type', 'dictData.operType.clear', '8', 9, '', '#f50', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (25, 'trace_type', 'dictData.trace.interface', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (26, 'trace_type', 'dictData.trace.device', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (27, 'trace_type', 'dictData.trace.user', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (28, 'sys_job_save_log', 'dictData.jobSaveLog.no', '0', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (29, 'sys_job_save_log', 'dictData.jobSaveLog.yes', '1', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (30, 'ne_host_type', 'dictData.ne_host_type.redis', 'redis', 2, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', '0', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', '1', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (33, 'sys_role_datascope', 'dictData.datascope.all', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (34, 'sys_role_datascope', 'dictData.datascope.custom', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (36, 'sys_role_datascope', 'dictData.datascope.deptAndChid', '4', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (37, 'sys_role_datascope', 'dictData.datascope.self', '5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', 'CommunicationAlarm', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', 'EquipmentAlarm', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', 'ProcessingFailure', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', 'EnvironmentalAlarm', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', 'QualityOfServiceAlarm', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', 'NotClear', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', 'AutoClear', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', 'ManualClear', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', 'NotAck', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', 'Ack', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', 'Critical', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', 'Major', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', 'Minor', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', 'Warning', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', 'Event', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (53, 'index_status', 'dictType.index_status.normal', 'normal', 1, '#91cc75', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (54, 'index_status', 'dictType.index_status.abnormal', 'abnormal', 2, '#ee6666', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (55, 'cdr_sip_code', 'dictData.cdr_sip_code.200', '200', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (56, 'cdr_sip_code', 'dictData.cdr_sip_code.403', '403', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (57, 'cdr_sip_code', 'dictData.cdr_sip_code.408', '408', 13, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (58, 'cdr_sip_code', 'dictData.cdr_sip_code.500', '500', 16, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (59, 'cdr_call_type', 'dictData.cdr_call_type.audio', 'audio', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (60, 'cdr_call_type', 'dictData.cdr_call_type.video', 'video', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (61, 'ue_auth_code', 'dictData.ue_auth_code.200', '200', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (62, 'ue_auth_code', 'dictData.ue_auth_code.001', '001', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (63, 'ue_auth_code', 'dictData.ue_auth_code.002', '002', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (64, 'ue_auth_code', 'dictData.ue_auth_code.003', '003', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (65, 'ue_auth_code', 'dictData.ue_auth_code.004', '004', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (66, 'ue_auth_code', 'dictData.ue_auth_code.005', '005', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (67, 'ue_auth_code', 'dictData.ue_auth_code.006', '006', 6, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (68, 'ue_auth_code', 'dictData.ue_auth_code.007', '007', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'Auth', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'Detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'CM', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (72, 'ue_event_cm_state', 'dictData.ue_event_cm_state.connected', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (73, 'ue_event_cm_state', 'dictData.ue_event_cm_state.idle', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (74, 'ue_event_cm_state', 'dictData.ue_event_cm_state.inactive', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (75, 'cdr_sip_code', 'dictData.cdr_sip_code.404', '404', 6, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (76, 'cdr_sip_code', 'dictData.cdr_sip_code.487', '487', 12, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (77, 'cdr_sip_code', 'dictData.cdr_sip_code.503', '503', 17, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (78, 'cdr_sip_code', 'dictData.cdr_sip_code.504', '504', 18, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (79, 'cdr_sip_code', 'dictData.cdr_sip_code.603', '603', 21, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (80, 'cdr_sip_code', 'dictData.cdr_sip_code.606', '606', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (81, 'cdr_sip_code', 'dictData.cdr_sip_code.202', '202', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (82, 'cdr_call_type', 'dictData.cdr_call_type.sms', 'sms', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (83, 'cdr_sip_code', 'dictData.cdr_sip_code.488', '488', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (84, 'cdr_sip_code', 'dictData.cdr_sip_code.0', '0', 99, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (85, 'ne_host_type', 'dictData.ne_host_type.ssh', 'ssh', 0, '', 'blue', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (86, 'ne_host_type', 'dictData.ne_host_type.telnet', 'telnet', 1, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (87, 'ne_host_groupId', 'dictData.ne_host_groupId.0', '0', 0, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (88, 'ne_host_groupId', 'dictData.ne_host_groupId.1', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (89, 'ne_host_groupId', 'dictData.ne_host_groupId.2', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (90, 'ne_host_authMode', 'dictData.ne_host_authMode.0', '0', 0, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (91, 'ne_host_authMode', 'dictData.ne_host_authMode.1', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (92, 'ne_host_cmd_groupId', 'dictData.ne_host_cmd_groupId.0', '0', 0, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (93, 'ne_host_cmd_groupId', 'dictData.ne_host_cmd_groupId.1', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (94, 'ne_info_status', 'dictData.ne_info_status.0', '0', 0, '', 'error', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (95, 'ne_info_status', 'dictData.ne_info_status.1', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (96, 'ne_info_status', 'dictData.ne_info_status.2', '2', 2, '', 'orange', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (97, 'ne_info_status', 'dictData.ne_info_status.3', '3', 3, '', 'blue', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (98, 'ne_license_status', 'dictData.ne_license_status.0', '0', 0, '', 'warning', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (99, 'ne_license_status', 'dictData.ne_license_status.1', '1', 1, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (100, 'ne_host_authMode', 'dictData.ne_host_authMode.2', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (101, 'ne_version_status', 'dictData.ne_version_status.0', '0', 0, '', 'default', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (102, 'ne_version_status', 'dictData.ne_version_status.1', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (103, 'ne_version_status', 'dictData.ne_version_status.2', '2', 1, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (104, 'ne_version_status', 'dictData.ne_version_status.3', '3', 1, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (105, 'cdr_cause_code', 'dictData.cdr_cause_code.0', '0', 0, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (106, 'cdr_cause_code', 'dictData.cdr_cause_code.8', '8', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (107, 'cdr_cause_code', 'dictData.cdr_cause_code.10', '10', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (108, 'cdr_cause_code', 'dictData.cdr_cause_code.21', '21', 10, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (109, 'cdr_cause_code', 'dictData.cdr_cause_code.22', '22', 11, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (110, 'cdr_cause_code', 'dictData.cdr_cause_code.27', '27', 12, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (111, 'cdr_cause_code', 'dictData.cdr_cause_code.28', '28', 13, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (112, 'cdr_cause_code', 'dictData.cdr_cause_code.29', '29', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (113, 'cdr_cause_code', 'dictData.cdr_cause_code.30', '30', 15, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (114, 'cdr_cause_code', 'dictData.cdr_cause_code.38', '38', 16, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (115, 'cdr_cause_code', 'dictData.cdr_cause_code.41', '41', 20, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (116, 'cdr_cause_code', 'dictData.cdr_cause_code.41', '41', 21, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (117, 'cdr_cause_code', 'dictData.cdr_cause_code.42', '42', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (118, 'cdr_cause_code', 'dictData.cdr_cause_code.47', '47', 23, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (119, 'cdr_cause_code', 'dictData.cdr_cause_code.50', '50', 30, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (120, 'trace_msg_type', 'dictData.trace_msg_type.0', '0', 0, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (121, 'trace_msg_type', 'dictData.trace_msg_type.1', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (122, 'trace_msg_direct', 'dictData.trace_msg_direct.0', '0', 0, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (123, 'trace_msg_direct', 'dictData.trace_msg_direct.1', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (124, 'trace_interfaces', 'dictData.trace_interfaces.1', 'N1', 1, '', '', '0', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (125, 'trace_interfaces', 'dictData.trace_interfaces.2', 'N2', 2, '', '', '0', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (126, 'trace_interfaces', 'dictData.trace_interfaces.3', 'N1/N2', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (127, 'trace_interfaces', 'dictData.trace_interfaces.4', 'N4', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (128, 'trace_interfaces', 'dictData.trace_interfaces.8', 'N8', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (129, 'trace_interfaces', 'dictData.trace_interfaces.10', 'N10', 10, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (130, 'trace_interfaces', 'dictData.trace_interfaces.11', 'N11', 11, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (131, 'trace_interfaces', 'dictData.trace_interfaces.12', 'N12', 12, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (132, 'trace_interfaces', 'dictData.trace_interfaces.13', 'N13', 13, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (133, 'trace_interfaces', 'dictData.trace_interfaces.7', 'N7', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (134, 'trace_interfaces', 'dictData.trace_interfaces.15', 'N15', 15, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (135, 'trace_interfaces', 'dictData.trace_interfaces.17', 'N17', 17, '', '', '0', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (136, 'trace_interfaces', 'dictData.trace_interfaces.20', 'N20', 20, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (137, 'trace_interfaces', 'dictData.trace_interfaces.22', 'N22', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (138, 'trace_interfaces', 'dictData.trace_interfaces.40', 'N40', 40, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (139, 'cdr_sip_code', 'dictData.cdr_sip_code.302', '302', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (140, 'cdr_sip_code', 'dictData.cdr_sip_code.402', '402', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (141, 'cdr_sip_code', 'dictData.cdr_sip_code.480', '480', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (142, 'cdr_sip_code', 'dictData.cdr_sip_code.481', '481', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (143, 'cdr_sip_code', 'dictData.cdr_sip_code.482', '482', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (144, 'cdr_sip_code', 'dictData.cdr_sip_code.486', '486', 11, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (145, 'cdr_sip_code', 'dictData.cdr_sip_code.489', '489', 15, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (146, 'cdr_sip_code', 'dictData.cdr_sip_code.580', '580', 19, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (147, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.0', '0', 99, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (148, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.200', '200', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (149, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.202', '202', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (150, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.302', '302', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (151, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.402', '402', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (152, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.403', '403', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (153, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.404', '404', 6, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (154, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.480', '480', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (155, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.481', '481', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (156, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.482', '482', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (157, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.486', '486', 11, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (158, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.487', '487', 12, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (159, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.408', '408', 13, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (160, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.488', '488', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (161, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.489', '489', 15, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (162, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.500', '500', 16, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (163, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.503', '503', 17, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (164, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.504', '504', 18, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (165, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.580', '580', 19, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (166, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.603', '603', 21, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (167, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.606', '606', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (168, 'trace_interfaces', 'dictData.trace_interfaces.14', 'N14', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (169, 'trace_interfaces', 'dictData.trace_interfaces.5', 'N5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); + diff --git a/build/database/lite/upgrade/upg_sys_job.sql b/build/database/lite/upgrade/upg_sys_job.sql new file mode 100644 index 00000000..47859628 --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_job.sql @@ -0,0 +1,50 @@ +-- ---------------------------- +-- Table structure for sys_job +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_job" ( + "job_id" integer NOT NULL, + "job_name" text(64), + "job_group" text(64), + "invoke_target" text(64) NOT NULL, + "target_params" text(2048), + "cron_expression" text(64), + "misfire_policy" text(1), + "concurrent" text(1), + "status_flag" text(1), + "save_log" text(1), + "create_by" text(64), + "create_time" integer(20), + "update_by" text(64), + "update_time" integer(20), + "remark" text(500), + PRIMARY KEY ("job_id") +); + +-- ---------------------------- +-- Indexes structure for table sys_job +-- ---------------------------- +CREATE UNIQUE INDEX IF NOT EXISTS "uk_name_group" +ON "sys_job" ( + "job_name" ASC, + "job_group" ASC +); + +-- ---------------------------- +-- Records of sys_job +-- ---------------------------- +REPLACE INTO "sys_job" VALUES (1, 'job.monitor_sys_resource', 'SYSTEM', 'monitor_sys_resource', '{"interval":5}', '0 0/5 * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.monitor_sys_resource_remark'); +REPLACE INTO "sys_job" VALUES (3, 'job.ne_data_udm', 'SYSTEM', 'ne_data_udm', '', '0 0 0/12 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, ''); +REPLACE INTO "sys_job" VALUES (6, 'job.ne_config_backup', 'SYSTEM', 'ne_config_backup', '', '0 30 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_config_backup_remark'); + +REPLACE INTO "sys_job" VALUES (10, 'job.delete_ne_config_backup', 'SYSTEM', 'delete_ne_config_backup', '{"storeDays":7,"storeNum":7}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_ne_config_backup_remark'); +REPLACE INTO "sys_job" VALUES (11, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{"storeDays":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); +REPLACE INTO "sys_job" VALUES (12, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{"storeDays":7,"neList":["IMS","AMF","UDM","UPF","MME","SMSC","SMF","MME"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); + +REPLACE INTO "sys_job" VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{"alarmTitle":"NE State Check Alarm","alarmType":"EquipmentAlarm","origSeverity":"Major","specificProblem":"alarm cause: the system state of target NE has not been received","specificProblemId":"AC10000","addInfo":""}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); +REPLACE INTO "sys_job" VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{"alarmTitle":"NE State Check Alarm CPU/Menory/Disk","alarmType":"EquipmentAlarm","origSeverity":"Major","specificProblem":"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold","specificProblemId":"AC10100","addInfo":"","cpuUseGt":70,"memUseGt":70,"diskUseGt":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); +REPLACE INTO "sys_job" VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{"alarmTitle":"NE State Check Alarm License","alarmType":"EquipmentAlarm","origSeverity":"Major","specificProblem":"Alarm Cause: License received from target NE is about to expire","specificProblemId":"AC10200","addInfo":"","dayLt":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); + +REPLACE INTO "sys_job" VALUES (30, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{"backupPath":"/udm_data/auth","storeDays":30},{"backupPath":"/udm_data/sub","storeDays":30},{"backupPath":"/udm_data/voip","storeDays":30},{"backupPath":"/udm_data/volte","storeDays":30},{"backupPath":"/cdr/ims_cdr_event","storeDays":30},{"backupPath":"/cdr/smsc_cdr_event","storeDays":30},{"backupPath":"/cdr/smf_cdr_event","storeDays":30},{"backupPath":"/cdr/sgwc_cdr_event","storeDays":30},{"backupPath":"/log/sys_log_operate","storeDays":30,"storeNum":7},{"backupPath":"/log/sys_log_login","storeDays":30,"storeNum":7}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); +REPLACE INTO "sys_job" VALUES (31, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{"dataType":["auth","sub","voip","volte"],"fileType":"txt"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); +REPLACE INTO "sys_job" VALUES (32, 'job.backup_export_cdr', 'SYSTEM', 'backup_export_cdr', '{"dataType":["ims","smf","sgwc","smsc"],"fileType":"xlsx","hour":1}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_cdr_remark'); +REPLACE INTO "sys_job" VALUES (33, 'job.backup_export_log', 'SYSTEM', 'backup_export_log', '{"dataType":["operate","login"],"fileType":"xlsx","hour":1}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_log_remark'); diff --git a/build/database/lite/upgrade/upg_sys_menu.sql b/build/database/lite/upgrade/upg_sys_menu.sql new file mode 100644 index 00000000..e39b0dfd --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_menu.sql @@ -0,0 +1,201 @@ +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_menu" ( + "menu_id" integer NOT NULL, + "menu_name" text(64) NOT NULL, + "parent_id" integer, + "menu_sort" integer, + "menu_path" text(255), + "component" text(255), + "frame_flag" text(1), + "cache_flag" text(1), + "menu_type" text(1) NOT NULL, + "visible_flag" text(1), + "status_flag" text(1), + "perms" text(128), + "icon" text(128), + "del_flag" text(1), + "create_by" text(64), + "create_time" integer, + "update_by" text(64), + "update_time" integer, + "remark" text(500), + PRIMARY KEY ("menu_id") +); + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +REPLACE INTO "sys_menu" VALUES (1, 'menu.system', 0, 16, 'system', '', '1', '1', 'D', '1', '1', '', 'icon-xiangmu', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.systemRemark'); +REPLACE INTO "sys_menu" VALUES (4, 'menu.ne', 0, 3, 'ne', '', '1', '0', 'D', '1', '1', '', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.configRemark'); +REPLACE INTO "sys_menu" VALUES (5, 'menu.ue', 0, 7, 'ue', '', '1', '0', 'D', '1', '1', '', 'icon-wocanyu', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.ueRemark'); +REPLACE INTO "sys_menu" VALUES (60, 'menu.tools', 0, 60, 'tool', '', '1', '1', 'D', '1', '1', '', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.toolsRemark'); +REPLACE INTO "sys_menu" VALUES (61, 'menu.tools.terminal', 60, 20, 'terminal', 'tool/terminal/index', '1', '1', 'M', '1', '1', 'tool:terminal:index', 'icon-suofang', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (62, 'menu.tools.help', 60, 62, 'help', 'tool/help/index', '1', '1', 'M', '0', '1', 'tool:help:list', 'icon-shuoming', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.tools.helpRemark'); +REPLACE INTO "sys_menu" VALUES (63, 'menu.tools.ps', 60, 8, 'ps', 'tool/ps/index', '1', '0', 'M', '1', '1', 'tool:ps:list', 'icon-zhizuoliucheng', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (64, 'menu.tools.net', 60, 9, 'net', 'tool/net/index', '1', '0', 'M', '1', '1', 'tool:net:list', 'icon-zhizuoliucheng', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (65, 'menu.tools.ping', 60, 4, 'ping', 'tool/ping/index', '1', '0', 'M', '1', '1', 'tool:ping:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (66, 'menu.tools.iperf', 60, 6, 'iperf', 'tool/iperf/index', '1', '0', 'M', '1', '1', 'tool:iperf:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (100, 'menu.security.user', 2113, 1, 'user', 'system/user/index', '1', '1', 'M', '1', '1', 'system:user:list', 'icon-wocanyu', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.security.userRemark'); +REPLACE INTO "sys_menu" VALUES (101, 'menu.security.role', 2113, 3, 'role', 'system/role/index', '1', '1', 'M', '1', '1', 'system:role:list', 'icon-anzhuo', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.security.roleRemark'); +REPLACE INTO "sys_menu" VALUES (102, 'menu.security.roleUser', 2113, 3, 'role/inline/auth-user/:roleId', 'system/role/auth-user', '1', '1', 'M', '0', '1', 'system:role:auth', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.security.roleUserRemark'); +REPLACE INTO "sys_menu" VALUES (103, 'menu.system.menu', 1, 10, 'menu', 'system/menu/index', '1', '1', 'M', '1', '1', 'system:menu:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.menuRemark'); +REPLACE INTO "sys_menu" VALUES (104, 'menu.security.dept', 2113, 5, 'dept', 'system/dept/index', '1', '1', 'M', '1', '1', 'system:dept:list', 'icon-yuzhanghao1', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.security.deptRemark'); +REPLACE INTO "sys_menu" VALUES (105, 'menu.security.post', 2113, 6, 'post', 'system/post/index', '1', '1', 'M', '1', '1', 'system:post:list', 'icon-gonggaodayi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.security.postRemark'); +REPLACE INTO "sys_menu" VALUES (106, 'menu.system.dictType', 1, 30, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.dictTypeRemark'); +REPLACE INTO "sys_menu" VALUES (107, 'menu.system.dictData', 1, 31, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.dictDataRemark'); +REPLACE INTO "sys_menu" VALUES (108, 'menu.system.paramSet', 1, 59, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.paramSetRemark'); +REPLACE INTO "sys_menu" VALUES (111, 'menu.system.systemLog', 1, 11, 'log', '', '1', '1', 'D', '0', '0', '', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemLogRemark'); +REPLACE INTO "sys_menu" VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemInfoRemark'); +REPLACE INTO "sys_menu" VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.cacheInfoRemark'); +REPLACE INTO "sys_menu" VALUES (114, 'menu.system.cache', 1, 9, 'cache', 'monitor/cache/index', '1', '1', 'M', '1', '1', 'monitor:cache:list', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.cacheRemark'); +REPLACE INTO "sys_menu" VALUES (115, 'menu.security.onlineUser', 2113, 2, 'online', 'monitor/online/index', '1', '1', 'M', '1', '1', 'monitor:online:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.security.onlineUserRemark'); +REPLACE INTO "sys_menu" VALUES (116, 'menu.system.job', 1, 20, 'job', 'monitor/job/index', '1', '1', 'M', '1', '1', 'monitor:job:list', 'icon-lishi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.jobRemark'); +REPLACE INTO "sys_menu" VALUES (117, 'menu.system.jobLog', 1, 21, '/system/job/inline/log/:jobId', 'monitor/job/log', '1', '1', 'M', '0', '1', 'monitor:job:log', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.jobLogRemark'); +REPLACE INTO "sys_menu" VALUES (500, 'menu.log.operat', 2089, 25, 'operate', 'system/log/operate/index', '1', '1', 'M', '1', '1', 'system:log:operate:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.log.operatRemark'); +REPLACE INTO "sys_menu" VALUES (501, 'menu.log.login', 2089, 26, 'login', 'system/log/login/index', '1', '1', 'M', '1', '1', 'system:log:login:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.log.loginRemark'); +REPLACE INTO "sys_menu" VALUES (1000, 'menu.common.query', 100, 1, '', '', '1', '1', 'B', '1', '1', 'system:user:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1001, 'menu.common.add', 100, 2, '', '', '1', '1', 'B', '1', '1', 'system:user:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1002, 'menu.common.edit', 100, 3, '', '', '1', '1', 'B', '1', '1', 'system:user:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1003, 'menu.common.delete', 100, 4, '', '', '1', '1', 'B', '1', '1', 'system:user:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1004, 'menu.common.export', 100, 5, '', '', '1', '1', 'B', '1', '1', 'system:user:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1005, 'menu.common.import', 100, 6, '', '', '1', '1', 'B', '1', '1', 'system:user:import', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1006, 'menu.common.resetPwd', 100, 7, '', '', '1', '1', 'B', '1', '1', 'system:user:resetPwd', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1007, 'menu.common.query', 101, 1, '', '', '1', '1', 'B', '1', '1', 'system:role:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1008, 'menu.common.add', 101, 2, '', '', '1', '1', 'B', '1', '1', 'system:role:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1009, 'menu.common.edit', 101, 3, '', '', '1', '1', 'B', '1', '1', 'system:role:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1010, 'menu.common.delete', 101, 4, '', '', '1', '1', 'B', '1', '1', 'system:role:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1011, 'menu.common.export', 101, 5, '', '', '1', '1', 'B', '1', '1', 'system:role:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1012, 'menu.common.query', 103, 1, '', '', '1', '1', 'B', '1', '1', 'system:menu:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1013, 'menu.common.add', 103, 2, '', '', '1', '1', 'B', '1', '1', 'system:menu:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1014, 'menu.common.edit', 103, 3, '', '', '1', '1', 'B', '1', '1', 'system:menu:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1015, 'menu.common.delete', 103, 4, '', '', '1', '1', 'B', '1', '1', 'system:menu:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1016, 'menu.common.query', 104, 1, '', '', '1', '1', 'B', '1', '1', 'system:dept:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1017, 'menu.common.add', 104, 2, '', '', '1', '1', 'B', '1', '1', 'system:dept:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1018, 'menu.common.edit', 104, 3, '', '', '1', '1', 'B', '1', '1', 'system:dept:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1019, 'menu.common.delete', 104, 4, '', '', '1', '1', 'B', '1', '1', 'system:dept:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1020, 'menu.common.query', 105, 1, '', '', '1', '1', 'B', '1', '1', 'system:post:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1021, 'menu.common.add', 105, 2, '', '', '1', '1', 'B', '1', '1', 'system:post:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1022, 'menu.common.edit', 105, 3, '', '', '1', '1', 'B', '1', '1', 'system:post:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1023, 'menu.common.delete', 105, 4, '', '', '1', '1', 'B', '1', '1', 'system:post:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1024, 'menu.common.export', 105, 5, '', '', '1', '1', 'B', '1', '1', 'system:post:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1025, 'menu.common.query', 106, 1, '#', '', '1', '1', 'B', '1', '1', 'system:dict:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1026, 'menu.common.add', 106, 2, '#', '', '1', '1', 'B', '1', '1', 'system:dict:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1027, 'menu.common.edit', 106, 3, '#', '', '1', '1', 'B', '1', '1', 'system:dict:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1028, 'menu.common.delete', 106, 4, '#', '', '1', '1', 'B', '1', '1', 'system:dict:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1029, 'menu.common.export', 106, 5, '#', '', '1', '1', 'B', '1', '1', 'system:dict:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1030, 'menu.common.query', 108, 1, '#', '', '1', '1', 'B', '1', '1', 'system:config:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1031, 'menu.common.add', 108, 2, '#', '', '1', '1', 'B', '1', '1', 'system:config:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1032, 'menu.common.edit', 108, 3, '#', '', '1', '1', 'B', '1', '1', 'system:config:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1033, 'menu.common.delete', 108, 4, '#', '', '1', '1', 'B', '1', '1', 'system:config:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1034, 'menu.common.export', 108, 5, '#', '', '1', '1', 'B', '1', '1', 'system:config:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1039, 'menu.common.query', 500, 1, '#', '', '1', '1', 'B', '1', '1', 'system:log:operate:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1040, 'menu.common.delete', 500, 2, '#', '', '1', '1', 'B', '1', '1', 'system:log:operate:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1041, 'menu.common.export', 500, 3, '#', '', '1', '1', 'B', '1', '1', 'system:log:operate:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1042, 'menu.common.query', 501, 1, '#', '', '1', '1', 'B', '1', '1', 'system:log:login:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1043, 'menu.common.delete', 501, 2, '#', '', '1', '1', 'B', '1', '1', 'system:log:login:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1044, 'menu.common.export', 501, 3, '#', '', '1', '1', 'B', '1', '1', 'system:log:login:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1045, 'menu.common.unlock', 501, 4, '#', '', '1', '1', 'B', '1', '1', 'system:log:login:unlock', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1046, 'menu.common.query', 114, 1, '#', '', '1', '1', 'B', '1', '1', 'monitor:cache:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1047, 'menu.common.delete', 114, 2, '#', '', '1', '1', 'B', '1', '1', 'monitor:cache:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1048, 'menu.common.query', 115, 1, '#', '', '1', '1', 'B', '1', '1', 'monitor:online:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1049, 'menu.forcedQuit.batch ', 115, 2, '#', '', '1', '1', 'B', '1', '1', 'monitor:online:batchLogout', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1050, 'menu.forcedQuit.single', 115, 3, '#', '', '1', '1', 'B', '1', '1', 'monitor:online:forceLogout', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1051, 'menu.common.query', 116, 1, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:query', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1052, 'menu.common.add', 116, 2, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:add', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2003, 'menu.neData.udmVolte', 5, 7, 'udm-volte', 'neData/udm-volte/index', '1', '0', 'M', '1', '1', 'udm+ims#volte:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2004, 'menu.neData.imsSub', 5, 9, 'ims-sub', 'neData/ims-sub/index', '1', '0', 'M', '1', '1', 'ims#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2005, 'menu.neData.smfSub', 5, 12, 'smf-sub', 'neData/smf-sub/index', '1', '0', 'M', '1', '1', 'smf#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2006, 'menu.neData.baseOnline', 5, 15, 'base-online', 'neData/base-online/index', '1', '0', 'M', '0', '1', 'amf,mme#base-online:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2007, 'menu.neData.baseStation', 5, 18, 'base-station', 'neData/base-station/index', '1', '0', 'M', '1', '1', 'amf,mme#base-station:list', 'icon-fenxiang', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2008, 'menu.ueUser.n3iwf', 5, 20, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '1', '1', 'n3iwf#sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2009, 'menu.neData.pcfSub', 5, 24, 'pcf-sub', 'neData/pcf-sub/index', '1', '0', 'M', '1', '1', 'pcf#sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2010, 'menu.neUser.nssf', 5, 26, 'nssf', 'neUser/nssf/index', '1', '0', 'M', '1', '1', 'nssf#sub:index', 'icon-daimayingyong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2011, 'menu.neUser.nssfAmf', 5, 28, 'nssfAmf', 'neUser/nssfAmf/index', '1', '0', 'M', '1', '1', 'nssf#sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2083, 'menu.trace', 2087, 30, 'traceManage', '', '1', '0', 'D', '1', '1', '', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.traceRemark'); +REPLACE INTO "sys_menu" VALUES (2084, 'menu.trace.task', 2083, 1, 'task', 'traceManage/task/index', '1', '0', 'M', '1', '1', 'traceManage:task:index', 'icon-chexiao', '0', 'system', 1728641403588, 'system', 1744453890548, 'menu.trace.taskRemark'); +REPLACE INTO "sys_menu" VALUES (2085, 'menu.trace.taskData', 2083, 4, 'task/inline/data', 'traceManage/task/data', '1', '0', 'M', '0', '1', 'traceManage:task:data', '#', '0', 'system', 1728641403588, 'system', 1744453921381, ''); +REPLACE INTO "sys_menu" VALUES (2086, 'menu.trace.pcap', 2083, 11, 'pcap', 'traceManage/pcap/index', '1', '1', 'M', '1', '1', 'traceManage:pcap:index', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.trace.pcapRemark'); +REPLACE INTO "sys_menu" VALUES (2087, 'menu.fault', 0, 2, 'faultManage', '', '1', '0', 'D', '1', '1', '', 'icon-jinggao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.faultRemark'); +REPLACE INTO "sys_menu" VALUES (2088, 'menu.fault.active', 2129, 1, 'active-alarm', 'faultManage/active-alarm/index', '1', '1', 'M', '1', '1', 'faultManage:active-alarm:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.fault.activemRemark'); +REPLACE INTO "sys_menu" VALUES (2089, 'menu.log', 0, 9, 'logManage', '', '1', '0', 'D', '1', '1', '', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.logRemark'); +REPLACE INTO "sys_menu" VALUES (2091, 'menu.log.mml', 2089, 30, 'mml', 'logManage/mml/index', '1', '1', 'M', '1', '1', 'logManage:mml:index', 'icon-wocanyu', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.log.mmlRemark'); +REPLACE INTO "sys_menu" VALUES (2092, 'menu.log.alarm', 2089, 40, 'alarm-log', 'logManage/alarm/index', '1', '0', 'M', '1', '1', 'logManage:alarm:index', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.log.alarmRemark'); +REPLACE INTO "sys_menu" VALUES (2094, 'menu.log.forwarding', 2089, 41, 'forwarding', 'logManage/forwarding/index', '1', '0', 'M', '1', '1', 'logManage:forwarding:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.log.forwardingRemark'); +REPLACE INTO "sys_menu" VALUES (2095, 'menu.log.set', 2089, 45, 'logSet', 'logManage/logSet/index', '1', '0', 'M', '0', '0', 'logManage:logSet:index', 'icon-you', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.log.setRemark'); +REPLACE INTO "sys_menu" VALUES (2096, 'menu.neData.backupData', 5, 40, 'backup-data', 'neData/backup-data/index', '1', '0', 'M', '1', '1', 'ne-data:backup-data:list', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2097, 'menu.fault.history', 2129, 2, 'history-alarm', 'faultManage/history-alarm/index', '1', '1', 'M', '1', '1', 'faultManage/history-alarm/index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.fault.historyRemark'); +REPLACE INTO "sys_menu" VALUES (2098, 'menu.fault.set', 2129, 100, 'fault-setting', 'faultManage/fault-setting/index', '1', '0', 'M', '0', '1', 'faultManage/fault-setting/index', 'icon-gonggaodayi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.fault.setRemark'); +REPLACE INTO "sys_menu" VALUES (2099, 'menu.perf', 0, 5, 'perfManage', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.perfRemark'); +REPLACE INTO "sys_menu" VALUES (2100, 'menu.perf.task', 2099, 1, 'taskManage', 'perfManage/taskManage/index', '1', '0', 'M', '0', '1', 'perfManage:taskManage:index', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.perf.taskRemark'); +REPLACE INTO "sys_menu" VALUES (2101, 'menu.perf.data', 2099, 2, 'perfData', 'perfManage/perfData/index', '1', '0', 'M', '0', '1', 'perfManage:perfData:index', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.perf.dataRemark'); +REPLACE INTO "sys_menu" VALUES (2102, 'menu.perf.kpiOverView', 2099, 10, 'kpiOverView', 'perfManage/kpiOverView/index', '1', '0', 'M', '1', '1', 'perfManage:perfReport:index', 'icon-gonggaodayi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2103, 'menu.perf.threshold', 2099, 4, 'perfThreshold', 'perfManage/perfThreshold/index', '1', '0', 'M', '0', '0', 'perfManage:perfThreshold:index', 'icon-zhuanrang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.perf.thresholdRemark'); +REPLACE INTO "sys_menu" VALUES (2104, 'menu.perf.kpi', 2099, 20, 'goldTarget', 'perfManage/goldTarget/index', '1', '1', 'M', '1', '1', 'perfManage:goldTarget:index', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.perf.kpiRemark'); +REPLACE INTO "sys_menu" VALUES (2105, 'menu.perf.customTarget', 2099, 99, 'customTarget', 'perfManage/customTarget/index', '1', '0', 'M', '1', '1', 'perfManage:customTarget:index', 'icon-fanhui1', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.perf.customTargetRemark'); +REPLACE INTO "sys_menu" VALUES (2106, 'menu.perf.kpiKeyTarget', 2099, 12, 'kpiKeyTarget', 'perfManage/kpiKeyTarget/index', '1', '0', 'M', '1', '1', 'perfManage:kpiKeyTarget:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2107, 'menu.mml', 0, 8, 'mmlManage', '', '1', '0', 'D', '1', '1', '', 'icon-zhizuoliucheng', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mmlRemark'); +REPLACE INTO "sys_menu" VALUES (2108, 'menu.mml.ne', 2107, 1, 'neOperate', 'mmlManage/neOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:neOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.neRemark'); +REPLACE INTO "sys_menu" VALUES (2109, 'menu.mml.udm', 2107, 2, 'udmOperate', 'mmlManage/udmOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:udmOperate:index', 'icon-gonggaodayi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.udmRemark'); +REPLACE INTO "sys_menu" VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '0', '0', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.setRemark'); +REPLACE INTO "sys_menu" VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '0', '0', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.omcRemark'); +REPLACE INTO "sys_menu" VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'sgwc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2113, 'menu.security', 0, 14, 'security', '', '1', '0', 'D', '1', '1', '', 'icon-suofang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.securityRemark'); +REPLACE INTO "sys_menu" VALUES (2114, 'menu.system.systemSet', 1, 60, 'setting', 'system/setting/index', '1', '1', 'M', '1', '1', 'system:setting:index', 'icon-piliang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemSetRemark'); +REPLACE INTO "sys_menu" VALUES (2115, 'menu.system.systemResource', 1, 6, 'monitor', 'monitor/monitor/index', '1', '1', 'M', '1', '1', 'monitor:monitor:info', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemResourceRemark'); +REPLACE INTO "sys_menu" VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.setting.i18nRemark'); +REPLACE INTO "sys_menu" VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2126, 'menu.monitor.topology', 2130, 10, 'topology', 'monitor/topology/index', '1', '0', 'M', '1', '1', 'monitor:topology:index', 'icon-fangda', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2127, 'menu.monitor.topologyBuild', 2130, 30, 'topologyBuild', 'monitor/topologyBuild/index', '1', '0', 'M', '1', '1', 'monitor:topologyBuild:index', 'icon-fangda', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2128, 'menu.monitor.topologyArchitecture', 2130, 20, 'topologyArchitecture', 'monitor/topologyArchitecture/index', '1', '0', 'M', '1', '1', 'monitor:topologyArchitecture:index', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', '0', 'D', '1', '1', '', 'icon-jinggao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2143, 'menu.ne.neLicense', 4, 20, 'neLicense', 'ne/neLicense/index', '1', '0', 'M', '1', '1', 'ne:neLicense:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2144, 'menu.ne.neSoftware', 4, 23, 'neSoftware', 'ne/neSoftware/index', '1', '0', 'M', '1', '1', 'ne:neSoftware:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2145, 'menu.ne.neVersion', 4, 26, 'neVersion', 'ne/neVersion/index', '1', '0', 'M', '1', '1', 'ne:neVersion:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2146, 'menu.ne.neConfig', 4, 28, 'neConfig', 'ne/neConfig/index', '1', '0', 'M', '1', '1', 'ne:neConfig:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2147, 'menu.fault.event', 2129, 3, 'event', 'faultManage/event/index', '1', '0', 'M', '1', '1', 'faultManage:event:index', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2148, 'menu.dashboard.smfCDR', 2140, 6, 'smfCDR', 'dashboard/smfCDR/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2149, 'menu.dashboard.mmeUE', 2141, 5, 'mmeUE', 'dashboard/mmeUE/index', '1', '0', 'M', '1', '1', 'mme#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2150, 'menu.system.user.editPost', 100, 9, '', '', '1', '1', 'B', '1', '1', 'system:user:editPost', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2151, 'menu.system.setting.doc', 2114, 2, '', '', '1', '1', 'B', '1', '1', 'system:setting:doc', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2152, 'menu.system.setting.official', 2114, 3, '', '', '1', '1', 'B', '1', '1', 'system:setting:official', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2153, 'menu.system.setting.lock', 2114, 4, '', '', '1', '1', 'B', '1', '1', 'system:setting:lock', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2154, 'menu.ne.neConfigBackup', 4, 29, 'neConfigBackup', 'ne/neConfigBackup/index', '1', '0', 'M', '1', '1', 'ne:neConfigBackup:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2155, 'menu.common.delete', 2154, 1, '#', '', '1', '1', 'B', '1', '1', 'ne:neConfigBackup:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2156, 'menu.common.edit', 2154, 2, '#', '', '1', '1', 'B', '1', '1', 'ne:neConfigBackup:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2157, 'menu.dashboard.smscCDR', 2140, 9, 'smscCDR', 'dashboard/smscCDR/index', '1', '0', 'M', '1', '1', 'smsc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2158, 'menu.trace.pcapFile', 2083, 12, 'pcap/inline/file', 'traceManage/pcap/file', '1', '0', 'M', '0', '1', 'traceManage:pcap:index', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2159, 'menu.log.exportFile', 2089, 100, 'exportFile', 'logManage/exportFile/index', '1', '0', 'M', '1', '1', 'logManage:exportFile:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2160, 'menu.perf.kpiCReport', 2099, 100, 'kpiCReport', 'perfManage/kpiCReport/index', '1', '0', 'M', '1', '1', 'perfManage:kpiCReport:index', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2161, 'menu.trace.taskHLR', 2083, 6, 'taskHLR', 'traceManage/task-hlr/index', '1', '0', 'M', '0', '1', 'traceManage:taskHLR:index', 'icon-chexiao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2162, 'menu.trace.taskAnalyze', 2083, 2, 'task/inline/analyze', 'traceManage/task/analyze', '1', '0', 'M', '0', '1', 'traceManage:task:analyze', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2163, 'menu.trace.tshark', 2083, 14, 'tshark', 'traceManage/tshark/index', '1', '0', 'M', '1', '1', 'traceManage:tshark:index', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2164, 'menu.trace.wireshark', 2083, 16, 'wireshark', 'traceManage/wireshark/index', '1', '0', 'M', '1', '1', 'traceManage:wireshark:index', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2165, 'menu.ne.neOverview', 4, 1, 'neOverview', 'configManage/neOverview/index', '1', '0', 'M', '1', '1', 'configManage:neOverview:index', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.ne.neOverviewRemark'); +REPLACE INTO "sys_menu" VALUES (2166, 'menu.dashboard.overview.smfUeNum', 2132, 4, '', '', '1', '1', 'B', '1', '1', 'dashboard:overview:smfUeNum', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +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, ''); diff --git a/build/database/lite/upgrade/upg_sys_role_menu.sql b/build/database/lite/upgrade/upg_sys_role_menu.sql new file mode 100644 index 00000000..20cc5770 --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_role_menu.sql @@ -0,0 +1,291 @@ +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_role_menu" ( + "role_id" integer(20) NOT NULL, + "menu_id" integer(20) NOT NULL, + PRIMARY KEY ("role_id", "menu_id") +); + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- +REPLACE INTO "sys_role_menu" VALUES (2, 1); +REPLACE INTO "sys_role_menu" VALUES (2, 4); +REPLACE INTO "sys_role_menu" VALUES (2, 5); +REPLACE INTO "sys_role_menu" VALUES (2, 60); +REPLACE INTO "sys_role_menu" VALUES (2, 61); +REPLACE INTO "sys_role_menu" VALUES (2, 63); +REPLACE INTO "sys_role_menu" VALUES (2, 64); +REPLACE INTO "sys_role_menu" VALUES (2, 65); +REPLACE INTO "sys_role_menu" VALUES (2, 66); +REPLACE INTO "sys_role_menu" VALUES (2, 100); +REPLACE INTO "sys_role_menu" VALUES (2, 101); +REPLACE INTO "sys_role_menu" VALUES (2, 102); +REPLACE INTO "sys_role_menu" VALUES (2, 103); +REPLACE INTO "sys_role_menu" VALUES (2, 104); +REPLACE INTO "sys_role_menu" VALUES (2, 105); +REPLACE INTO "sys_role_menu" VALUES (2, 108); +REPLACE INTO "sys_role_menu" VALUES (2, 111); +REPLACE INTO "sys_role_menu" VALUES (2, 112); +REPLACE INTO "sys_role_menu" VALUES (2, 115); +REPLACE INTO "sys_role_menu" VALUES (2, 116); +REPLACE INTO "sys_role_menu" VALUES (2, 117); +REPLACE INTO "sys_role_menu" VALUES (2, 500); +REPLACE INTO "sys_role_menu" VALUES (2, 501); +REPLACE INTO "sys_role_menu" VALUES (2, 1000); +REPLACE INTO "sys_role_menu" VALUES (2, 1001); +REPLACE INTO "sys_role_menu" VALUES (2, 1002); +REPLACE INTO "sys_role_menu" VALUES (2, 1003); +REPLACE INTO "sys_role_menu" VALUES (2, 1004); +REPLACE INTO "sys_role_menu" VALUES (2, 1005); +REPLACE INTO "sys_role_menu" VALUES (2, 1006); +REPLACE INTO "sys_role_menu" VALUES (2, 1007); +REPLACE INTO "sys_role_menu" VALUES (2, 1008); +REPLACE INTO "sys_role_menu" VALUES (2, 1009); +REPLACE INTO "sys_role_menu" VALUES (2, 1010); +REPLACE INTO "sys_role_menu" VALUES (2, 1011); +REPLACE INTO "sys_role_menu" VALUES (2, 1012); +REPLACE INTO "sys_role_menu" VALUES (2, 1013); +REPLACE INTO "sys_role_menu" VALUES (2, 1014); +REPLACE INTO "sys_role_menu" VALUES (2, 1015); +REPLACE INTO "sys_role_menu" VALUES (2, 1016); +REPLACE INTO "sys_role_menu" VALUES (2, 1017); +REPLACE INTO "sys_role_menu" VALUES (2, 1018); +REPLACE INTO "sys_role_menu" VALUES (2, 1019); +REPLACE INTO "sys_role_menu" VALUES (2, 1020); +REPLACE INTO "sys_role_menu" VALUES (2, 1021); +REPLACE INTO "sys_role_menu" VALUES (2, 1022); +REPLACE INTO "sys_role_menu" VALUES (2, 1023); +REPLACE INTO "sys_role_menu" VALUES (2, 1024); +REPLACE INTO "sys_role_menu" VALUES (2, 1030); +REPLACE INTO "sys_role_menu" VALUES (2, 1032); +REPLACE INTO "sys_role_menu" VALUES (2, 1034); +REPLACE INTO "sys_role_menu" VALUES (2, 1039); +REPLACE INTO "sys_role_menu" VALUES (2, 1040); +REPLACE INTO "sys_role_menu" VALUES (2, 1041); +REPLACE INTO "sys_role_menu" VALUES (2, 1042); +REPLACE INTO "sys_role_menu" VALUES (2, 1043); +REPLACE INTO "sys_role_menu" VALUES (2, 1044); +REPLACE INTO "sys_role_menu" VALUES (2, 1045); +REPLACE INTO "sys_role_menu" VALUES (2, 1048); +REPLACE INTO "sys_role_menu" VALUES (2, 1049); +REPLACE INTO "sys_role_menu" VALUES (2, 1050); +REPLACE INTO "sys_role_menu" VALUES (2, 1051); +REPLACE INTO "sys_role_menu" VALUES (2, 1052); +REPLACE INTO "sys_role_menu" VALUES (2, 1053); +REPLACE INTO "sys_role_menu" VALUES (2, 1054); +REPLACE INTO "sys_role_menu" VALUES (2, 1055); +REPLACE INTO "sys_role_menu" VALUES (2, 1056); +REPLACE INTO "sys_role_menu" VALUES (2, 2000); +REPLACE INTO "sys_role_menu" VALUES (2, 2001); +REPLACE INTO "sys_role_menu" VALUES (2, 2002); +REPLACE INTO "sys_role_menu" VALUES (2, 2003); +REPLACE INTO "sys_role_menu" VALUES (2, 2004); +REPLACE INTO "sys_role_menu" VALUES (2, 2005); +REPLACE INTO "sys_role_menu" VALUES (2, 2007); +REPLACE INTO "sys_role_menu" VALUES (2, 2008); +REPLACE INTO "sys_role_menu" VALUES (2, 2009); +REPLACE INTO "sys_role_menu" VALUES (2, 2010); +REPLACE INTO "sys_role_menu" VALUES (2, 2011); +REPLACE INTO "sys_role_menu" VALUES (2, 2083); +REPLACE INTO "sys_role_menu" VALUES (2, 2084); +REPLACE INTO "sys_role_menu" VALUES (2, 2086); +REPLACE INTO "sys_role_menu" VALUES (2, 2087); +REPLACE INTO "sys_role_menu" VALUES (2, 2088); +REPLACE INTO "sys_role_menu" VALUES (2, 2089); +REPLACE INTO "sys_role_menu" VALUES (2, 2091); +REPLACE INTO "sys_role_menu" VALUES (2, 2092); +REPLACE INTO "sys_role_menu" VALUES (2, 2094); +REPLACE INTO "sys_role_menu" VALUES (2, 2096); +REPLACE INTO "sys_role_menu" VALUES (2, 2097); +REPLACE INTO "sys_role_menu" VALUES (2, 2099); +REPLACE INTO "sys_role_menu" VALUES (2, 2100); +REPLACE INTO "sys_role_menu" VALUES (2, 2101); +REPLACE INTO "sys_role_menu" VALUES (2, 2102); +REPLACE INTO "sys_role_menu" VALUES (2, 2103); +REPLACE INTO "sys_role_menu" VALUES (2, 2104); +REPLACE INTO "sys_role_menu" VALUES (2, 2105); +REPLACE INTO "sys_role_menu" VALUES (2, 2107); +REPLACE INTO "sys_role_menu" VALUES (2, 2108); +REPLACE INTO "sys_role_menu" VALUES (2, 2109); +REPLACE INTO "sys_role_menu" VALUES (2, 2112); +REPLACE INTO "sys_role_menu" VALUES (2, 2113); +REPLACE INTO "sys_role_menu" VALUES (2, 2114); +REPLACE INTO "sys_role_menu" VALUES (2, 2115); +REPLACE INTO "sys_role_menu" VALUES (2, 2116); +REPLACE INTO "sys_role_menu" VALUES (2, 2117); +REPLACE INTO "sys_role_menu" VALUES (2, 2118); +REPLACE INTO "sys_role_menu" VALUES (2, 2121); +REPLACE INTO "sys_role_menu" VALUES (2, 2122); +REPLACE INTO "sys_role_menu" VALUES (2, 2123); +REPLACE INTO "sys_role_menu" VALUES (2, 2126); +REPLACE INTO "sys_role_menu" VALUES (2, 2128); +REPLACE INTO "sys_role_menu" VALUES (2, 2129); +REPLACE INTO "sys_role_menu" VALUES (2, 2130); +REPLACE INTO "sys_role_menu" VALUES (2, 2131); +REPLACE INTO "sys_role_menu" VALUES (2, 2132); +REPLACE INTO "sys_role_menu" VALUES (2, 2133); +REPLACE INTO "sys_role_menu" VALUES (2, 2137); +REPLACE INTO "sys_role_menu" VALUES (2, 2138); +REPLACE INTO "sys_role_menu" VALUES (2, 2140); +REPLACE INTO "sys_role_menu" VALUES (2, 2141); +REPLACE INTO "sys_role_menu" VALUES (2, 2142); +REPLACE INTO "sys_role_menu" VALUES (2, 2143); +REPLACE INTO "sys_role_menu" VALUES (2, 2145); +REPLACE INTO "sys_role_menu" VALUES (2, 2146); +REPLACE INTO "sys_role_menu" VALUES (2, 2147); +REPLACE INTO "sys_role_menu" VALUES (2, 2148); +REPLACE INTO "sys_role_menu" VALUES (2, 2149); +REPLACE INTO "sys_role_menu" VALUES (2, 2150); +REPLACE INTO "sys_role_menu" VALUES (2, 2151); +REPLACE INTO "sys_role_menu" VALUES (2, 2152); +REPLACE INTO "sys_role_menu" VALUES (2, 2153); +REPLACE INTO "sys_role_menu" VALUES (2, 2154); +REPLACE INTO "sys_role_menu" VALUES (2, 2155); +REPLACE INTO "sys_role_menu" VALUES (2, 2156); +REPLACE INTO "sys_role_menu" VALUES (2, 2157); +REPLACE INTO "sys_role_menu" VALUES (2, 2158); +REPLACE INTO "sys_role_menu" VALUES (2, 2159); +REPLACE INTO "sys_role_menu" VALUES (2, 2160); +REPLACE INTO "sys_role_menu" VALUES (2, 2162); +REPLACE INTO "sys_role_menu" VALUES (2, 2163); +REPLACE INTO "sys_role_menu" VALUES (2, 2164); +REPLACE INTO "sys_role_menu" VALUES (2, 2165); +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 (3, 1); +REPLACE INTO "sys_role_menu" VALUES (3, 4); +REPLACE INTO "sys_role_menu" VALUES (3, 5); +REPLACE INTO "sys_role_menu" VALUES (3, 60); +REPLACE INTO "sys_role_menu" VALUES (3, 65); +REPLACE INTO "sys_role_menu" VALUES (3, 66); +REPLACE INTO "sys_role_menu" VALUES (3, 108); +REPLACE INTO "sys_role_menu" VALUES (3, 112); +REPLACE INTO "sys_role_menu" VALUES (3, 115); +REPLACE INTO "sys_role_menu" VALUES (3, 500); +REPLACE INTO "sys_role_menu" VALUES (3, 501); +REPLACE INTO "sys_role_menu" VALUES (3, 1030); +REPLACE INTO "sys_role_menu" VALUES (3, 1032); +REPLACE INTO "sys_role_menu" VALUES (3, 1034); +REPLACE INTO "sys_role_menu" VALUES (3, 1039); +REPLACE INTO "sys_role_menu" VALUES (3, 1042); +REPLACE INTO "sys_role_menu" VALUES (3, 1048); +REPLACE INTO "sys_role_menu" VALUES (3, 2000); +REPLACE INTO "sys_role_menu" VALUES (3, 2001); +REPLACE INTO "sys_role_menu" VALUES (3, 2002); +REPLACE INTO "sys_role_menu" VALUES (3, 2003); +REPLACE INTO "sys_role_menu" VALUES (3, 2004); +REPLACE INTO "sys_role_menu" VALUES (3, 2005); +REPLACE INTO "sys_role_menu" VALUES (3, 2007); +REPLACE INTO "sys_role_menu" VALUES (3, 2008); +REPLACE INTO "sys_role_menu" VALUES (3, 2009); +REPLACE INTO "sys_role_menu" VALUES (3, 2010); +REPLACE INTO "sys_role_menu" VALUES (3, 2011); +REPLACE INTO "sys_role_menu" VALUES (3, 2083); +REPLACE INTO "sys_role_menu" VALUES (3, 2086); +REPLACE INTO "sys_role_menu" VALUES (3, 2087); +REPLACE INTO "sys_role_menu" VALUES (3, 2088); +REPLACE INTO "sys_role_menu" VALUES (3, 2089); +REPLACE INTO "sys_role_menu" VALUES (3, 2091); +REPLACE INTO "sys_role_menu" VALUES (3, 2092); +REPLACE INTO "sys_role_menu" VALUES (3, 2094); +REPLACE INTO "sys_role_menu" VALUES (3, 2097); +REPLACE INTO "sys_role_menu" VALUES (3, 2107); +REPLACE INTO "sys_role_menu" VALUES (3, 2108); +REPLACE INTO "sys_role_menu" VALUES (3, 2109); +REPLACE INTO "sys_role_menu" VALUES (3, 2113); +REPLACE INTO "sys_role_menu" VALUES (3, 2114); +REPLACE INTO "sys_role_menu" VALUES (3, 2115); +REPLACE INTO "sys_role_menu" VALUES (3, 2116); +REPLACE INTO "sys_role_menu" VALUES (3, 2123); +REPLACE INTO "sys_role_menu" VALUES (3, 2126); +REPLACE INTO "sys_role_menu" VALUES (3, 2128); +REPLACE INTO "sys_role_menu" VALUES (3, 2129); +REPLACE INTO "sys_role_menu" VALUES (3, 2130); +REPLACE INTO "sys_role_menu" VALUES (3, 2131); +REPLACE INTO "sys_role_menu" VALUES (3, 2132); +REPLACE INTO "sys_role_menu" VALUES (3, 2133); +REPLACE INTO "sys_role_menu" VALUES (3, 2137); +REPLACE INTO "sys_role_menu" VALUES (3, 2138); +REPLACE INTO "sys_role_menu" VALUES (3, 2140); +REPLACE INTO "sys_role_menu" VALUES (3, 2141); +REPLACE INTO "sys_role_menu" VALUES (3, 2143); +REPLACE INTO "sys_role_menu" VALUES (3, 2146); +REPLACE INTO "sys_role_menu" VALUES (3, 2147); +REPLACE INTO "sys_role_menu" VALUES (3, 2148); +REPLACE INTO "sys_role_menu" VALUES (3, 2149); +REPLACE INTO "sys_role_menu" VALUES (3, 2151); +REPLACE INTO "sys_role_menu" VALUES (3, 2152); +REPLACE INTO "sys_role_menu" VALUES (3, 2153); +REPLACE INTO "sys_role_menu" VALUES (3, 2154); +REPLACE INTO "sys_role_menu" VALUES (3, 2155); +REPLACE INTO "sys_role_menu" VALUES (3, 2156); +REPLACE INTO "sys_role_menu" VALUES (3, 2157); +REPLACE INTO "sys_role_menu" VALUES (3, 2158); +REPLACE INTO "sys_role_menu" VALUES (3, 2165); +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 (4, 1); +REPLACE INTO "sys_role_menu" VALUES (4, 4); +REPLACE INTO "sys_role_menu" VALUES (4, 60); +REPLACE INTO "sys_role_menu" VALUES (4, 65); +REPLACE INTO "sys_role_menu" VALUES (4, 66); +REPLACE INTO "sys_role_menu" VALUES (4, 112); +REPLACE INTO "sys_role_menu" VALUES (4, 115); +REPLACE INTO "sys_role_menu" VALUES (4, 500); +REPLACE INTO "sys_role_menu" VALUES (4, 501); +REPLACE INTO "sys_role_menu" VALUES (4, 1039); +REPLACE INTO "sys_role_menu" VALUES (4, 1041); +REPLACE INTO "sys_role_menu" VALUES (4, 1042); +REPLACE INTO "sys_role_menu" VALUES (4, 1044); +REPLACE INTO "sys_role_menu" VALUES (4, 1048); +REPLACE INTO "sys_role_menu" VALUES (4, 2083); +REPLACE INTO "sys_role_menu" VALUES (4, 2086); +REPLACE INTO "sys_role_menu" VALUES (4, 2087); +REPLACE INTO "sys_role_menu" VALUES (4, 2088); +REPLACE INTO "sys_role_menu" VALUES (4, 2089); +REPLACE INTO "sys_role_menu" VALUES (4, 2092); +REPLACE INTO "sys_role_menu" VALUES (4, 2094); +REPLACE INTO "sys_role_menu" VALUES (4, 2097); +REPLACE INTO "sys_role_menu" VALUES (4, 2113); +REPLACE INTO "sys_role_menu" VALUES (4, 2114); +REPLACE INTO "sys_role_menu" VALUES (4, 2116); +REPLACE INTO "sys_role_menu" VALUES (4, 2126); +REPLACE INTO "sys_role_menu" VALUES (4, 2128); +REPLACE INTO "sys_role_menu" VALUES (4, 2129); +REPLACE INTO "sys_role_menu" VALUES (4, 2130); +REPLACE INTO "sys_role_menu" VALUES (4, 2131); +REPLACE INTO "sys_role_menu" VALUES (4, 2132); +REPLACE INTO "sys_role_menu" VALUES (4, 2133); +REPLACE INTO "sys_role_menu" VALUES (4, 2138); +REPLACE INTO "sys_role_menu" VALUES (4, 2140); +REPLACE INTO "sys_role_menu" VALUES (4, 2141); +REPLACE INTO "sys_role_menu" VALUES (4, 2147); +REPLACE INTO "sys_role_menu" VALUES (4, 2148); +REPLACE INTO "sys_role_menu" VALUES (4, 2149); +REPLACE INTO "sys_role_menu" VALUES (4, 2151); +REPLACE INTO "sys_role_menu" VALUES (4, 2152); +REPLACE INTO "sys_role_menu" VALUES (4, 2153); +REPLACE INTO "sys_role_menu" VALUES (4, 2157); +REPLACE INTO "sys_role_menu" VALUES (4, 2163); +REPLACE INTO "sys_role_menu" VALUES (4, 2165); +REPLACE INTO "sys_role_menu" VALUES (4, 2166); +REPLACE INTO "sys_role_menu" VALUES (4, 2167); +REPLACE INTO "sys_role_menu" VALUES (4, 2168); +REPLACE INTO "sys_role_menu" VALUES (4, 2169); + +REPLACE INTO "sys_role_menu" VALUES (5, 1); +REPLACE INTO "sys_role_menu" VALUES (5, 4); +REPLACE INTO "sys_role_menu" VALUES (5, 112); +REPLACE INTO "sys_role_menu" VALUES (5, 2087); +REPLACE INTO "sys_role_menu" VALUES (5, 2115); +REPLACE INTO "sys_role_menu" VALUES (5, 2131); +REPLACE INTO "sys_role_menu" VALUES (5, 2132); +REPLACE INTO "sys_role_menu" VALUES (5, 2165); diff --git a/build/database/std/install/alarm.sql b/build/database/std/install/alarm.sql index cd132c3a..8cda201e 100644 --- a/build/database/std/install/alarm.sql +++ b/build/database/std/install/alarm.sql @@ -13,31 +13,31 @@ CREATE TABLE `alarm` ( `ne_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元名称', `province` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元省份地域', `pv_flag` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元标识虚拟化标识', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '告警ID', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', - `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5', - `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', - `perceived_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '告警级别 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', + `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型', + `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度', + `perceived_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '告警级别', `object_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象ID', `object_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象名称', `object_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象类型', `location_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警定位信息', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', `specific_problem` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因', `specific_problem_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因ID', `add_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警辅助信息', - `ack_state` int DEFAULT '0' COMMENT '确认状态 0: Unacked, 1: Acked', - `ack_time` bigint DEFAULT '0' COMMENT '确认时间 秒级', - `ack_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '确认用户', - `clear_type` int DEFAULT '0' COMMENT '清除状态 0: Unclear, 1: AutoClear, 2: ManualClear', + `ack_state` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotAck' COMMENT '确认状态', + `ack_time` bigint DEFAULT '0' COMMENT '确认时间', + `ack_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '确认用户', + `clear_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotClear' COMMENT '清除状态', `clear_time` bigint DEFAULT '0' COMMENT '清除时间', - `clear_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', + `clear_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', `timestamp` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, - UNIQUE KEY `uk_uni_aid_ne_aseq` (`ne_type`,`ne_id`,`alarm_id`,`alarm_seq`) USING BTREE, + UNIQUE KEY `uk_uni_ne_aid` (`ne_type`,`ne_id`,`alarm_id`) USING BTREE, KEY `idx_status_severity_time` (`alarm_status`,`orig_severity`,`event_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='告警_记录表'; diff --git a/build/database/std/install/alarm_event.sql b/build/database/std/install/alarm_event.sql index a9175d33..984d03c1 100644 --- a/build/database/std/install/alarm_event.sql +++ b/build/database/std/install/alarm_event.sql @@ -10,22 +10,22 @@ CREATE TABLE `alarm_event` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元类型', `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元ID', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '告警ID', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', `object_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象ID', `object_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象名称', `object_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象类型', `location_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警定位信息', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', `specific_problem` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因', `specific_problem_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因ID', `add_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警辅助信息', - `clear_type` int DEFAULT '0' COMMENT '清除状态 0: Unclear, 1: AutoClear, 2: ManualClear', + `clear_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotClear' COMMENT '清除状态', `clear_time` bigint DEFAULT '0' COMMENT '清除时间', - `clear_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', + `clear_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', `timestamp` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uk_ti_aid_aseq` (`ne_type`,`ne_id`,`alarm_id`,`alarm_seq`) USING BTREE, diff --git a/build/database/std/install/alarm_forward_log.sql b/build/database/std/install/alarm_forward_log.sql index 5fd2fe30..72686a10 100644 --- a/build/database/std/install/alarm_forward_log.sql +++ b/build/database/std/install/alarm_forward_log.sql @@ -10,16 +10,16 @@ CREATE TABLE `alarm_forward_log` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警ID', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', - `alarm_type` varchar(10) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5', - `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', + `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型', + `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度 ', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', `created_at` bigint DEFAULT '0' COMMENT '创建时间', - `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '转发方式 SMS/EMAIL', + `type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '转发方式 SMS/EMAIL', `target` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '发送目标用户', `result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '发送结果', PRIMARY KEY (`id`) USING BTREE diff --git a/build/database/std/install/alarm_log.sql b/build/database/std/install/alarm_log.sql index 2aa760ea..66239890 100644 --- a/build/database/std/install/alarm_log.sql +++ b/build/database/std/install/alarm_log.sql @@ -8,14 +8,14 @@ CREATE TABLE `alarm_log` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警ID', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', - `alarm_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5', - `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', + `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型', + `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', `created_at` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='告警_日志记录'; diff --git a/build/database/std/install/sys_dict_data.sql b/build/database/std/install/sys_dict_data.sql index 6ae74908..160440f2 100644 --- a/build/database/std/install/sys_dict_data.sql +++ b/build/database/std/install/sys_dict_data.sql @@ -63,21 +63,21 @@ INSERT INTO `sys_dict_data` VALUES (34, 'sys_role_datascope', 'dictData.datascop INSERT INTO `sys_dict_data` VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (36, 'sys_role_datascope', 'dictData.datascope.deptAndChid', '4', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (37, 'sys_role_datascope', 'dictData.datascope.self', '5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', '2', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', '3', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', '4', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', '5', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', '0', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', '2', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', '0', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', '2', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', '3', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', '4', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', '5', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', 'CommunicationAlarm', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', 'EquipmentAlarm', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', 'ProcessingFailure', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', 'EnvironmentalAlarm', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', 'QualityOfServiceAlarm', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', 'NotClear', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', 'AutoClear', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', 'ManualClear', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', 'NotAck', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', 'Ack', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', 'Critical', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', 'Major', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', 'Minor', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', 'Warning', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', 'Event', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (53, 'index_status', 'dictType.index_status.normal', 'normal', 1, '#91cc75', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (54, 'index_status', 'dictType.index_status.abnormal', 'abnormal', 2, '#ee6666', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (55, 'cdr_sip_code', 'dictData.cdr_sip_code.200', '200', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); @@ -94,9 +94,9 @@ INSERT INTO `sys_dict_data` VALUES (65, 'ue_auth_code', 'dictData.ue_auth_code.0 INSERT INTO `sys_dict_data` VALUES (66, 'ue_auth_code', 'dictData.ue_auth_code.005', '005', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (67, 'ue_auth_code', 'dictData.ue_auth_code.006', '006', 6, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (68, 'ue_auth_code', 'dictData.ue_auth_code.007', '007', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'auth-result', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'cm-state', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'Auth', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'Detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'CM', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (72, 'ue_event_cm_state', 'dictData.ue_event_cm_state.connected', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (73, 'ue_event_cm_state', 'dictData.ue_event_cm_state.idle', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (74, 'ue_event_cm_state', 'dictData.ue_event_cm_state.inactive', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/std/install/sys_job.sql b/build/database/std/install/sys_job.sql index ae856654..f7ea93d8 100644 --- a/build/database/std/install/sys_job.sql +++ b/build/database/std/install/sys_job.sql @@ -36,9 +36,9 @@ INSERT INTO `sys_job` VALUES (10, 'job.delete_ne_config_backup', 'SYSTEM', 'dele INSERT INTO `sys_job` VALUES (11, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{\"storeDays\":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); INSERT INTO `sys_job` VALUES (12, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{\"storeDays\":7,\"neList\":[\"IMS\",\"AMF\",\"UDM\",\"UPF\",\"MME\",\"SMSC\",\"SMF\",\"MME\"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); -INSERT INTO `sys_job` VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{\"alarmTitle\":\"NE State Check Alarm\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"alarm cause: the system state of target NE has not been received\",\"specificProblemId\":\"AC10000\",\"addInfo\":\"\"}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); -INSERT INTO `sys_job` VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{\"alarmTitle\":\"NE State Check Alarm CPU/Menory/Disk\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold\",\"specificProblemId\":\"AC10100\",\"addInfo\":\"\",\"cpuUseGt\":70,\"memUseGt\":70,\"diskUseGt\":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); -INSERT INTO `sys_job` VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{\"alarmTitle\":\"NE State Check Alarm License\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"Alarm Cause: License received from target NE is about to expire\",\"specificProblemId\":\"AC10200\",\"addInfo\":\"\",\"dayLt\":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); +INSERT INTO `sys_job` VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{\"alarmTitle\":\"NE State Check Alarm\",\"alarmType\":\"EquipmentAlarm\",\"origSeverity\":\"Major\",\"specificProblem\":\"alarm cause: the system state of target NE has not been received\",\"specificProblemId\":\"AC10000\",\"addInfo\":\"\"}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); +INSERT INTO `sys_job` VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{\"alarmTitle\":\"NE State Check Alarm CPU/Menory/Disk\",\"alarmType\":\"EquipmentAlarm\",\"origSeverity\":\"Major\",\"specificProblem\":\"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold\",\"specificProblemId\":\"AC10100\",\"addInfo\":\"\",\"cpuUseGt\":70,\"memUseGt\":70,\"diskUseGt\":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); +INSERT INTO `sys_job` VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{\"alarmTitle\":\"NE State Check Alarm License\",\"alarmType\":\"EquipmentAlarm\",\"origSeverity\":\"Major\",\"specificProblem\":\"Alarm Cause: License received from target NE is about to expire\",\"specificProblemId\":\"AC10200\",\"addInfo\":\"\",\"dayLt\":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); INSERT INTO `sys_job` VALUES (30, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{\"backupPath\":\"/udm_data/auth\",\"storeDays\":30},{\"backupPath\":\"/udm_data/sub\",\"storeDays\":30},{\"backupPath\":\"/udm_data/voip\",\"storeDays\":30},{\"backupPath\":\"/udm_data/volte\",\"storeDays\":30},{\"backupPath\":\"/cdr/ims_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/smsc_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/smf_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/sgwc_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/log/sys_log_operate\",\"storeDays\":30,\"storeNum\":7},{\"backupPath\":\"/log/sys_log_login\",\"storeDays\":30,\"storeNum\":7}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); INSERT INTO `sys_job` VALUES (31, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{\"dataType\":[\"auth\",\"sub\",\"voip\",\"volte\"],\"fileType\":\"txt\"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); diff --git a/build/database/std/install/sys_menu.sql b/build/database/std/install/sys_menu.sql index af9ccf1a..19f2683f 100644 --- a/build/database/std/install/sys_menu.sql +++ b/build/database/std/install/sys_menu.sql @@ -149,8 +149,8 @@ INSERT INTO `sys_menu` VALUES (2106, 'menu.perf.kpiKeyTarget', 2099, 12, 'kpiKey INSERT INTO `sys_menu` VALUES (2107, 'menu.mml', 0, 8, 'mmlManage', '', '1', '0', 'D', '1', '1', '', 'icon-zhizuoliucheng', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mmlRemark'); INSERT INTO `sys_menu` VALUES (2108, 'menu.mml.ne', 2107, 1, 'neOperate', 'mmlManage/neOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:neOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.neRemark'); INSERT INTO `sys_menu` VALUES (2109, 'menu.mml.udm', 2107, 2, 'udmOperate', 'mmlManage/udmOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:udmOperate:index', 'icon-gonggaodayi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.udmRemark'); -INSERT INTO `sys_menu` VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '1', '1', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.setRemark'); -INSERT INTO `sys_menu` VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.omcRemark'); +INSERT INTO `sys_menu` VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '0', '0', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.setRemark'); +INSERT INTO `sys_menu` VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '0', '0', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.omcRemark'); INSERT INTO `sys_menu` VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'sgwc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2113, 'menu.security', 0, 14, 'security', '', '1', '0', 'D', '1', '1', '', 'icon-suofang', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.securityRemark'); INSERT INTO `sys_menu` VALUES (2114, 'menu.system.systemSet', 1, 60, 'setting', 'system/setting/index', '1', '1', 'M', '1', '1', 'system:setting:index', 'icon-piliang', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemSetRemark'); diff --git a/build/database/std/install/sys_role_menu.sql b/build/database/std/install/sys_role_menu.sql index ebbd4896..62a310de 100644 --- a/build/database/std/install/sys_role_menu.sql +++ b/build/database/std/install/sys_role_menu.sql @@ -204,7 +204,6 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2097); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2107); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2108); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2109); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2111); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2113); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2114); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2115); diff --git a/build/database/std/install/ue_event.sql b/build/database/std/install/ue_event.sql index 5e77c77d..7e5ad74e 100644 --- a/build/database/std/install/ue_event.sql +++ b/build/database/std/install/ue_event.sql @@ -7,8 +7,8 @@ CREATE TABLE `ue_event` ( `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '可能没有', - `timestamp` bigint DEFAULT '48' COMMENT '接收到的timestamp秒级存储毫秒时间戳', - `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型 auth-result detach cm-state', + `timestamp` bigint DEFAULT '48' COMMENT '接收到的时间', + `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型', `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data JSON String', `created_at` bigint DEFAULT '0' COMMENT '记录创建存储毫秒', PRIMARY KEY (`id`) USING BTREE, diff --git a/build/database/std/install/ue_event_amf.sql b/build/database/std/install/ue_event_amf.sql index 78898c86..768e0826 100644 --- a/build/database/std/install/ue_event_amf.sql +++ b/build/database/std/install/ue_event_amf.sql @@ -7,8 +7,8 @@ CREATE TABLE `ue_event_amf` ( `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '可能没有', - `timestamp` bigint DEFAULT '48' COMMENT '接收到的timestamp秒级存储毫秒时间戳', - `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型 auth-result detach cm-state', + `timestamp` bigint DEFAULT '48' COMMENT '接收到的时间', + `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型', `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data JSON String', `created_at` bigint DEFAULT '0' COMMENT '记录创建存储毫秒', PRIMARY KEY (`id`) USING BTREE, diff --git a/build/database/std/install/ue_event_mme.sql b/build/database/std/install/ue_event_mme.sql index 20026bc1..e6548fce 100644 --- a/build/database/std/install/ue_event_mme.sql +++ b/build/database/std/install/ue_event_mme.sql @@ -7,8 +7,8 @@ CREATE TABLE `ue_event_mme` ( `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '可能没有', - `timestamp` bigint DEFAULT '48' COMMENT '接收到的timestamp秒级存储毫秒时间戳', - `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型 auth-result detach cm-state', + `timestamp` bigint DEFAULT '48' COMMENT '接收到的时间', + `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型', `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data JSON String', `created_at` bigint DEFAULT '0' COMMENT '记录创建存储毫秒', PRIMARY KEY (`id`) USING BTREE, diff --git a/build/database/std/upgrade/upg_alarm.sql b/build/database/std/upgrade/upg_alarm.sql index 68b3522e..e19327b9 100644 --- a/build/database/std/upgrade/upg_alarm.sql +++ b/build/database/std/upgrade/upg_alarm.sql @@ -11,31 +11,31 @@ CREATE TABLE IF NOT EXISTS `alarm` ( `ne_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元名称', `province` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元省份地域', `pv_flag` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元标识虚拟化标识', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '告警ID', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', - `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5', - `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', - `perceived_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '告警级别 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', + `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型', + `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度', + `perceived_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '告警级别', `object_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象ID', `object_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象名称', `object_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象类型', `location_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警定位信息', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', `specific_problem` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因', `specific_problem_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因ID', `add_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警辅助信息', - `ack_state` int DEFAULT '0' COMMENT '确认状态 0: Unacked, 1: Acked', - `ack_time` bigint DEFAULT '0' COMMENT '确认时间 秒级', - `ack_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '确认用户', - `clear_type` int DEFAULT '0' COMMENT '清除状态 0: Unclear, 1: AutoClear, 2: ManualClear', + `ack_state` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotAck' COMMENT '确认状态', + `ack_time` bigint DEFAULT '0' COMMENT '确认时间', + `ack_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '确认用户', + `clear_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotClear' COMMENT '清除状态', `clear_time` bigint DEFAULT '0' COMMENT '清除时间', - `clear_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', + `clear_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', `timestamp` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, - UNIQUE KEY `uk_uni_aid_ne_aseq` (`ne_type`,`ne_id`,`alarm_id`,`alarm_seq`) USING BTREE, + UNIQUE KEY `uk_uni_ne_aid` (`ne_type`,`ne_id`,`alarm_id`) USING BTREE, KEY `idx_status_severity_time` (`alarm_status`,`orig_severity`,`event_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='告警_记录表'; @@ -54,31 +54,49 @@ ALTER TABLE `alarm` MODIFY COLUMN `ne_id` varchar(64) CHARACTER SET utf8mb4 COLL ALTER TABLE `alarm` MODIFY COLUMN `ne_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '网元名称' AFTER `ne_id`; ALTER TABLE `alarm` MODIFY COLUMN `province` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '网元省份地域' AFTER `ne_name`; ALTER TABLE `alarm` MODIFY COLUMN `pv_flag` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '网元标识虚拟化标识' AFTER `province`; -ALTER TABLE `alarm` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT '告警序号 同网元类型连续递增' AFTER `pv_flag`; +ALTER TABLE `alarm` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT '告警序号 连续递增' AFTER `pv_flag`; ALTER TABLE `alarm` MODIFY COLUMN `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '告警ID' AFTER `alarm_seq`; ALTER TABLE `alarm` MODIFY COLUMN `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警标题' AFTER `alarm_id`; ALTER TABLE `alarm` MODIFY COLUMN `alarm_code` int(11) NULL DEFAULT 0 COMMENT '告警状态码' AFTER `alarm_title`; -ALTER TABLE `alarm` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间 秒级' AFTER `alarm_code`; -ALTER TABLE `alarm` MODIFY COLUMN `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5' AFTER `event_time`; -ALTER TABLE `alarm` MODIFY COLUMN `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)' AFTER `alarm_type`; -ALTER TABLE `alarm` MODIFY COLUMN `perceived_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '3' COMMENT '告警级别 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)' AFTER `orig_severity`; +ALTER TABLE `alarm` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间' AFTER `alarm_code`; +ALTER TABLE `alarm` MODIFY COLUMN `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警类型' AFTER `event_time`; +ALTER TABLE `alarm` MODIFY COLUMN `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度' AFTER `alarm_type`; +ALTER TABLE `alarm` MODIFY COLUMN `perceived_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '告警级别' AFTER `orig_severity`; ALTER TABLE `alarm` MODIFY COLUMN `object_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '对象ID' AFTER `perceived_severity`; ALTER TABLE `alarm` MODIFY COLUMN `object_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '对象名称' AFTER `object_uid`; ALTER TABLE `alarm` MODIFY COLUMN `object_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '对象类型' AFTER `object_name`; ALTER TABLE `alarm` MODIFY COLUMN `location_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警定位信息' AFTER `object_type`; -ALTER TABLE `alarm` MODIFY COLUMN `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '告警状态 0:clear, 1:active' AFTER `location_info`; +ALTER TABLE `alarm` MODIFY COLUMN `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态' AFTER `location_info`; ALTER TABLE `alarm` MODIFY COLUMN `specific_problem` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警问题原因' AFTER `alarm_status`; ALTER TABLE `alarm` MODIFY COLUMN `specific_problem_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警问题原因ID' AFTER `specific_problem`; ALTER TABLE `alarm` MODIFY COLUMN `add_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警辅助信息' AFTER `specific_problem_id`; -ALTER TABLE `alarm` MODIFY COLUMN `ack_state` int(11) NULL DEFAULT 0 COMMENT '确认状态 0: Unacked, 1: Acked' AFTER `add_info`; -ALTER TABLE `alarm` MODIFY COLUMN `ack_time` bigint(20) NULL DEFAULT 0 COMMENT '确认时间 秒级' AFTER `ack_state`; -ALTER TABLE `alarm` MODIFY COLUMN `ack_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '确认用户' AFTER `ack_time`; -ALTER TABLE `alarm` MODIFY COLUMN `clear_type` int(11) NULL DEFAULT 0 COMMENT '清除状态 0: Unclear, 1: AutoClear, 2: ManualClear' AFTER `ack_user`; +ALTER TABLE `alarm` MODIFY COLUMN `ack_state` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotAck' COMMENT '确认状态' AFTER `add_info`; +ALTER TABLE `alarm` MODIFY COLUMN `ack_time` bigint(20) NULL DEFAULT 0 COMMENT '确认时间' AFTER `ack_state`; +ALTER TABLE `alarm` MODIFY COLUMN `ack_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '确认用户' AFTER `ack_time`; +ALTER TABLE `alarm` MODIFY COLUMN `clear_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotClear' COMMENT '清除状态' AFTER `ack_user`; ALTER TABLE `alarm` MODIFY COLUMN `clear_time` bigint(20) NULL DEFAULT 0 COMMENT '清除时间' AFTER `clear_type`; -ALTER TABLE `alarm` MODIFY COLUMN `clear_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '清除用户' AFTER `clear_time`; +ALTER TABLE `alarm` MODIFY COLUMN `clear_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户' AFTER `clear_time`; ALTER TABLE `alarm` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 0 COMMENT '创建时间' AFTER `clear_user`; -ALTER TABLE `alarm` ADD UNIQUE INDEX `uk_uni_aid_ne_aseq`(`ne_type`, `ne_id`, `alarm_id`, `alarm_seq`) USING BTREE; +ALTER TABLE `alarm` ADD UNIQUE INDEX `uk_uni_ne_aid`(`ne_type`, `ne_id`, `alarm_id`) USING BTREE; ALTER TABLE `alarm` ADD INDEX `idx_status_severity_time`(`alarm_status`, `orig_severity`, `event_time`) USING BTREE; +-- 更新数据 +UPDATE `alarm` SET `alarm_type` = 'CommunicationAlarm' WHERE `alarm_type` = '1'; +UPDATE `alarm` SET `alarm_type` = 'EquipmentAlarm' WHERE `alarm_type` = '2'; +UPDATE `alarm` SET `alarm_type` = 'ProcessingFailure' WHERE `alarm_type` = '3'; +UPDATE `alarm` SET `alarm_type` = 'EnvironmentalAlarm' WHERE `alarm_type` = '4'; +UPDATE `alarm` SET `alarm_type` = 'QualityOfServiceAlarm' WHERE `alarm_type` = '5'; +UPDATE `alarm` SET `orig_severity` = 'Critical', `perceived_severity` = 'Critical' WHERE `orig_severity` = '1'; +UPDATE `alarm` SET `orig_severity` = 'Major', `perceived_severity` = 'Major' WHERE `orig_severity` = '2'; +UPDATE `alarm` SET `orig_severity` = 'Minor', `perceived_severity` = 'Minor' WHERE `orig_severity` = '3'; +UPDATE `alarm` SET `orig_severity` = 'Warning', `perceived_severity` = 'Warning' WHERE `orig_severity` = '4'; +UPDATE `alarm` SET `orig_severity` = 'Event', `perceived_severity` = 'Event' WHERE `orig_severity` = '5'; +UPDATE `alarm` SET `alarm_status` = 'Clear' WHERE `alarm_status` = '0'; +UPDATE `alarm` SET `alarm_status` = 'Active' WHERE `alarm_status` = '1'; +UPDATE `alarm` SET `ack_state` = 'NotAck' WHERE `ack_state` = '0'; +UPDATE `alarm` SET `ack_state` = 'Ack' WHERE `ack_state` = '1'; +UPDATE `alarm` SET `clear_type` = 'NotClear' WHERE `clear_type` = '0'; +UPDATE `alarm` SET `clear_type` = 'AutoClear' WHERE `clear_type` = '1'; +UPDATE `alarm` SET `clear_type` = 'ManualClear' WHERE `clear_type` = '2'; SET FOREIGN_KEY_CHECKS = 1; diff --git a/build/database/std/upgrade/upg_alarm_event.sql b/build/database/std/upgrade/upg_alarm_event.sql index e60f928d..94ce4024 100644 --- a/build/database/std/upgrade/upg_alarm_event.sql +++ b/build/database/std/upgrade/upg_alarm_event.sql @@ -8,25 +8,25 @@ CREATE TABLE IF NOT EXISTS `alarm_event` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元类型', `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元ID', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '告警ID', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', `object_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象ID', `object_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象名称', `object_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '对象类型', `location_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警定位信息', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', `specific_problem` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因', `specific_problem_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警问题原因ID', `add_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警辅助信息', - `clear_type` int DEFAULT '0' COMMENT '清除状态 0: Unclear, 1: AutoClear, 2: ManualClear', + `clear_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotClear' COMMENT '清除状态', `clear_time` bigint DEFAULT '0' COMMENT '清除时间', - `clear_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', + `clear_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户', `timestamp` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, - UNIQUE KEY `uk_ti_aid_aseq` (`ne_type`,`ne_id`,`alarm_id`,`alarm_seq`) USING BTREE, + UNIQUE KEY `uk_ti_aid` (`ne_type`,`ne_id`,`alarm_id`) USING BTREE, KEY `idx_astatus_etime` (`alarm_status`,`event_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='告警_事件记录表'; @@ -51,25 +51,31 @@ ALTER TABLE `alarm_event` DROP INDEX `idx_severity_status`; ALTER TABLE `alarm_event` COMMENT = '告警_事件记录表'; ALTER TABLE `alarm_event` MODIFY COLUMN `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元类型' AFTER `id`; ALTER TABLE `alarm_event` MODIFY COLUMN `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元ID' AFTER `ne_type`; -ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT '告警序号 同网元类型连续递增' AFTER `ne_id`; +ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT '告警序号 连续递增' AFTER `ne_id`; ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '告警ID' AFTER `alarm_seq`; ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警标题' AFTER `alarm_id`; ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_code` int(11) NULL DEFAULT 0 COMMENT '告警状态码' AFTER `alarm_title`; -ALTER TABLE `alarm_event` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间 秒级' AFTER `alarm_code`; +ALTER TABLE `alarm_event` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间' AFTER `alarm_code`; ALTER TABLE `alarm_event` MODIFY COLUMN `object_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '对象ID' AFTER `event_time`; ALTER TABLE `alarm_event` MODIFY COLUMN `object_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '对象名称' AFTER `object_uid`; ALTER TABLE `alarm_event` MODIFY COLUMN `object_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '对象类型' AFTER `object_name`; ALTER TABLE `alarm_event` MODIFY COLUMN `location_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警定位信息' AFTER `object_type`; -ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '告警状态 0:clear, 1:active' AFTER `location_info`; +ALTER TABLE `alarm_event` MODIFY COLUMN `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态' AFTER `location_info`; ALTER TABLE `alarm_event` MODIFY COLUMN `specific_problem` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警问题原因' AFTER `alarm_status`; ALTER TABLE `alarm_event` MODIFY COLUMN `specific_problem_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警问题原因ID' AFTER `specific_problem`; ALTER TABLE `alarm_event` MODIFY COLUMN `add_info` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警辅助信息' AFTER `specific_problem_id`; -ALTER TABLE `alarm_event` MODIFY COLUMN `clear_type` int(11) NULL DEFAULT 0 COMMENT '清除状态 0: Unclear, 1: AutoClear, 2: ManualClear' AFTER `add_info`; +ALTER TABLE `alarm_event` MODIFY COLUMN `clear_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'NotClear' COMMENT '清除状态' AFTER `add_info`; ALTER TABLE `alarm_event` MODIFY COLUMN `clear_time` bigint(20) NULL DEFAULT 0 COMMENT '清除时间' AFTER `clear_type`; -ALTER TABLE `alarm_event` MODIFY COLUMN `clear_user` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '清除用户' AFTER `clear_time`; +ALTER TABLE `alarm_event` MODIFY COLUMN `clear_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '清除用户' AFTER `clear_time`; ALTER TABLE `alarm_event` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 0 COMMENT '创建时间' AFTER `clear_user`; -ALTER TABLE `alarm_event` ADD UNIQUE INDEX `uk_ti_aid_aseq`(`ne_type`, `ne_id`, `alarm_id`, `alarm_seq`) USING BTREE; +ALTER TABLE `alarm_event` ADD UNIQUE INDEX `uk_ti_aid`(`ne_type`, `ne_id`, `alarm_id`) USING BTREE; ALTER TABLE `alarm_event` ADD INDEX `idx_astatus_etime`(`alarm_status`, `event_time`) USING BTREE; +-- 更新数据 +UPDATE `alarm_event` SET `alarm_status` = 'Clear' WHERE `alarm_status` = '0'; +UPDATE `alarm_event` SET `alarm_status` = 'Active' WHERE `alarm_status` = '1'; +UPDATE `alarm_event` SET `clear_type` = 'NotClear' WHERE `clear_type` = '0'; +UPDATE `alarm_event` SET `clear_type` = 'AutoClear' WHERE `clear_type` = '1'; +UPDATE `alarm_event` SET `clear_type` = 'ManualClear' WHERE `clear_type` = '2'; SET FOREIGN_KEY_CHECKS = 1; diff --git a/build/database/std/upgrade/upg_alarm_forward_log.sql b/build/database/std/upgrade/upg_alarm_forward_log.sql index fd3c804c..918c29d9 100644 --- a/build/database/std/upgrade/upg_alarm_forward_log.sql +++ b/build/database/std/upgrade/upg_alarm_forward_log.sql @@ -8,16 +8,16 @@ CREATE TABLE IF NOT EXISTS `alarm_forward_log` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警ID', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', - `alarm_type` varchar(10) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5', - `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', + `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型', + `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度 ', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', `created_at` bigint DEFAULT '0' COMMENT '创建时间', - `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '转发方式 SMS/EMAIL', + `type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '转发方式 SMS/EMAIL', `target` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '发送目标用户', `result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '发送结果', PRIMARY KEY (`id`) USING BTREE @@ -33,17 +33,32 @@ ALTER TABLE `alarm_forward_log` DROP COLUMN `log_time`; ALTER TABLE `alarm_forward_log` COMMENT = '告警_转发日志记录'; ALTER TABLE `alarm_forward_log` MODIFY COLUMN `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `id`; ALTER TABLE `alarm_forward_log` MODIFY COLUMN `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' AFTER `ne_type`; -ALTER TABLE `alarm_forward_log` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT '告警序号 同网元类型连续递增' AFTER `ne_id`; +ALTER TABLE `alarm_forward_log` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT '告警序号 连续递增' AFTER `ne_id`; ALTER TABLE `alarm_forward_log` MODIFY COLUMN `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警ID' AFTER `alarm_seq`; ALTER TABLE `alarm_forward_log` ADD COLUMN `alarm_code` int(11) NULL DEFAULT 0 COMMENT '告警状态码' AFTER `alarm_id`; ALTER TABLE `alarm_forward_log` MODIFY COLUMN `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警标题' AFTER `alarm_code`; -ALTER TABLE `alarm_forward_log` ADD COLUMN `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '告警状态 0:clear, 1:active' AFTER `alarm_title`; -ALTER TABLE `alarm_forward_log` ADD COLUMN `alarm_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5' AFTER `alarm_status`; -ALTER TABLE `alarm_forward_log` ADD COLUMN `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)' AFTER `alarm_type`; +ALTER TABLE `alarm_forward_log` ADD COLUMN `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态' AFTER `alarm_title`; +ALTER TABLE `alarm_forward_log` MODIFY COLUMN `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态' AFTER `alarm_title`; +ALTER TABLE `alarm_forward_log` ADD COLUMN `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型' AFTER `alarm_status`; +ALTER TABLE `alarm_forward_log` MODIFY COLUMN `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型' AFTER `alarm_status`; +ALTER TABLE `alarm_forward_log` ADD COLUMN `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度' AFTER `alarm_type`; ALTER TABLE `alarm_forward_log` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间 秒级' AFTER `orig_severity`; ALTER TABLE `alarm_forward_log` ADD COLUMN `created_at` bigint(20) NULL DEFAULT 0 COMMENT '创建时间' AFTER `event_time`; -ALTER TABLE `alarm_forward_log` ADD COLUMN `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '转发方式 SMS/EMAIL' AFTER `created_at`; +ALTER TABLE `alarm_forward_log` ADD COLUMN `type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '转发方式 SMS/EMAIL' AFTER `created_at`; ALTER TABLE `alarm_forward_log` ADD COLUMN `target` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '发送目标用户' AFTER `type`; ALTER TABLE `alarm_forward_log` ADD COLUMN `result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '发送结果' AFTER `target`; +-- 更新数据 +UPDATE `alarm_forward_log` SET `alarm_type` = 'CommunicationAlarm' WHERE `alarm_type` = '1'; +UPDATE `alarm_forward_log` SET `alarm_type` = 'EquipmentAlarm' WHERE `alarm_type` = '2'; +UPDATE `alarm_forward_log` SET `alarm_type` = 'ProcessingFailure' WHERE `alarm_type` = '3'; +UPDATE `alarm_forward_log` SET `alarm_type` = 'EnvironmentalAlarm' WHERE `alarm_type` = '4'; +UPDATE `alarm_forward_log` SET `alarm_type` = 'QualityOfServiceAlarm' WHERE `alarm_type` = '5'; +UPDATE `alarm_forward_log` SET `orig_severity` = 'Critical' WHERE `orig_severity` = '1'; +UPDATE `alarm_forward_log` SET `orig_severity` = 'Major' WHERE `orig_severity` = '2'; +UPDATE `alarm_forward_log` SET `orig_severity` = 'Minor' WHERE `orig_severity` = '3'; +UPDATE `alarm_forward_log` SET `orig_severity` = 'Warning' WHERE `orig_severity` = '4'; +UPDATE `alarm_forward_log` SET `orig_severity` = 'Event' WHERE `orig_severity` = '5'; +UPDATE `alarm_forward_log` SET `alarm_status` = 'Clear' WHERE `alarm_status` = '0'; +UPDATE `alarm_forward_log` SET `alarm_status` = 'Active' WHERE `alarm_status` = '1'; SET FOREIGN_KEY_CHECKS=1; diff --git a/build/database/std/upgrade/upg_alarm_log.sql b/build/database/std/upgrade/upg_alarm_log.sql index 992f8d8f..1fe1620c 100644 --- a/build/database/std/upgrade/upg_alarm_log.sql +++ b/build/database/std/upgrade/upg_alarm_log.sql @@ -5,14 +5,14 @@ CREATE TABLE IF NOT EXISTS `alarm_log` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', - `alarm_seq` int DEFAULT '0' COMMENT '告警序号 同网元类型连续递增', + `alarm_seq` int DEFAULT '0' COMMENT '告警序号 连续递增', `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警ID', `alarm_code` int DEFAULT '0' COMMENT '告警状态码', `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警标题', - `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '告警状态 0:clear, 1:active', - `alarm_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5', - `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)', - `event_time` bigint DEFAULT '0' COMMENT '事件产生时间 秒级', + `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态', + `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型', + `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度', + `event_time` bigint DEFAULT '0' COMMENT '事件产生时间', `created_at` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='告警_日志记录'; @@ -28,10 +28,25 @@ ALTER TABLE `alarm_log` MODIFY COLUMN `alarm_seq` int(11) NULL DEFAULT 0 COMMENT ALTER TABLE `alarm_log` MODIFY COLUMN `alarm_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警ID' AFTER `alarm_seq`; ALTER TABLE `alarm_log` MODIFY COLUMN `alarm_code` int(11) NULL DEFAULT 0 COMMENT '告警状态码' AFTER `alarm_id`; ALTER TABLE `alarm_log` ADD COLUMN `alarm_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警标题' AFTER `alarm_code`; -ALTER TABLE `alarm_log` MODIFY COLUMN `alarm_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '告警状态 0:clear, 1:active' AFTER `alarm_title`; -ALTER TABLE `alarm_log` ADD COLUMN `alarm_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '告警类型 CommunicationAlarm=1,EquipmentAlarm=2,ProcessingFailure=3,EnvironmentalAlarm=4,QualityOfServiceAlarm=5' AFTER `alarm_status`; -ALTER TABLE `alarm_log` ADD COLUMN `orig_severity` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '3' COMMENT '严重程度 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF)' AFTER `alarm_type`; -ALTER TABLE `alarm_log` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间 秒级' AFTER `orig_severity`; +ALTER TABLE `alarm_log` MODIFY COLUMN `alarm_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Active' COMMENT '告警状态' AFTER `alarm_title`; +ALTER TABLE `alarm_log` ADD COLUMN `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型' AFTER `alarm_status`; +ALTER TABLE `alarm_log` MODIFY COLUMN `alarm_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '告警类型' AFTER `alarm_status`; +ALTER TABLE `alarm_log` ADD COLUMN `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度' AFTER `alarm_type`; +ALTER TABLE `alarm_log` MODIFY COLUMN `orig_severity` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Minor' COMMENT '严重程度' AFTER `alarm_type`; +ALTER TABLE `alarm_log` MODIFY COLUMN `event_time` bigint(20) NULL DEFAULT 0 COMMENT '事件产生时间' AFTER `orig_severity`; ALTER TABLE `alarm_log` ADD COLUMN `created_at` bigint(20) NULL DEFAULT 0 COMMENT '创建时间' AFTER `event_time`; +-- 更新数据 +UPDATE `alarm_log` SET `alarm_type` = 'CommunicationAlarm' WHERE `alarm_type` = '1'; +UPDATE `alarm_log` SET `alarm_type` = 'EquipmentAlarm' WHERE `alarm_type` = '2'; +UPDATE `alarm_log` SET `alarm_type` = 'ProcessingFailure' WHERE `alarm_type` = '3'; +UPDATE `alarm_log` SET `alarm_type` = 'EnvironmentalAlarm' WHERE `alarm_type` = '4'; +UPDATE `alarm_log` SET `alarm_type` = 'QualityOfServiceAlarm' WHERE `alarm_type` = '5'; +UPDATE `alarm_log` SET `orig_severity` = 'Critical' WHERE `orig_severity` = '1'; +UPDATE `alarm_log` SET `orig_severity` = 'Major' WHERE `orig_severity` = '2'; +UPDATE `alarm_log` SET `orig_severity` = 'Minor' WHERE `orig_severity` = '3'; +UPDATE `alarm_log` SET `orig_severity` = 'Warning' WHERE `orig_severity` = '4'; +UPDATE `alarm_log` SET `orig_severity` = 'Event' WHERE `orig_severity` = '5'; +UPDATE `alarm_log` SET `alarm_status` = 'Clear' WHERE `alarm_status` = '0'; +UPDATE `alarm_log` SET `alarm_status` = 'Active' WHERE `alarm_status` = '1'; -- Dump completed on 2024-02-18 18:26:55 diff --git a/build/database/std/upgrade/upg_sys_dict_data.sql b/build/database/std/upgrade/upg_sys_dict_data.sql index 4ac4f59d..20af7de4 100644 --- a/build/database/std/upgrade/upg_sys_dict_data.sql +++ b/build/database/std/upgrade/upg_sys_dict_data.sql @@ -67,21 +67,21 @@ REPLACE INTO `sys_dict_data` VALUES (34, 'sys_role_datascope', 'dictData.datasco REPLACE INTO `sys_dict_data` VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (36, 'sys_role_datascope', 'dictData.datascope.deptAndChid', '4', 4, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (37, 'sys_role_datascope', 'dictData.datascope.self', '5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', '2', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', '3', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', '4', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', '5', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', '0', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', '2', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', '0', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', '1', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', '1', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', '2', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', '3', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', '4', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', '5', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (38, 'active_alarm_type', 'dictData.active_alarm_type.communication', 'CommunicationAlarm', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (39, 'active_alarm_type', 'dictData.active_alarm_type.equipment', 'EquipmentAlarm', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (40, 'active_alarm_type', 'dictData.active_alarm_type.processing', 'ProcessingFailure', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (41, 'active_alarm_type', 'dictData.active_alarm_type.environmental', 'EnvironmentalAlarm', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (42, 'active_alarm_type', 'dictData.active_alarm_type.qualityOfService', 'QualityOfServiceAlarm', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (43, 'active_clear_type', 'dictData.active_clear_type.notCleared', 'NotClear', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (44, 'active_clear_type', 'dictData.active_clear_type.auto', 'AutoClear', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (45, 'active_clear_type', 'dictData.active_clear_type.hand', 'ManualClear', 2, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (46, 'active_ack_state', 'dictData.active_ack_state.unconfirmed', 'NotAck', 0, '', 'processing', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (47, 'active_ack_state', 'dictData.active_ack_state.confirmed', 'Ack', 1, '', 'success', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (48, 'active_alarm_severity', 'dictData.active_alarm_severity.critical', 'Critical', 1, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (49, 'active_alarm_severity', 'dictData.active_alarm_severity.major', 'Major', 2, '', 'cyan', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (50, 'active_alarm_severity', 'dictData.active_alarm_severity.minor', 'Minor', 3, '', 'blue ', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (51, 'active_alarm_severity', 'dictData.active_alarm_severity.warning', 'Warning', 4, '', 'yellow', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (52, 'active_alarm_severity', 'dictData.active_alarm_severity.event', 'Event', 5, '', 'purple', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (53, 'index_status', 'dictType.index_status.normal', 'normal', 1, '#91cc75', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (54, 'index_status', 'dictType.index_status.abnormal', 'abnormal', 2, '#ee6666', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (55, 'cdr_sip_code', 'dictData.cdr_sip_code.200', '200', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); @@ -98,9 +98,9 @@ REPLACE INTO `sys_dict_data` VALUES (65, 'ue_auth_code', 'dictData.ue_auth_code. REPLACE INTO `sys_dict_data` VALUES (66, 'ue_auth_code', 'dictData.ue_auth_code.005', '005', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (67, 'ue_auth_code', 'dictData.ue_auth_code.006', '006', 6, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (68, 'ue_auth_code', 'dictData.ue_auth_code.007', '007', 7, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'auth-result', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'cm-state', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (69, 'ue_event_type', 'dictData.ue_event_type.auth', 'Auth', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (70, 'ue_event_type', 'dictData.ue_event_type.detach', 'Detach', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (71, 'ue_event_type', 'dictData.ue_event_type.state', 'CM', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (72, 'ue_event_cm_state', 'dictData.ue_event_cm_state.connected', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (73, 'ue_event_cm_state', 'dictData.ue_event_cm_state.idle', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (74, 'ue_event_cm_state', 'dictData.ue_event_cm_state.inactive', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/std/upgrade/upg_sys_job.sql b/build/database/std/upgrade/upg_sys_job.sql index 9019ce6f..9752e55c 100644 --- a/build/database/std/upgrade/upg_sys_job.sql +++ b/build/database/std/upgrade/upg_sys_job.sql @@ -52,9 +52,9 @@ REPLACE INTO `sys_job` VALUES (10, 'job.delete_ne_config_backup', 'SYSTEM', 'del REPLACE INTO `sys_job` VALUES (11, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{\"storeDays\":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); REPLACE INTO `sys_job` VALUES (12, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{\"storeDays\":7,\"neList\":[\"IMS\",\"AMF\",\"UDM\",\"UPF\",\"MME\",\"SMSC\",\"SMF\",\"MME\"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); -REPLACE INTO `sys_job` VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{\"alarmTitle\":\"NE State Check Alarm\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"alarm cause: the system state of target NE has not been received\",\"specificProblemId\":\"AC10000\",\"addInfo\":\"\"}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); -REPLACE INTO `sys_job` VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{\"alarmTitle\":\"NE State Check Alarm CPU/Menory/Disk\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold\",\"specificProblemId\":\"AC10100\",\"addInfo\":\"\",\"cpuUseGt\":70,\"memUseGt\":70,\"diskUseGt\":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); -REPLACE INTO `sys_job` VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{\"alarmTitle\":\"NE State Check Alarm License\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"Alarm Cause: License received from target NE is about to expire\",\"specificProblemId\":\"AC10200\",\"addInfo\":\"\",\"dayLt\":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); +REPLACE INTO `sys_job` VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{\"alarmTitle\":\"NE State Check Alarm\",\"alarmType\":\"EquipmentAlarm\",\"origSeverity\":\"Major\",\"specificProblem\":\"alarm cause: the system state of target NE has not been received\",\"specificProblemId\":\"AC10000\",\"addInfo\":\"\"}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); +REPLACE INTO `sys_job` VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{\"alarmTitle\":\"NE State Check Alarm CPU/Menory/Disk\",\"alarmType\":\"EquipmentAlarm\",\"origSeverity\":\"Major\",\"specificProblem\":\"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold\",\"specificProblemId\":\"AC10100\",\"addInfo\":\"\",\"cpuUseGt\":70,\"memUseGt\":70,\"diskUseGt\":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); +REPLACE INTO `sys_job` VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{\"alarmTitle\":\"NE State Check Alarm License\",\"alarmType\":\"EquipmentAlarm\",\"origSeverity\":\"Major\",\"specificProblem\":\"Alarm Cause: License received from target NE is about to expire\",\"specificProblemId\":\"AC10200\",\"addInfo\":\"\",\"dayLt\":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); REPLACE INTO `sys_job` VALUES (30, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{\"backupPath\":\"/udm_data/auth\",\"storeDays\":30},{\"backupPath\":\"/udm_data/sub\",\"storeDays\":30},{\"backupPath\":\"/udm_data/voip\",\"storeDays\":30},{\"backupPath\":\"/udm_data/volte\",\"storeDays\":30},{\"backupPath\":\"/cdr/ims_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/smsc_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/smf_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/sgwc_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/log/sys_log_operate\",\"storeDays\":30,\"storeNum\":7},{\"backupPath\":\"/log/sys_log_login\",\"storeDays\":30,\"storeNum\":7}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); REPLACE INTO `sys_job` VALUES (31, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{\"dataType\":[\"auth\",\"sub\",\"voip\",\"volte\"],\"fileType\":\"txt\"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); diff --git a/build/database/std/upgrade/upg_sys_menu.sql b/build/database/std/upgrade/upg_sys_menu.sql index b083b531..6f45f6fe 100644 --- a/build/database/std/upgrade/upg_sys_menu.sql +++ b/build/database/std/upgrade/upg_sys_menu.sql @@ -171,8 +171,8 @@ REPLACE INTO `sys_menu` VALUES (2106, 'menu.perf.kpiKeyTarget', 2099, 12, 'kpiKe REPLACE INTO `sys_menu` VALUES (2107, 'menu.mml', 0, 8, 'mmlManage', '', '1', '0', 'D', '1', '1', '', 'icon-zhizuoliucheng', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mmlRemark'); REPLACE INTO `sys_menu` VALUES (2108, 'menu.mml.ne', 2107, 1, 'neOperate', 'mmlManage/neOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:neOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.neRemark'); REPLACE INTO `sys_menu` VALUES (2109, 'menu.mml.udm', 2107, 2, 'udmOperate', 'mmlManage/udmOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:udmOperate:index', 'icon-gonggaodayi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.udmRemark'); -REPLACE INTO `sys_menu` VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '1', '1', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.setRemark'); -REPLACE INTO `sys_menu` VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.omcRemark'); +REPLACE INTO `sys_menu` VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '0', '0', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.setRemark'); +REPLACE INTO `sys_menu` VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '0', '0', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.omcRemark'); REPLACE INTO `sys_menu` VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'sgwc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2113, 'menu.security', 0, 14, 'security', '', '1', '0', 'D', '1', '1', '', 'icon-suofang', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.securityRemark'); REPLACE INTO `sys_menu` VALUES (2114, 'menu.system.systemSet', 1, 60, 'setting', 'system/setting/index', '1', '1', 'M', '1', '1', 'system:setting:index', 'icon-piliang', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemSetRemark'); diff --git a/build/database/std/upgrade/upg_sys_role_menu.sql b/build/database/std/upgrade/upg_sys_role_menu.sql index e236b3e4..d8e3385b 100644 --- a/build/database/std/upgrade/upg_sys_role_menu.sql +++ b/build/database/std/upgrade/upg_sys_role_menu.sql @@ -203,7 +203,6 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2097); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2107); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2108); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2109); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2111); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2113); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2114); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2115); diff --git a/build/database/std/upgrade/upg_ue_event.sql b/build/database/std/upgrade/upg_ue_event.sql index 77d78a61..26e84ca2 100644 --- a/build/database/std/upgrade/upg_ue_event.sql +++ b/build/database/std/upgrade/upg_ue_event.sql @@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS `ue_event` ( `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '可能没有', - `timestamp` bigint DEFAULT '48' COMMENT '接收到的timestamp秒级存储毫秒时间戳', - `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型 auth-result detach cm-state', + `timestamp` bigint DEFAULT '0' COMMENT '接收到时间', + `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型', `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data JSON String', `created_at` bigint DEFAULT '0' COMMENT '记录创建存储毫秒', PRIMARY KEY (`id`) USING BTREE, @@ -22,8 +22,8 @@ ALTER TABLE `ue_event` DROP INDEX `idx_type_timestamp`; ALTER TABLE `ue_event` MODIFY COLUMN `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `id`; ALTER TABLE `ue_event` MODIFY COLUMN `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `ne_type`; ALTER TABLE `ue_event` MODIFY COLUMN `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '可能没有' AFTER `ne_name`; -ALTER TABLE `ue_event` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 48 COMMENT '接收到的timestamp秒级存储毫秒时间戳' AFTER `rm_uid`; -ALTER TABLE `ue_event` MODIFY COLUMN `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '事件类型 auth-result detach cm-state' AFTER `timestamp`; +ALTER TABLE `ue_event` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 0 COMMENT '接收到时间' AFTER `rm_uid`; +ALTER TABLE `ue_event` MODIFY COLUMN `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '事件类型' AFTER `timestamp`; ALTER TABLE `ue_event` MODIFY COLUMN `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'data JSON String' AFTER `event_type`; ALTER TABLE `ue_event` MODIFY COLUMN `created_at` bigint(20) NULL DEFAULT 0 COMMENT '记录创建存储毫秒' AFTER `event_json`; ALTER TABLE `ue_event` ADD INDEX `idx_type_t`(`event_type`, `timestamp`) USING BTREE; diff --git a/build/database/std/upgrade/upg_ue_event_amf.sql b/build/database/std/upgrade/upg_ue_event_amf.sql index 59a07c6d..5da30e00 100644 --- a/build/database/std/upgrade/upg_ue_event_amf.sql +++ b/build/database/std/upgrade/upg_ue_event_amf.sql @@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS `ue_event_amf` ( `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '可能没有', - `timestamp` bigint DEFAULT '48' COMMENT '接收到的timestamp秒级存储毫秒时间戳', - `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型 auth-result detach cm-state', + `timestamp` bigint DEFAULT '0' COMMENT '接收到时间', + `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型', `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data JSON String', `created_at` bigint DEFAULT '0' COMMENT '记录创建存储毫秒', PRIMARY KEY (`id`) USING BTREE, @@ -22,11 +22,15 @@ ALTER TABLE `ue_event_amf` DROP INDEX `idx_type_timestamp`; ALTER TABLE `ue_event_amf` MODIFY COLUMN `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `id`; ALTER TABLE `ue_event_amf` MODIFY COLUMN `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `ne_type`; ALTER TABLE `ue_event_amf` MODIFY COLUMN `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '可能没有' AFTER `ne_name`; -ALTER TABLE `ue_event_amf` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 48 COMMENT '接收到的timestamp秒级存储毫秒时间戳' AFTER `rm_uid`; -ALTER TABLE `ue_event_amf` MODIFY COLUMN `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '事件类型 auth-result detach cm-state' AFTER `timestamp`; +ALTER TABLE `ue_event_amf` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 0 COMMENT '接收到时间' AFTER `rm_uid`; +ALTER TABLE `ue_event_amf` MODIFY COLUMN `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '事件类型' AFTER `timestamp`; ALTER TABLE `ue_event_amf` MODIFY COLUMN `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'data JSON String' AFTER `event_type`; ALTER TABLE `ue_event_amf` MODIFY COLUMN `created_at` bigint(20) NULL DEFAULT 0 COMMENT '记录创建存储毫秒' AFTER `event_json`; ALTER TABLE `ue_event_amf` ADD INDEX `idx_amf_type_t`(`event_type`, `timestamp`) USING BTREE; ALTER TABLE `ue_event_amf` COMMENT = 'UE事件_AMF终端接入'; +-- 更新数据 +UPDATE `ue_event_amf` SET `event_type` = 'Auth' WHERE `event_type` = 'auth-result'; +UPDATE `ue_event_amf` SET `event_type` = 'Detach' WHERE `event_type` = 'detach'; +UPDATE `ue_event_amf` SET `event_type` = 'CM' WHERE `event_type` = 'cm-state'; -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/upgrade/upg_ue_event_mme.sql b/build/database/std/upgrade/upg_ue_event_mme.sql index 6a306fff..60acbb36 100644 --- a/build/database/std/upgrade/upg_ue_event_mme.sql +++ b/build/database/std/upgrade/upg_ue_event_mme.sql @@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS `ue_event_mme` ( `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '可能没有', - `timestamp` bigint DEFAULT '48' COMMENT '接收到的timestamp秒级存储毫秒时间戳', - `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型 auth-result detach cm-state', + `timestamp` bigint DEFAULT '0' COMMENT '接收到时间', + `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '事件类型', `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data JSON String', `created_at` bigint DEFAULT '0' COMMENT '记录创建存储毫秒', PRIMARY KEY (`id`) USING BTREE, @@ -22,11 +22,15 @@ ALTER TABLE `ue_event_mme` DROP INDEX `idx_type_timestamp`; ALTER TABLE `ue_event_mme` MODIFY COLUMN `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `id`; ALTER TABLE `ue_event_mme` MODIFY COLUMN `ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' AFTER `ne_type`; ALTER TABLE `ue_event_mme` MODIFY COLUMN `rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '可能没有' AFTER `ne_name`; -ALTER TABLE `ue_event_mme` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 48 COMMENT '接收到的timestamp秒级存储毫秒时间戳' AFTER `rm_uid`; -ALTER TABLE `ue_event_mme` MODIFY COLUMN `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '事件类型 auth-result detach cm-state' AFTER `timestamp`; +ALTER TABLE `ue_event_mme` MODIFY COLUMN `timestamp` bigint(20) NULL DEFAULT 0 COMMENT '接收到时间' AFTER `rm_uid`; +ALTER TABLE `ue_event_mme` MODIFY COLUMN `event_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '事件类型' AFTER `timestamp`; ALTER TABLE `ue_event_mme` MODIFY COLUMN `event_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'data JSON String' AFTER `event_type`; ALTER TABLE `ue_event_mme` MODIFY COLUMN `created_at` bigint(20) NULL DEFAULT 0 COMMENT '记录创建存储毫秒' AFTER `event_json`; ALTER TABLE `ue_event_mme` ADD INDEX `idx_mme_type_t`(`event_type`, `timestamp`) USING BTREE; ALTER TABLE `ue_event_mme` COMMENT = 'UE事件_MME终端接入'; +-- 更新数据 +UPDATE `ue_event_mme` SET `event_type` = 'Auth' WHERE `event_type` = 'auth-result'; +UPDATE `ue_event_mme` SET `event_type` = 'Detach' WHERE `event_type` = 'detach'; +UPDATE `ue_event_mme` SET `event_type` = 'CM' WHERE `event_type` = 'cm-state'; -- Dump completed on 2025-02-14 15:26:56 From edbdcca74775b1a69afae397262c24dc1153dff0 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 19:04:36 +0800 Subject: [PATCH 23/80] =?UTF-8?q?sql:=20=E6=9B=B4=E6=96=B0OMC/CBC/UDM?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E9=85=8D=E7=BD=AE=E6=98=A0=E5=B0=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/common/ne_config.sql | 48 ++++----- build/database/std/common/ne_config.sql | 48 ++++----- local/param/cbc_param_config.yaml | 126 +++++++++++++++++------ local/param/omc_param_config.yaml | 55 +++++----- local/param/udm_param_config.yaml | 2 +- 5 files changed, 165 insertions(+), 114 deletions(-) diff --git a/build/database/lite/common/ne_config.sql b/build/database/lite/common/ne_config.sql index c99a77bc..2df1a188 100644 --- a/build/database/lite/common/ne_config.sql +++ b/build/database/lite/common/ne_config.sql @@ -96,22 +96,22 @@ INSERT INTO "ne_config" VALUES (190, 'SMF', 'localDhcpCfg', 'Local DHCP Config', INSERT INTO "ne_config" VALUES (191, 'SMF', 'dnnselectdhcpserver', 'DNN Select DHCP Server', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"0~65535","name":"index","type":"int","value":""},{"access":"read-write","comment":"","display":"Enable","filter":"","name":"enable","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"DNN","filter":"1~64","name":"dnn","type":"string","value":""},{"access":"read-write","comment":"e.g. 192.168.1.1","display":"DHCP Server IP","filter":"","name":"dhcpServerAddr","type":"string","value":""}]', 23, '', 1751019165587, 'public'); INSERT INTO "ne_config" VALUES (192, 'SMF', 'offlineChargingConfig', 'Offline Charging Config', 'list', '[{"access":"read-write","comment":"","display":"CDR File Name","filter":"1~64","name":"cdrFileName","type":"string","value":"smf.cdr"},{"access":"read-write","comment":"","display":"CDR File Path","filter":"1~256","name":"cdrFilePath","type":"string","value":"/var/log/smfCdr"},{"access":"read-write","comment":"","display":"CDR File Num","filter":"1~999999999","name":"cdrFileNum","type":"int","value":"50"},{"access":"read-write","comment":"Megabytes","display":"CDR File Size","filter":"1~999999","name":"cdrFileSize","type":"int","value":"300"},{"access":"read-write","comment":"Days","display":"CDR File Max Age","filter":"0~9999","name":"cdrFileMaxAge","type":"int","value":"30"},{"access":"read-write","comment":"","display":"Free Subscribers CDR Enable","filter":"","name":"freeSubsCdrEnable","type":"bool","value":"false"},{"access":"read-write","comment":"Seconds","display":"Time Threshold","filter":"0~999999999","name":"timeThreshold","type":"int","value":"600"},{"access":"read-write","comment":"Bytes","display":"Volume Threshold","filter":"0~999999999999999","name":"volumeThreshold","type":"int","value":"0"}]', 25, '', 1751019165593, 'public'); --- 更新 UDM 配置 20250613 -INSERT INTO "ne_config" VALUES (200, 'UDM', 'system', 'System', 'list', '[{"access":"read-write","comment":"","display":"Service IP","filter":"","name":"serviceIP","type":"ipv4","value":"172.16.5.140"},{"access":"read-write","comment":"","display":"Service Port","filter":"0~65535","name":"servicePort","type":"int","value":"8080"},{"access":"read-write","comment":"","display":"NRF URI","filter":"","name":"nrfUri","type":"string","value":"http://172.16.5.180:8080"},{"access":"read-write","comment":"","display":"FQDN","filter":"","name":"fqdn","type":"string","value":"omc.com"},{"access":"read-write","comment":"","display":"Priority","filter":"0~4095","name":"priority","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Capacity","filter":"0~65535","name":"capacity","type":"int","value":"4096"},{"access":"read-write","comment":"","display":"Group ID","filter":"","name":"groupId","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Supported Plmn1","filter":"^\\d{5,6}$","name":"supportedPlmn1","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn2","filter":"^\\d{5,6}$","name":"supportedPlmn2","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn3","filter":"^\\d{5,6}$","name":"supportedPlmn3","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn4","filter":"^\\d{5,6}$","name":"supportedPlmn4","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"SUPI Ranges","filter":"^imsi-\\d{15}~imsi-\\d{15}$","name":"supiRanges","type":"regex","value":"imsi-001010100080000~imsi-001010100080099"},{"access":"read-write","comment":"","display":"GPSI Ranges","filter":"^msisdn-\\d{2,15}~msisdn-\\d{2,15}$","name":"gpsiRanges","type":"regex","value":"msisdn-69072000~msisdn-69072099"},{"access":"read-write","comment":"","display":"Scheme","filter":"{\"0\":\"HTTP\", \"1\":\"HTTPS\"}","name":"scheme","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Redis Link","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"redisLink","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Redis Address","filter":"","name":"redisAddr","type":"string","value":"172.16.5.140:6379"}]', 1, '', 1751451940555, 'public'); -INSERT INTO "ne_config" VALUES (201, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"Uplink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"uplink","type":"regex","value":"1 Gbps"},{"access":"read-write","comment":"","display":"Downlink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"downlink","type":"regex","value":"2 Gbps"}]', 5, '', 1751451940566, 'public'); -INSERT INTO "ne_config" VALUES (202, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_nssai"},{"access":"read-write","comment":"","display":"Supported Features","filter":"^[0-9a-fA-F]{8}$","name":"supportedFeatures","type":"regex","value":"00000001"},{"access":"read-write","comment":"","display":"Default Single NSSAIs","filter":"","name":"defaultSingleNSSAIs","type":"string","value":"1-000001"},{"access":"read-write","comment":"","display":"Single NSSAIs","filter":"","name":"singleNssais","type":"string","value":"1-000002"}]', 7, '', 1751451940570, 'public'); -INSERT INTO "ne_config" VALUES (203, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"TACs","filter":"","name":"tacs","type":"string","value":"123"},{"access":"read-write","comment":"","display":"Area Codes","filter":"","name":"areaCodes","type":"string","value":"123456"}]', 9, '', 1751451940574, 'public'); -INSERT INTO "ne_config" VALUES (204, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"Restriction Type","filter":"{\"0\":\"Allowed Areas\", \"1\":\"Not Allowed Areas\"}","name":"restrictionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"TACs","filter":"","name":"tacs","type":"string","value":"123"},{"access":"read-write","comment":"","display":"Area Codes","filter":"","name":"areaCodes","type":"string","value":"123456"},{"access":"read-write","comment":"","display":"Max TAs","filter":"^\\d{1,2}$","name":"maxTAs","type":"int","value":"1"}]', 11, '', 1751451940579, 'public'); -INSERT INTO "ne_config" VALUES (205, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_snssai"},{"access":"read-write","comment":"","display":"SNSSAI","filter":"^\\d{1,3}[A-Fa-f0-9]{6}$","name":"snssai","type":"string","value":"1-000001"},{"access":"read-only","array":[{"access":"read-only","comment":"","display":"Index","filter":"1~4","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"DNN","filter":"^.{1,32}$","name":"dnn","type":"string","value":"internet"},{"access":"read-write","comment":"","display":"Default DNN Indicator","filter":"false;true;","name":"defaultDnnInd","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"LBO Roaming Allowed","filter":"false;true;","name":"lboRoamingAllowed","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"Interworking EPS Indicator","filter":"false;true;","name":"iwkEpsInd","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"LADN Indicator","filter":"false;true;","name":"ladnIndicator","type":"bool","value":"false"}],"comment":"","display":"DNN List","filter":"1~4","name":"dnnList","type":"int","value":"1"}]', 13, '', 1751451940583, 'public'); -INSERT INTO "ne_config" VALUES (206, 'UDM', 'dnn', 'DNN Conf', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_nssai"},{"access":"read-write","comment":"","display":"Default PDU Session Type","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"Ethernet\",\"4\":\"Unstruction\"}","name":"defaultPDUSessionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Allowed PDU Session Types","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"Ethernet\",\"4\":\"Unstruction\",\"5\":\"IPv4 \u0026 IPv6\",\"6\":\"IPv4 \u0026 IPv4v6\",\"7\":\"IPv6 \u0026 IPv4v6\",\"8\":\"IPv4 \u0026 IPv6 \u0026 IPv4v6\"}","name":"allowedPDUSessionTypes","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"5QI","filter":"0~255","name":"5qi","type":"int","value":"9"},{"access":"read-write","comment":"","display":"Priority Level","filter":"1~127","name":"priorityLevel","type":"int","value":"9"},{"access":"read-write","comment":"","display":"Default SSC Mode","filter":"{\"0\":\"SSC Mode1\",\"1\":\"SSC Mode2\",\"2\":\"SSC Mode3\"}","name":"defaultSSCmode","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Allowed SSC Modes","filter":"{\"0\":\"SSC Mode1\",\"1\":\"SSC Mode2\",\"2\":\"SSC Mode3\",\"3\":\"SSC Mode1 \u0026 SSC Mode2\",\"4\":\"SSC Mode1 \u0026 SSC Mode3\",\"5\":\"SSC Mode2 \u0026 SSC Mode3\",\"6\":\"SSC Mode1 \u0026 SSC Mode2 \u0026 SSC Mode3\"}","name":"allowedSSCmodes","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Interworking EPS Indicator","filter":"","name":"interworkingEPSIndicator","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"LADN Indicator","filter":"","name":"ladnIndicator","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"Charging Characteristics","filter":"4~4","name":"chargingCharacteristics","type":"string","value":"0001"},{"access":"read-write","comment":"","display":"Subscribed Session AMBR Uplink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"subscribedSessionAmbrUL","type":"regex","value":"1 Gbps"},{"access":"read-write","comment":"","display":"Subscribed Session AMBR Downlink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"subscribedSessionAmbrDL","type":"regex","value":"2 Gbps"},{"access":"read-write","comment":"","display":"Static IP Address","filter":"","name":"staticIPAddress","type":"ipv4","value":"192.168.1.100"},{"access":"read-write","comment":"","display":"User Plane Integrity","filter":"{\"0\":\"Null\",\"1\":\"Required\",\"2\":\"Preferred\",\"3\":\"Not Needed\"}","name":"userPlaneIntegrity","type":"enum","value":"3"},{"access":"read-write","comment":"","display":"User Plane Confidentiality","filter":"{\"0\":\"Null\",\"1\":\"Required\",\"2\":\"Preferred\",\"3\":\"Not Needed\"}","name":"userPlaneConfidentiality","type":"enum","value":"3"},{"access":"read-write","comment":"","display":"ARP Priority Level","filter":"0~255","name":"arpPriorityLevel","type":"int","value":"6"},{"access":"read-write","comment":"","display":"ARP Preempt Capability","filter":"{\"0\":\"Not Preempt\",\"1\":\"May Preempt\"}","name":"arpPreemptCap","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"ARP Preempt Vulnerability","filter":"{\"0\":\"Not Preemptable\",\"1\":\"Preemptable\"}","name":"arpPreemptVuln","type":"enum","value":"0"}]', 15, '', 1751451940587, 'public'); -INSERT INTO "ne_config" VALUES (207, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{0,31}$","name":"name","type":"string","value":"def_eps"},{"access":"read-write","comment":"","display":"AMBR Uplink","filter":"0~4294967295","name":"ambrUplink","type":"int","value":"100000000"},{"access":"read-write","comment":"","display":"AMBR Downlink","filter":"0~4294967295","name":"ambrDownlink","type":"int","value":"200000000"},{"access":"read-write","comment":"","display":"APN OI Replacement","filter":"^.{0,31}$","name":"apnOIReplacement","type":"string","value":"money"},{"access":"read-write","comment":"","display":"RFSP","filter":"","name":"rfsp","type":"int","value":"1"},{"access":"read-write","comment":"","display":"RAU TAU Timer","filter":"","name":"rauTauTimer","type":"int","value":"120"},{"access":"read-write","comment":"","display":"Charging Characteristic","filter":"4~4","name":"chargingCharacteristic","type":"string","value":"0001"}]', 17, '', 1751451940591, 'public'); -INSERT INTO "ne_config" VALUES (208, 'UDM', 'epsApn', 'EPS APN', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"DNN","filter":"^.{0,127}$","name":"dnn","type":"string","value":"internet"},{"access":"read-write","comment":"","display":"PDN Type","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"IPv4 or IPv6\"}","name":"pdnType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"QCI","filter":"1~255","name":"qci","type":"int","value":"9"},{"access":"read-write","comment":"","display":"ARP Priority","filter":"1~127","name":"arpPriorityLevel","type":"int","value":"8"},{"access":"read-write","comment":"","display":"ARP Preemption Capability","filter":"{\"0\":\"Not Preempt\",\"1\":\"May Preempt\"}","name":"arpPreemptCap","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"ARP Preemption Vulnerability","filter":"{\"0\":\"Not Preemptable\",\"1\":\"Preemptable\"}","name":"arpPreemptVuln","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Context Identifier","filter":"","name":"contextIdentifier","type":"int","value":"1"},{"access":"read-write","comment":"","display":"VPLMN Dynamic Address Allowed","filter":"false;true;","name":"vplmnDynamicAddressAllowed","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"PDN GW Allocation Type","filter":"{\"0\":\"Static\",\"1\":\"Dynamic\"}","name":"pdnGWAllocationType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"AMBR Uplink","filter":"0~4294967295","name":"ambrUplink","type":"int","value":"100000000"},{"access":"read-write","comment":"","display":"AMBR Downlink","filter":"0~4294967295","name":"ambrDownlink","type":"int","value":"200000000"},{"access":"read-write","comment":"","display":"Charging Characteristic","filter":"4~4","name":"chargingCharacteristic","type":"string","value":"0001"}]', 19, '', 1751451940594, 'public'); -INSERT INTO "ne_config" VALUES (209, 'UDM', 'applicationServer', 'Application Server', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"AS Name","filter":"^.{1,31}$","name":"name","type":"string","value":"mmtel_as"},{"access":"read-write","comment":"","display":"Default Handling","filter":"{\"0\":\"Session Continued\",\"1\":\"Session Terminated\"}","name":"defaultHandling","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Server Name","filter":"^.{1,127}$","name":"serverName","type":"string","value":"sip:192.168.8.26:7060"},{"access":"read-write","comment":"","display":"Diameter Address","filter":"^.{1,127}$","name":"diameterAddress","type":"string","value":"mmtel.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Rep Data Size Limit","filter":"0~65535","name":"repDataSizeLimit","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Include Register Request","filter":"false;true;","name":"includeRegisterRequest","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"Include Register Response","filter":"false;true;","name":"includeRegisterResponse","type":"bool","value":"false"}]', 21, '', 1751451940597, 'public'); -INSERT INTO "ne_config" VALUES (210, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~8","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,31}$","name":"name","type":"string","value":"mmtel_as"},{"access":"read-write","comment":"","display":"Priority","filter":"","name":"priority","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Server Name","filter":"^.{1,127}$","name":"serverName","type":"string","value":"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060"}]', 23, '', 1751451940601, 'public'); -INSERT INTO "ne_config" VALUES (211, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_snssai"},{"access":"read-write","comment":"","display":"Condition Type CNF","filter":"0~1","name":"conditionTypeCNF","type":"int","value":"0"},{"access":"read-only","array":[{"access":"read-only","comment":"","display":"Index","filter":"1~4","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Enable","filter":"","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Condition Negated","filter":"0~1","name":"conditionNegated","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Group","filter":"0~4096","name":"group","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Method","filter":"^.{0,32}$","name":"method","type":"string","value":""},{"access":"read-write","comment":"","display":"SIP Header","filter":"^.{0,64}$","name":"sipHeader","type":"string","value":""},{"access":"read-write","comment":"","display":"SIP Content","filter":"^.{0,64}$","name":"sipContent","type":"string","value":""}],"comment":"","display":"SPT List","filter":"1~4","name":"sptList","type":"int","value":"1"}]', 25, '', 1751451940605, 'public'); -INSERT INTO "ne_config" VALUES (212, 'UDM', 's6aServer', 'S6a Server', 'list', '[{"access":"read-write","comment":"","display":"Enable","filter":"false;true;","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"netType","type":"enum","value":"1"},{"access":"read-write","comment":"","display":"Address","filter":"","name":"addr","type":"string","value":"172.16.5.140:3868"},{"access":"read-write","comment":"","display":"Host","filter":"^.{1,127}$","name":"host","type":"string","value":"hss.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Realm","filter":"^.{1,127}$","name":"realm","type":"string","value":"ims.mnc001.mcc001.3gppnetwork.org"}]', 27, '', 1751451940610, 'public'); -INSERT INTO "ne_config" VALUES (213, 'UDM', 'cxServer', 'Cx Server', 'list', '[{"access":"read-write","comment":"","display":"Enable","filter":"false;true;","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"netType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Address","filter":"","name":"addr","type":"string","value":"172.16.5.140:3868"},{"access":"read-write","comment":"","display":"Host","filter":"^.{1,127}$","name":"host","type":"string","value":"hss.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Realm","filter":"^.{1,127}$","name":"realm","type":"string","value":"ims.mnc001.mcc001.3gppnetwork.org"}]', 29, '', 1751451940614, 'public'); -INSERT INTO "ne_config" VALUES (214, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{"access":"read-write","comment":"","display":"AUSF enable","filter":"","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"EAP-Aka SupiOrImsi Prefix","filter":"","name":"eapAkaSupiImsiPrefix","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"AUSF FQDN","filter":"0~128","name":"ausfFqdn","type":"string","value":"ausf.5gc.com"}]', 3, '', 1751451940561, 'public'); +-- 更新 UDM 配置 20250715 +INSERT INTO "ne_config" VALUES (200, 'UDM', 'system', 'System', 'list', '[{"access":"read-write","comment":"","display":"Service IP","filter":"","name":"serviceIP","type":"ipv4","value":"172.16.5.140"},{"access":"read-write","comment":"","display":"Service Port","filter":"0~65535","name":"servicePort","type":"int","value":"8080"},{"access":"read-write","comment":"","display":"NRF URI","filter":"","name":"nrfUri","type":"string","value":"http://172.16.5.180:8080"},{"access":"read-write","comment":"","display":"FQDN","filter":"","name":"fqdn","type":"string","value":"omc.com"},{"access":"read-write","comment":"","display":"Priority","filter":"0~4095","name":"priority","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Capacity","filter":"0~65535","name":"capacity","type":"int","value":"4096"},{"access":"read-write","comment":"","display":"Group ID","filter":"","name":"groupId","type":"string","value":"0"},{"access":"read-write","comment":"","display":"Supported Plmn1","filter":"^\\d{5,6}$","name":"supportedPlmn1","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn2","filter":"^\\d{5,6}$","name":"supportedPlmn2","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn3","filter":"^\\d{5,6}$","name":"supportedPlmn3","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"Supported Plmn4","filter":"^\\d{5,6}$","name":"supportedPlmn4","type":"string","value":"00101"},{"access":"read-write","comment":"","display":"SUPI Ranges","filter":"^imsi-\\d{15}~imsi-\\d{15}$","name":"supiRanges","type":"regex","value":"imsi-001010100080000~imsi-001010100080099"},{"access":"read-write","comment":"","display":"GPSI Ranges","filter":"^msisdn-\\d{2,15}~msisdn-\\d{2,15}$","name":"gpsiRanges","type":"regex","value":"msisdn-69072000~msisdn-69072099"},{"access":"read-write","comment":"","display":"Scheme","filter":"{\"0\":\"HTTP\", \"1\":\"HTTPS\"}","name":"scheme","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Redis Link","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"redisLink","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Redis Address","filter":"","name":"redisAddr","type":"string","value":"172.16.5.140:6379"}]', 1, '', 1752577177260, 'public'); +INSERT INTO "ne_config" VALUES (201, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{"access":"read-write","comment":"","display":"AUSF enable","filter":"","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"EAP-Aka SupiOrImsi Prefix","filter":"","name":"eapAkaSupiImsiPrefix","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"AUSF FQDN","filter":"0~128","name":"ausfFqdn","type":"string","value":"ausf.5gc.com"}]', 3, '', 1752577177350, 'public'); +INSERT INTO "ne_config" VALUES (202, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"Uplink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"uplink","type":"regex","value":"1 Gbps"},{"access":"read-write","comment":"","display":"Downlink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"downlink","type":"regex","value":"2 Gbps"}]', 5, '', 1752577177371, 'public'); +INSERT INTO "ne_config" VALUES (203, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_nssai"},{"access":"read-write","comment":"","display":"Supported Features","filter":"^[0-9a-fA-F]{8}$","name":"supportedFeatures","type":"regex","value":"00000001"},{"access":"read-write","comment":"","display":"Default Single NSSAIs","filter":"","name":"defaultSingleNSSAIs","type":"string","value":"1-000001"},{"access":"read-write","comment":"","display":"Single NSSAIs","filter":"","name":"singleNssais","type":"string","value":"1-000002"}]', 7, '', 1752577177376, 'public'); +INSERT INTO "ne_config" VALUES (204, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_ambr"},{"access":"read-write","comment":"","display":"TACs","filter":"","name":"tacs","type":"string","value":"123"},{"access":"read-write","comment":"","display":"Area Codes","filter":"","name":"areaCodes","type":"string","value":"123456"}]', 9, '', 1752577177380, 'public'); +INSERT INTO "ne_config" VALUES (205, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"lab_sar"},{"access":"read-write","comment":"","display":"Restriction Type","filter":"{\"0\":\"Allowed Areas\", \"1\":\"Not Allowed Areas\"}","name":"restrictionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"TACs","filter":"","name":"tacs","type":"string","value":"123"},{"access":"read-write","comment":"","display":"Area Codes","filter":"","name":"areaCodes","type":"string","value":"123456"},{"access":"read-write","comment":"","display":"Max TAs","filter":"^\\d{1,2}$","name":"maxTAs","type":"int","value":"1"}]', 11, '', 1752577177385, 'public'); +INSERT INTO "ne_config" VALUES (206, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_snssai"},{"access":"read-write","comment":"","display":"SNSSAI","filter":"^\\d{1,3}[A-Fa-f0-9]{6}$","name":"snssai","type":"string","value":"1-000001"},{"access":"read-only","array":[{"access":"read-only","comment":"","display":"Index","filter":"1~4","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"DNN","filter":"^.{1,32}$","name":"dnn","type":"string","value":"internet"},{"access":"read-write","comment":"","display":"Default DNN Indicator","filter":"false;true;","name":"defaultDnnInd","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"LBO Roaming Allowed","filter":"false;true;","name":"lboRoamingAllowed","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"Interworking EPS Indicator","filter":"false;true;","name":"iwkEpsInd","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"LADN Indicator","filter":"false;true;","name":"ladnIndicator","type":"bool","value":"false"}],"comment":"","display":"DNN List","filter":"1~4","name":"dnnList","type":"int","value":"1"}]', 13, '', 1752577177391, 'public'); +INSERT INTO "ne_config" VALUES (207, 'UDM', 'dnn', 'DNN Conf', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_nssai"},{"access":"read-write","comment":"","display":"Default PDU Session Type","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"Ethernet\",\"4\":\"Unstruction\"}","name":"defaultPDUSessionType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Allowed PDU Session Types","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"Ethernet\",\"4\":\"Unstruction\",\"5\":\"IPv4 \u0026 IPv6\",\"6\":\"IPv4 \u0026 IPv4v6\",\"7\":\"IPv6 \u0026 IPv4v6\",\"8\":\"IPv4 \u0026 IPv6 \u0026 IPv4v6\"}","name":"allowedPDUSessionTypes","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"5QI","filter":"0~255","name":"5qi","type":"int","value":"9"},{"access":"read-write","comment":"","display":"Priority Level","filter":"1~127","name":"priorityLevel","type":"int","value":"9"},{"access":"read-write","comment":"","display":"Default SSC Mode","filter":"{\"0\":\"SSC Mode1\",\"1\":\"SSC Mode2\",\"2\":\"SSC Mode3\"}","name":"defaultSSCmode","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Allowed SSC Modes","filter":"{\"0\":\"SSC Mode1\",\"1\":\"SSC Mode2\",\"2\":\"SSC Mode3\",\"3\":\"SSC Mode1 \u0026 SSC Mode2\",\"4\":\"SSC Mode1 \u0026 SSC Mode3\",\"5\":\"SSC Mode2 \u0026 SSC Mode3\",\"6\":\"SSC Mode1 \u0026 SSC Mode2 \u0026 SSC Mode3\"}","name":"allowedSSCmodes","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Interworking EPS Indicator","filter":"","name":"interworkingEPSIndicator","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"LADN Indicator","filter":"","name":"ladnIndicator","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"Charging Characteristics","filter":"4~4","name":"chargingCharacteristics","type":"string","value":"0001"},{"access":"read-write","comment":"","display":"Subscribed Session AMBR Uplink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"subscribedSessionAmbrUL","type":"regex","value":"1 Gbps"},{"access":"read-write","comment":"","display":"Subscribed Session AMBR Downlink","filter":"^\\d+(\\.\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$","name":"subscribedSessionAmbrDL","type":"regex","value":"2 Gbps"},{"access":"read-write","comment":"","display":"Static IP Address","filter":"","name":"staticIPAddress","type":"ipv4","value":"192.168.1.100"},{"access":"read-write","comment":"","display":"User Plane Integrity","filter":"{\"0\":\"Null\",\"1\":\"Required\",\"2\":\"Preferred\",\"3\":\"Not Needed\"}","name":"userPlaneIntegrity","type":"enum","value":"3"},{"access":"read-write","comment":"","display":"User Plane Confidentiality","filter":"{\"0\":\"Null\",\"1\":\"Required\",\"2\":\"Preferred\",\"3\":\"Not Needed\"}","name":"userPlaneConfidentiality","type":"enum","value":"3"},{"access":"read-write","comment":"","display":"ARP Priority Level","filter":"0~255","name":"arpPriorityLevel","type":"int","value":"6"},{"access":"read-write","comment":"","display":"ARP Preempt Capability","filter":"{\"0\":\"Not Preempt\",\"1\":\"May Preempt\"}","name":"arpPreemptCap","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"ARP Preempt Vulnerability","filter":"{\"0\":\"Not Preemptable\",\"1\":\"Preemptable\"}","name":"arpPreemptVuln","type":"enum","value":"0"}]', 15, '', 1752577177395, 'public'); +INSERT INTO "ne_config" VALUES (208, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{0,31}$","name":"name","type":"string","value":"def_eps"},{"access":"read-write","comment":"","display":"AMBR Uplink","filter":"0~4294967295","name":"ambrUplink","type":"int","value":"100000000"},{"access":"read-write","comment":"","display":"AMBR Downlink","filter":"0~4294967295","name":"ambrDownlink","type":"int","value":"200000000"},{"access":"read-write","comment":"","display":"APN OI Replacement","filter":"^.{0,31}$","name":"apnOIReplacement","type":"string","value":"money"},{"access":"read-write","comment":"","display":"RFSP","filter":"","name":"rfsp","type":"int","value":"1"},{"access":"read-write","comment":"","display":"RAU TAU Timer","filter":"","name":"rauTauTimer","type":"int","value":"120"},{"access":"read-write","comment":"","display":"Charging Characteristic","filter":"4~4","name":"chargingCharacteristic","type":"string","value":"0001"}]', 17, '', 1752577177401, 'public'); +INSERT INTO "ne_config" VALUES (209, 'UDM', 'epsApn', 'EPS APN', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"DNN","filter":"^.{0,127}$","name":"dnn","type":"string","value":"internet"},{"access":"read-write","comment":"","display":"PDN Type","filter":"{\"0\":\"IPv4\",\"1\":\"IPv6\",\"2\":\"IPv4v6\",\"3\":\"IPv4 or IPv6\"}","name":"pdnType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"QCI","filter":"1~255","name":"qci","type":"int","value":"9"},{"access":"read-write","comment":"","display":"ARP Priority","filter":"1~127","name":"arpPriorityLevel","type":"int","value":"8"},{"access":"read-write","comment":"","display":"ARP Preemption Capability","filter":"{\"0\":\"Not Preempt\",\"1\":\"May Preempt\"}","name":"arpPreemptCap","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"ARP Preemption Vulnerability","filter":"{\"0\":\"Not Preemptable\",\"1\":\"Preemptable\"}","name":"arpPreemptVuln","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Context Identifier","filter":"","name":"contextIdentifier","type":"int","value":"1"},{"access":"read-write","comment":"","display":"VPLMN Dynamic Address Allowed","filter":"false;true;","name":"vplmnDynamicAddressAllowed","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"PDN GW Allocation Type","filter":"{\"0\":\"Static\",\"1\":\"Dynamic\"}","name":"pdnGWAllocationType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"AMBR Uplink","filter":"0~4294967295","name":"ambrUplink","type":"int","value":"100000000"},{"access":"read-write","comment":"","display":"AMBR Downlink","filter":"0~4294967295","name":"ambrDownlink","type":"int","value":"200000000"},{"access":"read-write","comment":"","display":"Charging Characteristic","filter":"4~4","name":"chargingCharacteristic","type":"string","value":"0001"}]', 19, '', 1752577177405, 'public'); +INSERT INTO "ne_config" VALUES (210, 'UDM', 'applicationServer', 'Application Server', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"AS Name","filter":"^.{1,31}$","name":"name","type":"string","value":"mmtel_as"},{"access":"read-write","comment":"","display":"Default Handling","filter":"{\"0\":\"Session Continued\",\"1\":\"Session Terminated\"}","name":"defaultHandling","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Server Name","filter":"^.{1,127}$","name":"serverName","type":"string","value":"sip:192.168.8.26:7060"},{"access":"read-write","comment":"","display":"Diameter Address","filter":"^.{1,127}$","name":"diameterAddress","type":"string","value":"mmtel.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Rep Data Size Limit","filter":"0~65535","name":"repDataSizeLimit","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Include Register Request","filter":"false;true;","name":"includeRegisterRequest","type":"bool","value":"false"},{"access":"read-write","comment":"","display":"Include Register Response","filter":"false;true;","name":"includeRegisterResponse","type":"bool","value":"false"}]', 21, '', 1752577177410, 'public'); +INSERT INTO "ne_config" VALUES (211, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~8","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,31}$","name":"name","type":"string","value":"mmtel_as"},{"access":"read-write","comment":"","display":"Priority","filter":"","name":"priority","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Server Name","filter":"^.{1,127}$","name":"serverName","type":"string","value":"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060"}]', 23, '', 1752577177415, 'public'); +INSERT INTO "ne_config" VALUES (212, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{"access":"read-only","comment":"","display":"Index","filter":"1~16","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Name","filter":"^.{1,32}$","name":"name","type":"string","value":"def_snssai"},{"access":"read-write","comment":"","display":"Condition Type CNF","filter":"0~1","name":"conditionTypeCNF","type":"int","value":"0"},{"access":"read-only","array":[{"access":"read-only","comment":"","display":"Index","filter":"1~4","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Enable","filter":"","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Condition Negated","filter":"0~1","name":"conditionNegated","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Group","filter":"0~4096","name":"group","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Method","filter":"^.{0,32}$","name":"method","type":"string","value":""},{"access":"read-write","comment":"","display":"SIP Header","filter":"^.{0,64}$","name":"sipHeader","type":"string","value":""},{"access":"read-write","comment":"","display":"SIP Content","filter":"^.{0,64}$","name":"sipContent","type":"string","value":""}],"comment":"","display":"SPT List","filter":"1~4","name":"sptList","type":"int","value":"1"}]', 25, '', 1752577177419, 'public'); +INSERT INTO "ne_config" VALUES (213, 'UDM', 's6aServer', 'S6a Server', 'list', '[{"access":"read-write","comment":"","display":"Enable","filter":"false;true;","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"netType","type":"enum","value":"1"},{"access":"read-write","comment":"","display":"Address","filter":"","name":"addr","type":"string","value":"172.16.5.140:3868"},{"access":"read-write","comment":"","display":"Host","filter":"^.{1,127}$","name":"host","type":"string","value":"hss.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Realm","filter":"^.{1,127}$","name":"realm","type":"string","value":"ims.mnc001.mcc001.3gppnetwork.org"}]', 27, '', 1752577177423, 'public'); +INSERT INTO "ne_config" VALUES (214, 'UDM', 'cxServer', 'Cx Server', 'list', '[{"access":"read-write","comment":"","display":"Enable","filter":"false;true;","name":"enable","type":"bool","value":"true"},{"access":"read-write","comment":"","display":"Link Type","filter":"{\"0\":\"TCP\",\"1\":\"SCTP\"}","name":"netType","type":"enum","value":"0"},{"access":"read-write","comment":"","display":"Address","filter":"","name":"addr","type":"string","value":"172.16.5.140:3868"},{"access":"read-write","comment":"","display":"Host","filter":"^.{1,127}$","name":"host","type":"string","value":"hss.ims.mnc001.mcc001.3gppnetwork.org"},{"access":"read-write","comment":"","display":"Realm","filter":"^.{1,127}$","name":"realm","type":"string","value":"ims.mnc001.mcc001.3gppnetwork.org"}]', 29, '', 1752577177427, 'public'); -- 更新 UPF 配置 20250320 INSERT INTO "ne_config" VALUES (220, 'UPF', 'general', 'General', 'list', '[{"access":"read-write","comment":"","display":"Config File Directory","filter":"","name":"configFileDirectory","type":"string","value":"/usr/local/etc/upf/"},{"access":"read-write","comment":"","display":"EXE File Directory","filter":"","name":"exeFileDirectory","type":"string","value":"/usr/local/bin/"},{"access":"read-write","comment":"1~255","display":"System ID","filter":"","name":"systemId","type":"int","value":"1"},{"access":"read-write","comment":"1~8","display":"Data Forwarder Number","filter":"1~8","name":"dataForwarderNum","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Common Statistic Interval","filter":"","name":"commonStatisticInterval","type":"int","value":"60"},{"access":"read-write","comment":"","display":"User Statistic Interval","filter":"","name":"userStatisticInterval","type":"int","value":"60"},{"access":"read-write","comment":"","display":"RX N3 OverLoad Threshold Mbps","filter":"","name":"rxN3OverLoadThresholdMbps","type":"int","value":"0"},{"access":"read-write","comment":"","display":"RX N6 OverLoad Threshold Mbps","filter":"","name":"rxN6OverLoadThresholdMbps","type":"int","value":"0"},{"access":"read-write","comment":"0~255","display":"Checksum Offload","filter":"0~255","name":"checksumOffload","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Max Downlink Buffer Num","filter":"","name":"maxDownlinkBufferNum","type":"int","value":"50"}]', 1, '', 1742469466451, 'public'); @@ -133,15 +133,15 @@ INSERT INTO "ne_config" VALUES (235, 'UPF', 'dpiHeaderEnrichInfoList', 'DPI Head INSERT INTO "ne_config" VALUES (236, 'UPF', 'dpiAppList', 'DPI APP List', 'array', '[{"access":"read-write","comment":"1~32","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"APP Name","filter":"","name":"appName","type":"string","value":""},{"access":"read-write","comment":"","display":"Proxy Enabled","filter":"0~1","name":"proxyEnabled","type":"int","value":"0"},{"access":"read-write","comment":"","display":"Force Check Type","filter":"0~1","name":"forceCheckType","type":"int","value":"0"},{"access":"read-write","comment":"","display":"N3 Interface ID","filter":"0~32","name":"n3InterfaceId","type":"int","value":"0"},{"access":"read-write","comment":"","display":"N6 Interface ID","filter":"0~32","name":"n6InterfaceId","type":"int","value":"0"},{"access":"read-write","array":[{"access":"read-only","comment":"1~32","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Rule ID","filter":"","name":"ruleId","type":"int","value":""},{"access":"read-write","comment":"","display":"REGEX Match","filter":"","name":"regexMatch","type":"string","value":""},{"access":"read-write","comment":"","display":"Flow Description","filter":"","name":"flowDescription","type":"string","value":""},{"access":"read-write","comment":"","display":"Custom Name","filter":"","name":"customName","type":"string","value":""}],"comment":"","display":"Rule List","filter":"0~32","name":"ruleList","type":"int","value":"1"}]', 35, '', 1742469466580, 'public'); INSERT INTO "ne_config" VALUES (237, 'UPF', 'networkControlFreeServerList', 'Free Server List', 'array', '[{"access":"read-write","comment":"1~32","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Enabled","filter":"0~1","name":"enabled","type":"int","value":"0"},{"access":"read-write","array":[{"access":"read-only","comment":"1~32","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"Server IPv4","filter":"","name":"serverIpv4","type":"string","value":"0.0.0.0"},{"access":"read-write","comment":"","display":"Server IPv4 Mask","filter":"","name":"serverIpv4Mask","type":"string","value":"255.255.255.0"},{"access":"read-write","comment":"","display":"Server IPv6","filter":"","name":"serverIpv6","type":"string","value":""},{"access":"read-write","comment":"","display":"Server IPv6 Prefix","filter":"","name":"serverIpv6Prefix","type":"int","value":"64"}],"comment":"","display":"Free Server Address List","filter":"0~32","name":"freeServerAddrList","type":"int","value":"1"}]', 27, '', 1742469466563, 'public'); --- 更新 CBC 配置 20240823 -INSERT INTO "ne_config" VALUES (240, 'CBC', 'system', 'System Config', 'list', '[{"access":"read-write","comment":"","display":"CBC Name","filter":"0~64","name":"name","type":"string","value":"CBC"},{"access":"read-write","comment":"","display":"NF Instance","filter":"0~64","name":"instance","type":"string","value":"CBC-001"},{"access":"read-write","comment":"","display":"SBI Server IP","filter":"0~64","name":"sbiIp","type":"string","value":"127.0.0.1"},{"access":"read-write","comment":"0~65535","display":"SBI Server Port","filter":"0~65535","name":"sbiPort","type":"int","value":"9090"},{"access":"read-write","comment":"http or https","display":"SBI Scheme","filter":"{\"0\":\"http\",\"1\":\"https\"}","name":"sbiScheme","type":"enum","value":"0"}]', 1, '', 1724327154483, 'public'); -INSERT INTO "ne_config" VALUES (241, 'CBC', 'amfProfile', 'AMF Profile', 'array', '[{"access":"read-only","comment":"0~15","display":"Index","filter":"0~15","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"","display":"NF Name","filter":"0~64","name":"name","type":"string","value":"AMF"},{"access":"read-write","comment":"","display":"AMF URI","filter":"0~64","name":"uri","type":"string","value":"http://172.16.5.130:8080"},{"access":"read-write","comment":"","display":"PLMN ID","filter":"^[0-9]{5,6}$","name":"plmnId","type":"regex","value":"00101"},{"access":"read-write","comment":"0~16777215","display":"TAC","filter":"0~8","name":"tac","type":"string","value":"1"}]', 3, '', 1724327154499, 'public'); -INSERT INTO "ne_config" VALUES (242, 'CBC', 'mmeProfile', 'MME Profile', 'array', '[{"access":"read-only","comment":"0~15","display":"Index","filter":"0~15","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"","display":"NF Name","filter":"0~64","name":"name","type":"string","value":"MME"},{"access":"read-write","comment":"","display":"MME URI","filter":"0~64","name":"uri","type":"string","value":"sctp://192.168.1.1:9090"},{"access":"read-write","comment":"","display":"PLMN ID","filter":"^[0-9]{5,6}$","name":"plmnId","type":"regex","value":"00101"},{"access":"read-write","comment":"0~16777215","display":"TAC","filter":"0~8","name":"tac","type":"string","value":"1"}]', 5, '', 1724327154504, 'public'); +-- 更新 CBC 配置 20250715 +INSERT INTO "ne_config" VALUES (240, 'CBC', 'system', 'System Config', 'list', '[{"access":"read-write","comment":"","display":"CBC Name","filter":"0~64","name":"name","type":"string","value":"CBC"},{"access":"read-write","comment":"","display":"SBI Server IP","filter":"0~64","name":"sbiIp","type":"string","value":"127.0.0.1"},{"access":"read-write","comment":"0~65535","display":"SBI Server Port","filter":"0~65535","name":"sbiPort","type":"int","value":"9090"},{"access":"read-write","comment":"","display":"SBI Scheme","filter":"{\"0\":\"http\",\"1\":\"https\"}","name":"sbiScheme","type":"enum","value":"0"},{"access":"read-write","comment":"0~65535","display":"SBI Timeout","filter":"0~65535","name":"sbiTimeout","type":"int","value":"3"}]', 1, '', 1752577098470, 'public'); +INSERT INTO "ne_config" VALUES (241, 'CBC', 'amfProfile', 'AMF Profile', 'array', '[{"access":"read-only","comment":"0~15","display":"Index","filter":"0~15","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"apply the current AMF NF Profile","display":"Enable AMF","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enabled","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"NF Name","filter":"0~64","name":"name","type":"string","value":"AMF"},{"access":"read-write","comment":"format: http://\u003cIP\u003e:\u003cPORT\u003e e.g: http://192.168.1.1:9090","display":"AMF URI","filter":"0~64","name":"uri","type":"string","value":"http://172.16.5.130:8080"},{"access":"read-write","array":[{"access":"read-only","comment":"1~32","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"MCC","filter":"^\\d{3,3}$","name":"mcc","type":"regex","value":"460"},{"access":"read-write","comment":"","display":"MNC","filter":"^\\d{2,3}$","name":"mnc","type":"regex","value":"00"},{"access":"read-write","comment":"(A).format is decimal string,e.g:43888 (B).Allow set multiple tac value by ; split, e:4388;4360 ","display":"TAC","filter":"^(\\d+(;\\d+)*)?$","name":"tac","type":"regex","value":"4388"}],"comment":"allow TaiList null or add more tai value","display":"Tai List","filter":"","name":"taiList","type":"regex","value":""}]', 3, '', 1752577099153, 'public'); +INSERT INTO "ne_config" VALUES (242, 'CBC', 'mmeProfile', 'MME Profile', 'array', '[{"access":"read-only","comment":"0~15","display":"Index","filter":"0~15","name":"index","type":"int","value":"0"},{"access":"read-write","comment":"apply the current MME NF Profile","display":"Enable MME","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enabled","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"NF Name","filter":"0~64","name":"name","type":"string","value":"MME"},{"access":"read-write","comment":"format: sctp://\u003cIP\u003e:\u003cPORT\u003e e.g: sctp://192.168.1.1:9090","display":"MME URI","filter":"0~64","name":"uri","type":"string","value":"sctp://192.168.1.1:9090"},{"access":"read-write","array":[{"access":"read-only","comment":"1~32","display":"Index","filter":"1~32","name":"index","type":"int","value":"1"},{"access":"read-write","comment":"","display":"MCC","filter":"^\\d{3,3}$","name":"mcc","type":"regex","value":"460"},{"access":"read-write","comment":"","display":"MNC","filter":"^\\d{2,3}$","name":"mnc","type":"regex","value":"00"},{"access":"read-write","comment":"(A).format is decimal string,e.g:43888 (B).Allow set multiple tac value by ; split, e:4388;4360 ","display":"TAC","filter":"^(\\d+(;\\d+)*)?$","name":"tac","type":"regex","value":"4388"}],"comment":"allow TaiList null or add more tai value","display":"Tai List","filter":"","name":"taiList","type":"regex","value":""}]', 5, '', 1752577099228, 'public'); --- 更新 OMC 配置 2025627 -INSERT INTO "ne_config" VALUES (260, 'OMC', 'alarmEmailForward', 'Alarm Email Forward Interface', 'list', '[{"access":"rw","comment":"Is it enabled forward alarm with Email interface","display":"Enable","filter":"true;false","name":"enable","type":"bool","value":"true"},{"access":"rw","comment":"string, no variable support","display":"Email Title","filter":"","name":"title","type":"string","value":""},{"access":"rw","comment":"","display":"Email List","filter":"","name":"emailList","type":"string","value":""},{"access":"rw","comment":"Email SMTP server","display":"SMTP Server","filter":"","name":"smtp","type":"string","value":""},{"access":"rw","comment":"","display":"Port","filter":"0~65535","name":"port","type":"int","value":""},{"access":"rw","comment":"","display":"User","filter":"","name":"user","type":"string","value":""},{"access":"rw","comment":"","display":"Password","filter":"","name":"password","type":"string","value":""},{"access":"rw","comment":"If skip TLS verify (true/false)","display":"TLS Skip Verify","filter":"true;false","name":"tlsSkipVerify","type":"bool","value":"true"}]', 3, '', 1751013716061, 'public'); -INSERT INTO "ne_config" VALUES (261, 'OMC', 'alarmSMSForward', 'Alarm SMS Forward Interface', 'list', '[{"access":"rw","comment":"Is it enabled forward alarm with SMS interface","display":"Enable","filter":"true;false","name":"enable","type":"bool","value":"true"},{"access":"rw","comment":"Multiple mobile separated by commas","display":"Mobile List","filter":"","name":"mobileList","type":"string","value":""},{"access":"rw","comment":"The SMSC SMPP Address","display":"SMSC Address","filter":"","name":"smscAddr","type":"string","value":""},{"access":"rw","comment":"","display":"System ID","filter":"","name":"systemID","type":"string","value":""},{"access":"rw","comment":"","display":"Password","filter":"","name":"password","type":"string","value":""},{"access":"rw","comment":"","display":"System Type","filter":"","name":"systemType","type":"string","value":""},{"access":"rw","comment":"Short message coding type","display":"Data Coding","filter":"{\"0\":\"GSM7BIT\",\"1\":\"ASCII\",\"2\":\"BINARY8BIT1\",\"3\":\"LATIN1\",\"4\":\"BINARY8BIT2\",\"6\":\"CYRILLIC\",\"7\":\"HEBREW\",\"8\":\"UCS2\"}","name":"dataCoding","type":"enum","value":"GSM7BIT"},{"access":"rw","comment":"It is the source address, the length is between 3 and 20","display":"Service Number","filter":"3~20","name":"serviceNumber","type":"string","value":"OMC"}]', 4, '', 1750993234232, 'public'); -INSERT INTO "ne_config" VALUES (262, 'OMC', 'trace', 'NE Signaling Trace', 'list', '[{"access":"read-write","comment":"enable or disable NE signaling trace creation","display":"Enable","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enabled","type":"bool","value":"false"},{"access":"read-write","comment":"NE signaling trace host address","display":"Host","filter":"0~128","name":"host","type":"ipv4","value":"172.16.5.100"},{"access":"read-write","comment":"NE signaling trace port","display":"Port","filter":"3000~65530","name":"port","type":"int","value":"33033"}]', 1, '', 1750993234209, 'public'); +-- 更新 OMC 配置 20250715 +INSERT INTO "ne_config" VALUES (260, 'OMC', 'trace', 'NE Signaling Trace', 'list', '[{"access":"read-write","comment":"enable or disable NE signaling trace creation","display":"Enable","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enabled","type":"bool","value":"false"},{"access":"read-write","comment":"NE signaling trace host address","display":"Host","filter":"0~128","name":"host","type":"ipv4","value":"172.16.5.100"},{"access":"read-write","comment":"NE signaling trace port","display":"Port","filter":"3000~65530","name":"port","type":"int","value":"33033"}]', 1, '', 1752576919477, 'public'); +INSERT INTO "ne_config" VALUES (261, 'OMC', 'notificationEmail', 'Alarm Email Forward Interface', 'list', '[{"access":"rw","comment":"Is it enabled forward alarm with Email interface","display":"Enable","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"enable","type":"bool","value":"true"},{"access":"rw","comment":"","display":"Email List","filter":"","name":"list","type":"string","value":""},{"access":"rw","comment":"string, no variable support","display":"Email Title","filter":"","name":"title","type":"string","value":""},{"access":"rw","comment":"Email SMTP server","display":"SMTP Server","filter":"","name":"smtp","type":"string","value":""},{"access":"rw","comment":"","display":"Port","filter":"0~65535","name":"port","type":"int","value":""},{"access":"rw","comment":"","display":"User","filter":"","name":"user","type":"string","value":""},{"access":"rw","comment":"","display":"Password","filter":"","name":"password","type":"string","value":""}]', 3, '', 1752576919810, 'public'); +INSERT INTO "ne_config" VALUES (262, 'OMC', 'notificationSMSC', 'Alarm SMS Forward Interface', 'list', '[{"access":"rw","comment":"Is it enabled forward alarm with SMS interface","display":"Enable","filter":"true;false","name":"enable","type":"bool","value":"true"},{"access":"rw","comment":"Multiple mobile separated by commas","display":"Mobile List","filter":"","name":"list","type":"string","value":""},{"access":"rw","comment":"The SMSC SMPP Address","display":"SMSC Address","filter":"","name":"addr","type":"string","value":""},{"access":"rw","comment":"","display":"System ID","filter":"","name":"systemid","type":"string","value":""},{"access":"rw","comment":"","display":"System Type","filter":"","name":"systemtype","type":"string","value":""},{"access":"rw","comment":"","display":"Password","filter":"","name":"password","type":"string","value":""},{"access":"rw","comment":"Short message coding type","display":"Data Coding","filter":"{\"0\":\"GSM7BIT\",\"1\":\"ASCII\",\"2\":\"BINARY8BIT1\",\"3\":\"LATIN1\",\"4\":\"BINARY8BIT2\",\"6\":\"CYRILLIC\",\"7\":\"HEBREW\",\"8\":\"UCS2\"}","name":"coding","type":"enum","value":"GSM7BIT"},{"access":"rw","comment":"It is the source address, the length is between 3 and 20","display":"Service Number","filter":"3~20","name":"servicenumber","type":"string","value":"OMC"}]', 4, '', 1752576919817, 'public'); -- 更新 SMSC 配置 2025521 INSERT INTO "ne_config" VALUES (280, 'SMSC', 'system', 'System', 'list', '[{"access":"read-write","comment":"","display":"CDR Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"cdrFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"SM Validity","filter":"0-2147483647","name":"smValidity","type":"int","value":"259200"},{"access":"read-write","comment":"","display":"Log Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"logFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to unattainable local users.","display":"Local Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"localPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to unattainable outbound roaming users.","display":"Local Roaming Out Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"localRoamingOutPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to unattainable inbound roaming users.","display":"Visitor Roaming In Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"visitorRoamingInPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable resend pending SMS to other unattainable users.","display":"Other Polling Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"otherPollingFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Define the maximum port number that the queue of pending SMS may grow to.","display":"Polling Number","filter":"0-64","name":"pollingNumber","type":"int","value":"64"},{"access":"read-write","comment":"Specify the priority parameter of SM_RP_PRI. true = High; false = Low.","display":"Priority Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"priorityFlag","type":"bool","value":"1"},{"access":"read-write","comment":"Enable or disable TP-Reply-Path parameter in the SMS-DELIVER data unit.","display":"TP Reply Path Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"tpReplyPathFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"SMSC Number","filter":"0~32","name":"smscNumber","type":"string","value":"0"},{"access":"read-write","comment":"","display":"SMSC Domain","filter":"0~16","name":"smscDomain","type":"string","value":"0.0.0.0"},{"access":"read-write","comment":"","display":"CSFB VoLTE Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"csfbVolteFlag","type":"bool","value":"1"},{"access":"read-write","comment":"","display":"Camel Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"camelFlag","type":"bool","value":"0"},{"access":"read-write","comment":"","display":"SCF Address","filter":"0~16","name":"scfAddress","type":"string","value":"0.0.0.0"},{"access":"read-write","comment":"If add plus then set false","display":"MT Id Format Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"mtIdFormatFlag","type":"bool","value":"0"},{"access":"read-write","comment":"enable mcast sms","display":"Mcast Flag","filter":"{\"0\":\"false\",\"1\":\"true\"}","name":"mcastFlag","type":"bool","value":"0"},{"access":"read-write","comment":"","display":"Log Level","filter":"{\"0\":\"none\",\"1\":\"error\",\"2\":\"debug\"}","name":"logLevel","type":"enum","value":"0"},{"access":"read-write","comment":"The MB sizeof log file","display":"Log Size","filter":"1-1000","name":"logSize","type":"int","value":"200"},{"access":"read-write","comment":"The number of log file","display":"Log Number","filter":"1-20","name":"logNum","type":"int","value":"10"},{"access":"read-write","comment":"","display":"Log Directory","filter":"0~128","name":"logDir","type":"string","value":"/var/log/"}]', 1, '', 1751438862010, 'public'); diff --git a/build/database/std/common/ne_config.sql b/build/database/std/common/ne_config.sql index 073d1845..d4d6f635 100644 --- a/build/database/std/common/ne_config.sql +++ b/build/database/std/common/ne_config.sql @@ -97,22 +97,22 @@ INSERT INTO `ne_config` VALUES (190, 'SMF', 'localDhcpCfg', 'Local DHCP Config', INSERT INTO `ne_config` VALUES (191, 'SMF', 'dnnselectdhcpserver', 'DNN Select DHCP Server', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"0~65535\",\"name\":\"index\",\"type\":\"int\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"1~64\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"e.g. 192.168.1.1\",\"display\":\"DHCP Server IP\",\"filter\":\"\",\"name\":\"dhcpServerAddr\",\"type\":\"string\",\"value\":\"\"}]', 23, '', 1751019165587, 'public'); INSERT INTO `ne_config` VALUES (192, 'SMF', 'offlineChargingConfig', 'Offline Charging Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR File Name\",\"filter\":\"1~64\",\"name\":\"cdrFileName\",\"type\":\"string\",\"value\":\"smf.cdr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR File Path\",\"filter\":\"1~256\",\"name\":\"cdrFilePath\",\"type\":\"string\",\"value\":\"/var/log/smfCdr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR File Num\",\"filter\":\"1~999999999\",\"name\":\"cdrFileNum\",\"type\":\"int\",\"value\":\"50\"},{\"access\":\"read-write\",\"comment\":\"Megabytes\",\"display\":\"CDR File Size\",\"filter\":\"1~999999\",\"name\":\"cdrFileSize\",\"type\":\"int\",\"value\":\"300\"},{\"access\":\"read-write\",\"comment\":\"Days\",\"display\":\"CDR File Max Age\",\"filter\":\"0~9999\",\"name\":\"cdrFileMaxAge\",\"type\":\"int\",\"value\":\"30\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Free Subscribers CDR Enable\",\"filter\":\"\",\"name\":\"freeSubsCdrEnable\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"Seconds\",\"display\":\"Time Threshold\",\"filter\":\"0~999999999\",\"name\":\"timeThreshold\",\"type\":\"int\",\"value\":\"600\"},{\"access\":\"read-write\",\"comment\":\"Bytes\",\"display\":\"Volume Threshold\",\"filter\":\"0~999999999999999\",\"name\":\"volumeThreshold\",\"type\":\"int\",\"value\":\"0\"}]', 25, '', 1751019165593, 'public'); --- 更新 UDM 配置 20250613 -INSERT INTO `ne_config` VALUES (200, 'UDM', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service IP\",\"filter\":\"\",\"name\":\"serviceIP\",\"type\":\"ipv4\",\"value\":\"172.16.5.140\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Port\",\"filter\":\"0~65535\",\"name\":\"servicePort\",\"type\":\"int\",\"value\":\"8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NRF URI\",\"filter\":\"\",\"name\":\"nrfUri\",\"type\":\"string\",\"value\":\"http://172.16.5.180:8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"FQDN\",\"filter\":\"\",\"name\":\"fqdn\",\"type\":\"string\",\"value\":\"omc.com\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"0~4095\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Capacity\",\"filter\":\"0~65535\",\"name\":\"capacity\",\"type\":\"int\",\"value\":\"4096\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group ID\",\"filter\":\"\",\"name\":\"groupId\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn1\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn1\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn2\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn2\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn3\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn3\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn4\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn4\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SUPI Ranges\",\"filter\":\"^imsi-\\\\d{15}~imsi-\\\\d{15}$\",\"name\":\"supiRanges\",\"type\":\"regex\",\"value\":\"imsi-001010100080000~imsi-001010100080099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"GPSI Ranges\",\"filter\":\"^msisdn-\\\\d{2,15}~msisdn-\\\\d{2,15}$\",\"name\":\"gpsiRanges\",\"type\":\"regex\",\"value\":\"msisdn-69072000~msisdn-69072099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"HTTP\\\", \\\"1\\\":\\\"HTTPS\\\"}\",\"name\":\"scheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Link\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"redisLink\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Address\",\"filter\":\"\",\"name\":\"redisAddr\",\"type\":\"string\",\"value\":\"172.16.5.140:6379\"}]', 1, '', 1751451940555, 'public'); -INSERT INTO `ne_config` VALUES (201, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"uplink\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"downlink\",\"type\":\"regex\",\"value\":\"2 Gbps\"}]', 5, '', 1751451940566, 'public'); -INSERT INTO `ne_config` VALUES (202, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Features\",\"filter\":\"^[0-9a-fA-F]{8}$\",\"name\":\"supportedFeatures\",\"type\":\"regex\",\"value\":\"00000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Single NSSAIs\",\"filter\":\"\",\"name\":\"defaultSingleNSSAIs\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Single NSSAIs\",\"filter\":\"\",\"name\":\"singleNssais\",\"type\":\"string\",\"value\":\"1-000002\"}]', 7, '', 1751451940570, 'public'); -INSERT INTO `ne_config` VALUES (203, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"}]', 9, '', 1751451940574, 'public'); -INSERT INTO `ne_config` VALUES (204, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Restriction Type\",\"filter\":\"{\\\"0\\\":\\\"Allowed Areas\\\", \\\"1\\\":\\\"Not Allowed Areas\\\"}\",\"name\":\"restrictionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max TAs\",\"filter\":\"^\\\\d{1,2}$\",\"name\":\"maxTAs\",\"type\":\"int\",\"value\":\"1\"}]', 11, '', 1751451940579, 'public'); -INSERT INTO `ne_config` VALUES (205, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SNSSAI\",\"filter\":\"^\\\\d{1,3}[A-Fa-f0-9]{6}$\",\"name\":\"snssai\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{1,32}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default DNN Indicator\",\"filter\":\"false;true;\",\"name\":\"defaultDnnInd\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LBO Roaming Allowed\",\"filter\":\"false;true;\",\"name\":\"lboRoamingAllowed\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"false;true;\",\"name\":\"iwkEpsInd\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"false;true;\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"false\"}],\"comment\":\"\",\"display\":\"DNN List\",\"filter\":\"1~4\",\"name\":\"dnnList\",\"type\":\"int\",\"value\":\"1\"}]', 13, '', 1751451940583, 'public'); -INSERT INTO `ne_config` VALUES (206, 'UDM', 'dnn', 'DNN Conf', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default PDU Session Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\"}\",\"name\":\"defaultPDUSessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed PDU Session Types\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\",\\\"5\\\":\\\"IPv4 \\u0026 IPv6\\\",\\\"6\\\":\\\"IPv4 \\u0026 IPv4v6\\\",\\\"7\\\":\\\"IPv6 \\u0026 IPv4v6\\\",\\\"8\\\":\\\"IPv4 \\u0026 IPv6 \\u0026 IPv4v6\\\"}\",\"name\":\"allowedPDUSessionTypes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"5QI\",\"filter\":\"0~255\",\"name\":\"5qi\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"1~127\",\"name\":\"priorityLevel\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default SSC Mode\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\"}\",\"name\":\"defaultSSCmode\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed SSC Modes\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\",\\\"3\\\":\\\"SSC Mode1 \\u0026 SSC Mode2\\\",\\\"4\\\":\\\"SSC Mode1 \\u0026 SSC Mode3\\\",\\\"5\\\":\\\"SSC Mode2 \\u0026 SSC Mode3\\\",\\\"6\\\":\\\"SSC Mode1 \\u0026 SSC Mode2 \\u0026 SSC Mode3\\\"}\",\"name\":\"allowedSSCmodes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"\",\"name\":\"interworkingEPSIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristics\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristics\",\"type\":\"string\",\"value\":\"0001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrUL\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrDL\",\"type\":\"regex\",\"value\":\"2 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Static IP Address\",\"filter\":\"\",\"name\":\"staticIPAddress\",\"type\":\"ipv4\",\"value\":\"192.168.1.100\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Integrity\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneIntegrity\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Confidentiality\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneConfidentiality\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority Level\",\"filter\":\"0~255\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"6\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"}]', 15, '', 1751451940587, 'public'); -INSERT INTO `ne_config` VALUES (207, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{0,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_eps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"APN OI Replacement\",\"filter\":\"^.{0,31}$\",\"name\":\"apnOIReplacement\",\"type\":\"string\",\"value\":\"money\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RFSP\",\"filter\":\"\",\"name\":\"rfsp\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RAU TAU Timer\",\"filter\":\"\",\"name\":\"rauTauTimer\",\"type\":\"int\",\"value\":\"120\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 17, '', 1751451940591, 'public'); -INSERT INTO `ne_config` VALUES (208, 'UDM', 'epsApn', 'EPS APN', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{0,127}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"IPv4 or IPv6\\\"}\",\"name\":\"pdnType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"QCI\",\"filter\":\"1~255\",\"name\":\"qci\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority\",\"filter\":\"1~127\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"8\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Context Identifier\",\"filter\":\"\",\"name\":\"contextIdentifier\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"VPLMN Dynamic Address Allowed\",\"filter\":\"false;true;\",\"name\":\"vplmnDynamicAddressAllowed\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN GW Allocation Type\",\"filter\":\"{\\\"0\\\":\\\"Static\\\",\\\"1\\\":\\\"Dynamic\\\"}\",\"name\":\"pdnGWAllocationType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 19, '', 1751451940594, 'public'); -INSERT INTO `ne_config` VALUES (209, 'UDM', 'applicationServer', 'Application Server', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AS Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Handling\",\"filter\":\"{\\\"0\\\":\\\"Session Continued\\\",\\\"1\\\":\\\"Session Terminated\\\"}\",\"name\":\"defaultHandling\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:192.168.8.26:7060\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Diameter Address\",\"filter\":\"^.{1,127}$\",\"name\":\"diameterAddress\",\"type\":\"string\",\"value\":\"mmtel.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Rep Data Size Limit\",\"filter\":\"0~65535\",\"name\":\"repDataSizeLimit\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Request\",\"filter\":\"false;true;\",\"name\":\"includeRegisterRequest\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Response\",\"filter\":\"false;true;\",\"name\":\"includeRegisterResponse\",\"type\":\"bool\",\"value\":\"false\"}]', 21, '', 1751451940597, 'public'); -INSERT INTO `ne_config` VALUES (210, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~8\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060\"}]', 23, '', 1751451940601, 'public'); -INSERT INTO `ne_config` VALUES (211, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Type CNF\",\"filter\":\"0~1\",\"name\":\"conditionTypeCNF\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Negated\",\"filter\":\"0~1\",\"name\":\"conditionNegated\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group\",\"filter\":\"0~4096\",\"name\":\"group\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Method\",\"filter\":\"^.{0,32}$\",\"name\":\"method\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Header\",\"filter\":\"^.{0,64}$\",\"name\":\"sipHeader\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Content\",\"filter\":\"^.{0,64}$\",\"name\":\"sipContent\",\"type\":\"string\",\"value\":\"\"}],\"comment\":\"\",\"display\":\"SPT List\",\"filter\":\"1~4\",\"name\":\"sptList\",\"type\":\"int\",\"value\":\"1\"}]', 25, '', 1751451940605, 'public'); -INSERT INTO `ne_config` VALUES (212, 'UDM', 's6aServer', 'S6a Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 27, '', 1751451940610, 'public'); -INSERT INTO `ne_config` VALUES (213, 'UDM', 'cxServer', 'Cx Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 29, '', 1751451940614, 'public'); -INSERT INTO `ne_config` VALUES (214, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EAP-Aka SupiOrImsi Prefix\",\"filter\":\"\",\"name\":\"eapAkaSupiImsiPrefix\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF FQDN\",\"filter\":\"0~128\",\"name\":\"ausfFqdn\",\"type\":\"string\",\"value\":\"ausf.5gc.com\"}]', 3, '', 1751451940561, 'public'); +-- 更新 UDM 配置 20250715 +INSERT INTO `ne_config` VALUES (200, 'UDM', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service IP\",\"filter\":\"\",\"name\":\"serviceIP\",\"type\":\"ipv4\",\"value\":\"172.16.5.140\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Service Port\",\"filter\":\"0~65535\",\"name\":\"servicePort\",\"type\":\"int\",\"value\":\"8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NRF URI\",\"filter\":\"\",\"name\":\"nrfUri\",\"type\":\"string\",\"value\":\"http://172.16.5.180:8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"FQDN\",\"filter\":\"\",\"name\":\"fqdn\",\"type\":\"string\",\"value\":\"omc.com\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"0~4095\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Capacity\",\"filter\":\"0~65535\",\"name\":\"capacity\",\"type\":\"int\",\"value\":\"4096\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group ID\",\"filter\":\"\",\"name\":\"groupId\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn1\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn1\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn2\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn2\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn3\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn3\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Plmn4\",\"filter\":\"^\\\\d{5,6}$\",\"name\":\"supportedPlmn4\",\"type\":\"string\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SUPI Ranges\",\"filter\":\"^imsi-\\\\d{15}~imsi-\\\\d{15}$\",\"name\":\"supiRanges\",\"type\":\"regex\",\"value\":\"imsi-001010100080000~imsi-001010100080099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"GPSI Ranges\",\"filter\":\"^msisdn-\\\\d{2,15}~msisdn-\\\\d{2,15}$\",\"name\":\"gpsiRanges\",\"type\":\"regex\",\"value\":\"msisdn-69072000~msisdn-69072099\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"HTTP\\\", \\\"1\\\":\\\"HTTPS\\\"}\",\"name\":\"scheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Link\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"redisLink\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Redis Address\",\"filter\":\"\",\"name\":\"redisAddr\",\"type\":\"string\",\"value\":\"172.16.5.140:6379\"}]', 1, '', 1752577177260, 'public'); +INSERT INTO `ne_config` VALUES (201, 'UDM', 'ausfCfg', 'AUSF Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EAP-Aka SupiOrImsi Prefix\",\"filter\":\"\",\"name\":\"eapAkaSupiImsiPrefix\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AUSF FQDN\",\"filter\":\"0~128\",\"name\":\"ausfFqdn\",\"type\":\"string\",\"value\":\"ausf.5gc.com\"}]', 3, '', 1752577177350, 'public'); +INSERT INTO `ne_config` VALUES (202, 'UDM', 'subsUEAmbr', 'Subs UE AMBR', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"uplink\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"downlink\",\"type\":\"regex\",\"value\":\"2 Gbps\"}]', 5, '', 1752577177371, 'public'); +INSERT INTO `ne_config` VALUES (203, 'UDM', 'subsNssais', 'Subs NSSAIs', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Supported Features\",\"filter\":\"^[0-9a-fA-F]{8}$\",\"name\":\"supportedFeatures\",\"type\":\"regex\",\"value\":\"00000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Single NSSAIs\",\"filter\":\"\",\"name\":\"defaultSingleNSSAIs\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Single NSSAIs\",\"filter\":\"\",\"name\":\"singleNssais\",\"type\":\"string\",\"value\":\"1-000002\"}]', 7, '', 1752577177376, 'public'); +INSERT INTO `ne_config` VALUES (204, 'UDM', 'forbiddenAreas', 'Forbidden Areas', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_ambr\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"}]', 9, '', 1752577177380, 'public'); +INSERT INTO `ne_config` VALUES (205, 'UDM', 'serviceAreaRestriction', 'Service Area Restriction', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"lab_sar\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Restriction Type\",\"filter\":\"{\\\"0\\\":\\\"Allowed Areas\\\", \\\"1\\\":\\\"Not Allowed Areas\\\"}\",\"name\":\"restrictionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"TACs\",\"filter\":\"\",\"name\":\"tacs\",\"type\":\"string\",\"value\":\"123\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Area Codes\",\"filter\":\"\",\"name\":\"areaCodes\",\"type\":\"string\",\"value\":\"123456\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max TAs\",\"filter\":\"^\\\\d{1,2}$\",\"name\":\"maxTAs\",\"type\":\"int\",\"value\":\"1\"}]', 11, '', 1752577177385, 'public'); +INSERT INTO `ne_config` VALUES (206, 'UDM', 'smfSelection', 'Subs SMF Selection', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SNSSAI\",\"filter\":\"^\\\\d{1,3}[A-Fa-f0-9]{6}$\",\"name\":\"snssai\",\"type\":\"string\",\"value\":\"1-000001\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{1,32}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default DNN Indicator\",\"filter\":\"false;true;\",\"name\":\"defaultDnnInd\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LBO Roaming Allowed\",\"filter\":\"false;true;\",\"name\":\"lboRoamingAllowed\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"false;true;\",\"name\":\"iwkEpsInd\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"false;true;\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"false\"}],\"comment\":\"\",\"display\":\"DNN List\",\"filter\":\"1~4\",\"name\":\"dnnList\",\"type\":\"int\",\"value\":\"1\"}]', 13, '', 1752577177391, 'public'); +INSERT INTO `ne_config` VALUES (207, 'UDM', 'dnn', 'DNN Conf', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_nssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default PDU Session Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\"}\",\"name\":\"defaultPDUSessionType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed PDU Session Types\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"Ethernet\\\",\\\"4\\\":\\\"Unstruction\\\",\\\"5\\\":\\\"IPv4 \\u0026 IPv6\\\",\\\"6\\\":\\\"IPv4 \\u0026 IPv4v6\\\",\\\"7\\\":\\\"IPv6 \\u0026 IPv4v6\\\",\\\"8\\\":\\\"IPv4 \\u0026 IPv6 \\u0026 IPv4v6\\\"}\",\"name\":\"allowedPDUSessionTypes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"5QI\",\"filter\":\"0~255\",\"name\":\"5qi\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"1~127\",\"name\":\"priorityLevel\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default SSC Mode\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\"}\",\"name\":\"defaultSSCmode\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Allowed SSC Modes\",\"filter\":\"{\\\"0\\\":\\\"SSC Mode1\\\",\\\"1\\\":\\\"SSC Mode2\\\",\\\"2\\\":\\\"SSC Mode3\\\",\\\"3\\\":\\\"SSC Mode1 \\u0026 SSC Mode2\\\",\\\"4\\\":\\\"SSC Mode1 \\u0026 SSC Mode3\\\",\\\"5\\\":\\\"SSC Mode2 \\u0026 SSC Mode3\\\",\\\"6\\\":\\\"SSC Mode1 \\u0026 SSC Mode2 \\u0026 SSC Mode3\\\"}\",\"name\":\"allowedSSCmodes\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Interworking EPS Indicator\",\"filter\":\"\",\"name\":\"interworkingEPSIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"LADN Indicator\",\"filter\":\"\",\"name\":\"ladnIndicator\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristics\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristics\",\"type\":\"string\",\"value\":\"0001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Uplink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrUL\",\"type\":\"regex\",\"value\":\"1 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Subscribed Session AMBR Downlink\",\"filter\":\"^\\\\d+(\\\\.\\\\d+)?( ?)(bps|Kbps|Mbps|Gbps|Tbps)$\",\"name\":\"subscribedSessionAmbrDL\",\"type\":\"regex\",\"value\":\"2 Gbps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Static IP Address\",\"filter\":\"\",\"name\":\"staticIPAddress\",\"type\":\"ipv4\",\"value\":\"192.168.1.100\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Integrity\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneIntegrity\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Plane Confidentiality\",\"filter\":\"{\\\"0\\\":\\\"Null\\\",\\\"1\\\":\\\"Required\\\",\\\"2\\\":\\\"Preferred\\\",\\\"3\\\":\\\"Not Needed\\\"}\",\"name\":\"userPlaneConfidentiality\",\"type\":\"enum\",\"value\":\"3\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority Level\",\"filter\":\"0~255\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"6\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preempt Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"}]', 15, '', 1752577177395, 'public'); +INSERT INTO `ne_config` VALUES (208, 'UDM', 'epsTemplate', 'EPS User Template', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{0,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_eps\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"APN OI Replacement\",\"filter\":\"^.{0,31}$\",\"name\":\"apnOIReplacement\",\"type\":\"string\",\"value\":\"money\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RFSP\",\"filter\":\"\",\"name\":\"rfsp\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RAU TAU Timer\",\"filter\":\"\",\"name\":\"rauTauTimer\",\"type\":\"int\",\"value\":\"120\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 17, '', 1752577177401, 'public'); +INSERT INTO `ne_config` VALUES (209, 'UDM', 'epsApn', 'EPS APN', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"^.{0,127}$\",\"name\":\"dnn\",\"type\":\"string\",\"value\":\"internet\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN Type\",\"filter\":\"{\\\"0\\\":\\\"IPv4\\\",\\\"1\\\":\\\"IPv6\\\",\\\"2\\\":\\\"IPv4v6\\\",\\\"3\\\":\\\"IPv4 or IPv6\\\"}\",\"name\":\"pdnType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"QCI\",\"filter\":\"1~255\",\"name\":\"qci\",\"type\":\"int\",\"value\":\"9\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Priority\",\"filter\":\"1~127\",\"name\":\"arpPriorityLevel\",\"type\":\"int\",\"value\":\"8\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Capability\",\"filter\":\"{\\\"0\\\":\\\"Not Preempt\\\",\\\"1\\\":\\\"May Preempt\\\"}\",\"name\":\"arpPreemptCap\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"ARP Preemption Vulnerability\",\"filter\":\"{\\\"0\\\":\\\"Not Preemptable\\\",\\\"1\\\":\\\"Preemptable\\\"}\",\"name\":\"arpPreemptVuln\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Context Identifier\",\"filter\":\"\",\"name\":\"contextIdentifier\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"VPLMN Dynamic Address Allowed\",\"filter\":\"false;true;\",\"name\":\"vplmnDynamicAddressAllowed\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PDN GW Allocation Type\",\"filter\":\"{\\\"0\\\":\\\"Static\\\",\\\"1\\\":\\\"Dynamic\\\"}\",\"name\":\"pdnGWAllocationType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Uplink\",\"filter\":\"0~4294967295\",\"name\":\"ambrUplink\",\"type\":\"int\",\"value\":\"100000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMBR Downlink\",\"filter\":\"0~4294967295\",\"name\":\"ambrDownlink\",\"type\":\"int\",\"value\":\"200000000\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Charging Characteristic\",\"filter\":\"4~4\",\"name\":\"chargingCharacteristic\",\"type\":\"string\",\"value\":\"0001\"}]', 19, '', 1752577177405, 'public'); +INSERT INTO `ne_config` VALUES (210, 'UDM', 'applicationServer', 'Application Server', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AS Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Default Handling\",\"filter\":\"{\\\"0\\\":\\\"Session Continued\\\",\\\"1\\\":\\\"Session Terminated\\\"}\",\"name\":\"defaultHandling\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:192.168.8.26:7060\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Diameter Address\",\"filter\":\"^.{1,127}$\",\"name\":\"diameterAddress\",\"type\":\"string\",\"value\":\"mmtel.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Rep Data Size Limit\",\"filter\":\"0~65535\",\"name\":\"repDataSizeLimit\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Request\",\"filter\":\"false;true;\",\"name\":\"includeRegisterRequest\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Include Register Response\",\"filter\":\"false;true;\",\"name\":\"includeRegisterResponse\",\"type\":\"bool\",\"value\":\"false\"}]', 21, '', 1752577177410, 'public'); +INSERT INTO `ne_config` VALUES (211, 'UDM', 'scscfSet', 'SCSCF Set', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~8\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,31}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"mmtel_as\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Priority\",\"filter\":\"\",\"name\":\"priority\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server Name\",\"filter\":\"^.{1,127}$\",\"name\":\"serverName\",\"type\":\"string\",\"value\":\"sip:scscf.ims.mnc001.mcc001.3gppnetwork.org:6060\"}]', 23, '', 1752577177415, 'public'); +INSERT INTO `ne_config` VALUES (212, 'UDM', 'triggerPoint', 'Trigger Point', 'array', '[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~16\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Name\",\"filter\":\"^.{1,32}$\",\"name\":\"name\",\"type\":\"string\",\"value\":\"def_snssai\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Type CNF\",\"filter\":\"0~1\",\"name\":\"conditionTypeCNF\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-only\",\"array\":[{\"access\":\"read-only\",\"comment\":\"\",\"display\":\"Index\",\"filter\":\"1~4\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Condition Negated\",\"filter\":\"0~1\",\"name\":\"conditionNegated\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Group\",\"filter\":\"0~4096\",\"name\":\"group\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Method\",\"filter\":\"^.{0,32}$\",\"name\":\"method\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Header\",\"filter\":\"^.{0,64}$\",\"name\":\"sipHeader\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SIP Content\",\"filter\":\"^.{0,64}$\",\"name\":\"sipContent\",\"type\":\"string\",\"value\":\"\"}],\"comment\":\"\",\"display\":\"SPT List\",\"filter\":\"1~4\",\"name\":\"sptList\",\"type\":\"int\",\"value\":\"1\"}]', 25, '', 1752577177419, 'public'); +INSERT INTO `ne_config` VALUES (213, 'UDM', 's6aServer', 'S6a Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 27, '', 1752577177423, 'public'); +INSERT INTO `ne_config` VALUES (214, 'UDM', 'cxServer', 'Cx Server', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enable\",\"filter\":\"false;true;\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Link Type\",\"filter\":\"{\\\"0\\\":\\\"TCP\\\",\\\"1\\\":\\\"SCTP\\\"}\",\"name\":\"netType\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"172.16.5.140:3868\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Host\",\"filter\":\"^.{1,127}$\",\"name\":\"host\",\"type\":\"string\",\"value\":\"hss.ims.mnc001.mcc001.3gppnetwork.org\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Realm\",\"filter\":\"^.{1,127}$\",\"name\":\"realm\",\"type\":\"string\",\"value\":\"ims.mnc001.mcc001.3gppnetwork.org\"}]', 29, '', 1752577177427, 'public'); -- 更新 UPF 配置 20250320 INSERT INTO `ne_config` VALUES (220, 'UPF', 'general', 'General', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Config File Directory\",\"filter\":\"\",\"name\":\"configFileDirectory\",\"type\":\"string\",\"value\":\"/usr/local/etc/upf/\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"EXE File Directory\",\"filter\":\"\",\"name\":\"exeFileDirectory\",\"type\":\"string\",\"value\":\"/usr/local/bin/\"},{\"access\":\"read-write\",\"comment\":\"1~255\",\"display\":\"System ID\",\"filter\":\"\",\"name\":\"systemId\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"1~8\",\"display\":\"Data Forwarder Number\",\"filter\":\"1~8\",\"name\":\"dataForwarderNum\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Common Statistic Interval\",\"filter\":\"\",\"name\":\"commonStatisticInterval\",\"type\":\"int\",\"value\":\"60\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"User Statistic Interval\",\"filter\":\"\",\"name\":\"userStatisticInterval\",\"type\":\"int\",\"value\":\"60\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RX N3 OverLoad Threshold Mbps\",\"filter\":\"\",\"name\":\"rxN3OverLoadThresholdMbps\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"RX N6 OverLoad Threshold Mbps\",\"filter\":\"\",\"name\":\"rxN6OverLoadThresholdMbps\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"0~255\",\"display\":\"Checksum Offload\",\"filter\":\"0~255\",\"name\":\"checksumOffload\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Max Downlink Buffer Num\",\"filter\":\"\",\"name\":\"maxDownlinkBufferNum\",\"type\":\"int\",\"value\":\"50\"}]', 1, '', 1742469466451, 'public'); @@ -134,15 +134,15 @@ INSERT INTO `ne_config` VALUES (235, 'UPF', 'dpiHeaderEnrichInfoList', 'DPI Head INSERT INTO `ne_config` VALUES (236, 'UPF', 'dpiAppList', 'DPI APP List', 'array', '[{\"access\":\"read-write\",\"comment\":\"1~32\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"APP Name\",\"filter\":\"\",\"name\":\"appName\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Proxy Enabled\",\"filter\":\"0~1\",\"name\":\"proxyEnabled\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Force Check Type\",\"filter\":\"0~1\",\"name\":\"forceCheckType\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"N3 Interface ID\",\"filter\":\"0~32\",\"name\":\"n3InterfaceId\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"N6 Interface ID\",\"filter\":\"0~32\",\"name\":\"n6InterfaceId\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"array\":[{\"access\":\"read-only\",\"comment\":\"1~32\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Rule ID\",\"filter\":\"\",\"name\":\"ruleId\",\"type\":\"int\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"REGEX Match\",\"filter\":\"\",\"name\":\"regexMatch\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Flow Description\",\"filter\":\"\",\"name\":\"flowDescription\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Custom Name\",\"filter\":\"\",\"name\":\"customName\",\"type\":\"string\",\"value\":\"\"}],\"comment\":\"\",\"display\":\"Rule List\",\"filter\":\"0~32\",\"name\":\"ruleList\",\"type\":\"int\",\"value\":\"1\"}]', 35, '', 1742469466580, 'public'); INSERT INTO `ne_config` VALUES (237, 'UPF', 'networkControlFreeServerList', 'Free Server List', 'array', '[{\"access\":\"read-write\",\"comment\":\"1~32\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Enabled\",\"filter\":\"0~1\",\"name\":\"enabled\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"array\":[{\"access\":\"read-only\",\"comment\":\"1~32\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server IPv4\",\"filter\":\"\",\"name\":\"serverIpv4\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server IPv4 Mask\",\"filter\":\"\",\"name\":\"serverIpv4Mask\",\"type\":\"string\",\"value\":\"255.255.255.0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server IPv6\",\"filter\":\"\",\"name\":\"serverIpv6\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Server IPv6 Prefix\",\"filter\":\"\",\"name\":\"serverIpv6Prefix\",\"type\":\"int\",\"value\":\"64\"}],\"comment\":\"\",\"display\":\"Free Server Address List\",\"filter\":\"0~32\",\"name\":\"freeServerAddrList\",\"type\":\"int\",\"value\":\"1\"}]', 27, '', 1742469466563, 'public'); --- 更新 CBC 配置 20240823 -INSERT INTO `ne_config` VALUES (240, 'CBC', 'system', 'System Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CBC Name\",\"filter\":\"0~64\",\"name\":\"name\",\"type\":\"string\",\"value\":\"CBC\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NF Instance\",\"filter\":\"0~64\",\"name\":\"instance\",\"type\":\"string\",\"value\":\"CBC-001\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SBI Server IP\",\"filter\":\"0~64\",\"name\":\"sbiIp\",\"type\":\"string\",\"value\":\"127.0.0.1\"},{\"access\":\"read-write\",\"comment\":\"0~65535\",\"display\":\"SBI Server Port\",\"filter\":\"0~65535\",\"name\":\"sbiPort\",\"type\":\"int\",\"value\":\"9090\"},{\"access\":\"read-write\",\"comment\":\"http or https\",\"display\":\"SBI Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\",\\\"1\\\":\\\"https\\\"}\",\"name\":\"sbiScheme\",\"type\":\"enum\",\"value\":\"0\"}]', 1, '', 1724327154483, 'public'); -INSERT INTO `ne_config` VALUES (241, 'CBC', 'amfProfile', 'AMF Profile', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NF Name\",\"filter\":\"0~64\",\"name\":\"name\",\"type\":\"string\",\"value\":\"AMF\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"AMF URI\",\"filter\":\"0~64\",\"name\":\"uri\",\"type\":\"string\",\"value\":\"http://172.16.5.130:8080\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PLMN ID\",\"filter\":\"^[0-9]{5,6}$\",\"name\":\"plmnId\",\"type\":\"regex\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"0~16777215\",\"display\":\"TAC\",\"filter\":\"0~8\",\"name\":\"tac\",\"type\":\"string\",\"value\":\"1\"}]', 3, '', 1724327154499, 'public'); -INSERT INTO `ne_config` VALUES (242, 'CBC', 'mmeProfile', 'MME Profile', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NF Name\",\"filter\":\"0~64\",\"name\":\"name\",\"type\":\"string\",\"value\":\"MME\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"MME URI\",\"filter\":\"0~64\",\"name\":\"uri\",\"type\":\"string\",\"value\":\"sctp://192.168.1.1:9090\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"PLMN ID\",\"filter\":\"^[0-9]{5,6}$\",\"name\":\"plmnId\",\"type\":\"regex\",\"value\":\"00101\"},{\"access\":\"read-write\",\"comment\":\"0~16777215\",\"display\":\"TAC\",\"filter\":\"0~8\",\"name\":\"tac\",\"type\":\"string\",\"value\":\"1\"}]', 5, '', 1724327154504, 'public'); +-- 更新 CBC 配置 20250715 +INSERT INTO `ne_config` VALUES (240, 'CBC', 'system', 'System Config', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CBC Name\",\"filter\":\"0~64\",\"name\":\"name\",\"type\":\"string\",\"value\":\"CBC\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SBI Server IP\",\"filter\":\"0~64\",\"name\":\"sbiIp\",\"type\":\"string\",\"value\":\"127.0.0.1\"},{\"access\":\"read-write\",\"comment\":\"0~65535\",\"display\":\"SBI Server Port\",\"filter\":\"0~65535\",\"name\":\"sbiPort\",\"type\":\"int\",\"value\":\"9090\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SBI Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\",\\\"1\\\":\\\"https\\\"}\",\"name\":\"sbiScheme\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"0~65535\",\"display\":\"SBI Timeout\",\"filter\":\"0~65535\",\"name\":\"sbiTimeout\",\"type\":\"int\",\"value\":\"3\"}]', 1, '', 1752577098470, 'public'); +INSERT INTO `ne_config` VALUES (241, 'CBC', 'amfProfile', 'AMF Profile', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"apply the current AMF NF Profile\",\"display\":\"Enable AMF\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enabled\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NF Name\",\"filter\":\"0~64\",\"name\":\"name\",\"type\":\"string\",\"value\":\"AMF\"},{\"access\":\"read-write\",\"comment\":\"format: http://\\u003cIP\\u003e:\\u003cPORT\\u003e e.g: http://192.168.1.1:9090\",\"display\":\"AMF URI\",\"filter\":\"0~64\",\"name\":\"uri\",\"type\":\"string\",\"value\":\"http://172.16.5.130:8080\"},{\"access\":\"read-write\",\"array\":[{\"access\":\"read-only\",\"comment\":\"1~32\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"MCC\",\"filter\":\"^\\\\d{3,3}$\",\"name\":\"mcc\",\"type\":\"regex\",\"value\":\"460\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"MNC\",\"filter\":\"^\\\\d{2,3}$\",\"name\":\"mnc\",\"type\":\"regex\",\"value\":\"00\"},{\"access\":\"read-write\",\"comment\":\"(A).format is decimal string,e.g:43888 (B).Allow set multiple tac value by ; split, e:4388;4360 \",\"display\":\"TAC\",\"filter\":\"^(\\\\d+(;\\\\d+)*)?$\",\"name\":\"tac\",\"type\":\"regex\",\"value\":\"4388\"}],\"comment\":\"allow TaiList null or add more tai value\",\"display\":\"Tai List\",\"filter\":\"\",\"name\":\"taiList\",\"type\":\"regex\",\"value\":\"\"}]', 3, '', 1752577099153, 'public'); +INSERT INTO `ne_config` VALUES (242, 'CBC', 'mmeProfile', 'MME Profile', 'array', '[{\"access\":\"read-only\",\"comment\":\"0~15\",\"display\":\"Index\",\"filter\":\"0~15\",\"name\":\"index\",\"type\":\"int\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"apply the current MME NF Profile\",\"display\":\"Enable MME\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enabled\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"NF Name\",\"filter\":\"0~64\",\"name\":\"name\",\"type\":\"string\",\"value\":\"MME\"},{\"access\":\"read-write\",\"comment\":\"format: sctp://\\u003cIP\\u003e:\\u003cPORT\\u003e e.g: sctp://192.168.1.1:9090\",\"display\":\"MME URI\",\"filter\":\"0~64\",\"name\":\"uri\",\"type\":\"string\",\"value\":\"sctp://192.168.1.1:9090\"},{\"access\":\"read-write\",\"array\":[{\"access\":\"read-only\",\"comment\":\"1~32\",\"display\":\"Index\",\"filter\":\"1~32\",\"name\":\"index\",\"type\":\"int\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"MCC\",\"filter\":\"^\\\\d{3,3}$\",\"name\":\"mcc\",\"type\":\"regex\",\"value\":\"460\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"MNC\",\"filter\":\"^\\\\d{2,3}$\",\"name\":\"mnc\",\"type\":\"regex\",\"value\":\"00\"},{\"access\":\"read-write\",\"comment\":\"(A).format is decimal string,e.g:43888 (B).Allow set multiple tac value by ; split, e:4388;4360 \",\"display\":\"TAC\",\"filter\":\"^(\\\\d+(;\\\\d+)*)?$\",\"name\":\"tac\",\"type\":\"regex\",\"value\":\"4388\"}],\"comment\":\"allow TaiList null or add more tai value\",\"display\":\"Tai List\",\"filter\":\"\",\"name\":\"taiList\",\"type\":\"regex\",\"value\":\"\"}]', 5, '', 1752577099228, 'public'); --- 更新 OMC 配置 20250627 -INSERT INTO `ne_config` VALUES (260, 'OMC', 'alarmEmailForward', 'Alarm Email Forward Interface', 'list', '[{\"access\":\"rw\",\"comment\":\"Is it enabled forward alarm with Email interface\",\"display\":\"Enable\",\"filter\":\"true;false\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"rw\",\"comment\":\"string, no variable support\",\"display\":\"Email Title\",\"filter\":\"\",\"name\":\"title\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Email List\",\"filter\":\"\",\"name\":\"emailList\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"Email SMTP server\",\"display\":\"SMTP Server\",\"filter\":\"\",\"name\":\"smtp\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"type\":\"int\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"User\",\"filter\":\"\",\"name\":\"user\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"\",\"name\":\"password\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"If skip TLS verify (true/false)\",\"display\":\"TLS Skip Verify\",\"filter\":\"true;false\",\"name\":\"tlsSkipVerify\",\"type\":\"bool\",\"value\":\"true\"}]', 3, '', 1751013716061, 'public'); -INSERT INTO `ne_config` VALUES (261, 'OMC', 'alarmSMSForward', 'Alarm SMS Forward Interface', 'list', '[{\"access\":\"rw\",\"comment\":\"Is it enabled forward alarm with SMS interface\",\"display\":\"Enable\",\"filter\":\"true;false\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"rw\",\"comment\":\"Multiple mobile separated by commas\",\"display\":\"Mobile List\",\"filter\":\"\",\"name\":\"mobileList\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"The SMSC SMPP Address\",\"display\":\"SMSC Address\",\"filter\":\"\",\"name\":\"smscAddr\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"System ID\",\"filter\":\"\",\"name\":\"systemID\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"\",\"name\":\"password\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"System Type\",\"filter\":\"\",\"name\":\"systemType\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"Short message coding type\",\"display\":\"Data Coding\",\"filter\":\"{\\\"0\\\":\\\"GSM7BIT\\\",\\\"1\\\":\\\"ASCII\\\",\\\"2\\\":\\\"BINARY8BIT1\\\",\\\"3\\\":\\\"LATIN1\\\",\\\"4\\\":\\\"BINARY8BIT2\\\",\\\"6\\\":\\\"CYRILLIC\\\",\\\"7\\\":\\\"HEBREW\\\",\\\"8\\\":\\\"UCS2\\\"}\",\"name\":\"dataCoding\",\"type\":\"enum\",\"value\":\"GSM7BIT\"},{\"access\":\"rw\",\"comment\":\"It is the source address, the length is between 3 and 20\",\"display\":\"Service Number\",\"filter\":\"3~20\",\"name\":\"serviceNumber\",\"type\":\"string\",\"value\":\"OMC\"}]', 4, '', 1750993234232, 'public'); -INSERT INTO `ne_config` VALUES (262, 'OMC', 'trace', 'NE Signaling Trace', 'list', '[{\"access\":\"read-write\",\"comment\":\"enable or disable NE signaling trace creation\",\"display\":\"Enable\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enabled\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"NE signaling trace host address\",\"display\":\"Host\",\"filter\":\"0~128\",\"name\":\"host\",\"type\":\"ipv4\",\"value\":\"172.16.5.100\"},{\"access\":\"read-write\",\"comment\":\"NE signaling trace port\",\"display\":\"Port\",\"filter\":\"3000~65530\",\"name\":\"port\",\"type\":\"int\",\"value\":\"33033\"}]', 1, '', 1750993234209, 'public'); +-- 更新 OMC 配置 20250715 +INSERT INTO `ne_config` VALUES (260, 'OMC', 'trace', 'NE Signaling Trace', 'list', '[{\"access\":\"read-write\",\"comment\":\"enable or disable NE signaling trace creation\",\"display\":\"Enable\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enabled\",\"type\":\"bool\",\"value\":\"false\"},{\"access\":\"read-write\",\"comment\":\"NE signaling trace host address\",\"display\":\"Host\",\"filter\":\"0~128\",\"name\":\"host\",\"type\":\"ipv4\",\"value\":\"172.16.5.100\"},{\"access\":\"read-write\",\"comment\":\"NE signaling trace port\",\"display\":\"Port\",\"filter\":\"3000~65530\",\"name\":\"port\",\"type\":\"int\",\"value\":\"33033\"}]', 1, '', 1752576919477, 'public'); +INSERT INTO `ne_config` VALUES (261, 'OMC', 'notificationEmail', 'Alarm Email Forward Interface', 'list', '[{\"access\":\"rw\",\"comment\":\"Is it enabled forward alarm with Email interface\",\"display\":\"Enable\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Email List\",\"filter\":\"\",\"name\":\"list\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"string, no variable support\",\"display\":\"Email Title\",\"filter\":\"\",\"name\":\"title\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"Email SMTP server\",\"display\":\"SMTP Server\",\"filter\":\"\",\"name\":\"smtp\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"type\":\"int\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"User\",\"filter\":\"\",\"name\":\"user\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"\",\"name\":\"password\",\"type\":\"string\",\"value\":\"\"}]', 3, '', 1752576919810, 'public'); +INSERT INTO `ne_config` VALUES (262, 'OMC', 'notificationSMSC', 'Alarm SMS Forward Interface', 'list', '[{\"access\":\"rw\",\"comment\":\"Is it enabled forward alarm with SMS interface\",\"display\":\"Enable\",\"filter\":\"true;false\",\"name\":\"enable\",\"type\":\"bool\",\"value\":\"true\"},{\"access\":\"rw\",\"comment\":\"Multiple mobile separated by commas\",\"display\":\"Mobile List\",\"filter\":\"\",\"name\":\"list\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"The SMSC SMPP Address\",\"display\":\"SMSC Address\",\"filter\":\"\",\"name\":\"addr\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"System ID\",\"filter\":\"\",\"name\":\"systemid\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"System Type\",\"filter\":\"\",\"name\":\"systemtype\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"\",\"display\":\"Password\",\"filter\":\"\",\"name\":\"password\",\"type\":\"string\",\"value\":\"\"},{\"access\":\"rw\",\"comment\":\"Short message coding type\",\"display\":\"Data Coding\",\"filter\":\"{\\\"0\\\":\\\"GSM7BIT\\\",\\\"1\\\":\\\"ASCII\\\",\\\"2\\\":\\\"BINARY8BIT1\\\",\\\"3\\\":\\\"LATIN1\\\",\\\"4\\\":\\\"BINARY8BIT2\\\",\\\"6\\\":\\\"CYRILLIC\\\",\\\"7\\\":\\\"HEBREW\\\",\\\"8\\\":\\\"UCS2\\\"}\",\"name\":\"coding\",\"type\":\"enum\",\"value\":\"GSM7BIT\"},{\"access\":\"rw\",\"comment\":\"It is the source address, the length is between 3 and 20\",\"display\":\"Service Number\",\"filter\":\"3~20\",\"name\":\"servicenumber\",\"type\":\"string\",\"value\":\"OMC\"}]', 4, '', 1752576919817, 'public'); -- 更新 SMSC 配置 2025521 INSERT INTO `ne_config` VALUES (280, 'SMSC', 'system', 'System', 'list', '[{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CDR Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"cdrFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SM Validity\",\"filter\":\"0-2147483647\",\"name\":\"smValidity\",\"type\":\"int\",\"value\":\"259200\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"logFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable local users.\",\"display\":\"Local Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable outbound roaming users.\",\"display\":\"Local Roaming Out Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"localRoamingOutPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to unattainable inbound roaming users.\",\"display\":\"Visitor Roaming In Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"visitorRoamingInPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable resend pending SMS to other unattainable users.\",\"display\":\"Other Polling Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"otherPollingFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Define the maximum port number that the queue of pending SMS may grow to.\",\"display\":\"Polling Number\",\"filter\":\"0-64\",\"name\":\"pollingNumber\",\"type\":\"int\",\"value\":\"64\"},{\"access\":\"read-write\",\"comment\":\"Specify the priority parameter of SM_RP_PRI. true = High; false = Low.\",\"display\":\"Priority Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"priorityFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"Enable or disable TP-Reply-Path parameter in the SMS-DELIVER data unit.\",\"display\":\"TP Reply Path Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"tpReplyPathFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Number\",\"filter\":\"0~32\",\"name\":\"smscNumber\",\"type\":\"string\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SMSC Domain\",\"filter\":\"0~16\",\"name\":\"smscDomain\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"CSFB VoLTE Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"csfbVolteFlag\",\"type\":\"bool\",\"value\":\"1\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Camel Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"camelFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"SCF Address\",\"filter\":\"0~16\",\"name\":\"scfAddress\",\"type\":\"string\",\"value\":\"0.0.0.0\"},{\"access\":\"read-write\",\"comment\":\"If add plus then set false\",\"display\":\"MT Id Format Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mtIdFormatFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"enable mcast sms\",\"display\":\"Mcast Flag\",\"filter\":\"{\\\"0\\\":\\\"false\\\",\\\"1\\\":\\\"true\\\"}\",\"name\":\"mcastFlag\",\"type\":\"bool\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Level\",\"filter\":\"{\\\"0\\\":\\\"none\\\",\\\"1\\\":\\\"error\\\",\\\"2\\\":\\\"debug\\\"}\",\"name\":\"logLevel\",\"type\":\"enum\",\"value\":\"0\"},{\"access\":\"read-write\",\"comment\":\"The MB sizeof log file\",\"display\":\"Log Size\",\"filter\":\"1-1000\",\"name\":\"logSize\",\"type\":\"int\",\"value\":\"200\"},{\"access\":\"read-write\",\"comment\":\"The number of log file\",\"display\":\"Log Number\",\"filter\":\"1-20\",\"name\":\"logNum\",\"type\":\"int\",\"value\":\"10\"},{\"access\":\"read-write\",\"comment\":\"\",\"display\":\"Log Directory\",\"filter\":\"0~128\",\"name\":\"logDir\",\"type\":\"string\",\"value\":\"/var/log/\"}]', 1, '', 1751438862010, 'public'); diff --git a/local/param/cbc_param_config.yaml b/local/param/cbc_param_config.yaml index 4da1094c..3f201230 100644 --- a/local/param/cbc_param_config.yaml +++ b/local/param/cbc_param_config.yaml @@ -10,13 +10,6 @@ cbc: filter: "0~64" display: "CBC Name" comment: "" - - name: "instance" - type: "string" - value: "CBC-001" - access: "read-write" - filter: "0~64" - display: "NF Instance" - comment: "" - name: "sbiIp" type: "string" value: "127.0.0.1" @@ -37,7 +30,14 @@ cbc: access: "read-write" filter: '{"0":"http","1":"https"}' display: "SBI Scheme" - comment: "http or https" + comment: "" + - name: "sbiTimeout" + type: "int" + value: "3" + access: "read-write" + filter: "0~65535" + display: "SBI Timeout" + comment: "0~65535" amfProfile: display: "AMF Profile" @@ -50,6 +50,13 @@ cbc: filter: "0~15" display: "Index" comment: "0~15" + - name: "enabled" + type: "bool" + value: "1" + access: "read-write" + filter: '{"0":"false","1":"true"}' + display: "Enable AMF" + comment: "apply the current AMF NF Profile" - name: "name" type: "string" value: "AMF" @@ -63,21 +70,43 @@ cbc: access: "read-write" filter: "0~64" display: "AMF URI" - comment: "" - - name: "plmnId" + comment: "format: http://: e.g: http://192.168.1.1:9090" + - name: "taiList" type: "regex" - value: "00101" + value: "" access: "read-write" - filter: "^[0-9]{5,6}$" - display: "PLMN ID" - comment: "" - - name: "tac" - type: "string" - value: "1" - access: "read-write" - filter: "0~8" - display: "TAC" - comment: "0~16777215" + filter: "" + display: "Tai List" + comment: "allow TaiList null or add more tai value" + array: + - name: "index" + type: "int" + value: "1" + access: "read-only" + filter: "1~32" + display: "Index" + comment: "1~32" + - name: "mcc" + type: "regex" + value: "460" + access: "read-write" + filter: '^\d{3,3}$' + display: "MCC" + comment: "" + - name: "mnc" + type: "regex" + value: "00" + access: "read-write" + filter: '^\d{2,3}$' + display: "MNC" + comment: "" + - name: "tac" + type: "regex" + value: "4388" + access: "read-write" + filter: '^(\d+(;\d+)*)?$' + display: "TAC" + comment: "(A).format is decimal string,e.g:43888 (B).Allow set multiple tac value by ; split, e:4388;4360 " mmeProfile: display: "MME Profile" @@ -90,6 +119,13 @@ cbc: filter: "0~15" display: "Index" comment: "0~15" + - name: "enabled" + type: "bool" + value: "1" + access: "read-write" + filter: '{"0":"false","1":"true"}' + display: "Enable MME" + comment: "apply the current MME NF Profile" - name: "name" type: "string" value: "MME" @@ -103,18 +139,40 @@ cbc: access: "read-write" filter: "0~64" display: "MME URI" - comment: "" - - name: "plmnId" + comment: "format: sctp://: e.g: sctp://192.168.1.1:9090" + - name: "taiList" type: "regex" - value: "00101" + value: "" access: "read-write" - filter: "^[0-9]{5,6}$" - display: "PLMN ID" - comment: "" - - name: "tac" - type: "string" - value: "1" - access: "read-write" - filter: "0~8" - display: "TAC" - comment: "0~16777215" + filter: "" + display: "Tai List" + comment: "allow TaiList null or add more tai value" + array: + - name: "index" + type: "int" + value: "1" + access: "read-only" + filter: "1~32" + display: "Index" + comment: "1~32" + - name: "mcc" + type: "regex" + value: "460" + access: "read-write" + filter: '^\d{3,3}$' + display: "MCC" + comment: "" + - name: "mnc" + type: "regex" + value: "00" + access: "read-write" + filter: '^\d{2,3}$' + display: "MNC" + comment: "" + - name: "tac" + type: "regex" + value: "4388" + access: "read-write" + filter: '^(\d+(;\d+)*)?$' + display: "TAC" + comment: "(A).format is decimal string,e.g:43888 (B).Allow set multiple tac value by ; split, e:4388;4360 " diff --git a/local/param/omc_param_config.yaml b/local/param/omc_param_config.yaml index cce7a7ae..90fd952f 100644 --- a/local/param/omc_param_config.yaml +++ b/local/param/omc_param_config.yaml @@ -14,17 +14,17 @@ omc: type: "ipv4" value: "172.16.5.100" access: "read-write" - filter: '0~128' + filter: "0~128" display: "Host" comment: "NE signaling trace host address" - name: "port" type: "int" value: "33033" access: "read-write" - filter: '3000~65530' + filter: "3000~65530" display: "Port" comment: "NE signaling trace port" - alarmEmailForward: + notificationEmail: display: "Alarm Email Forward Interface" sort: 3 list: @@ -32,9 +32,16 @@ omc: type: "bool" value: "true" access: "rw" - filter: "true;false" + filter: '{"0":"false","1":"true"}' display: "Enable" comment: "Is it enabled forward alarm with Email interface" + - name: "list" + type: "string" + value: "" + access: "rw" + filter: "" + display: "Email List" + comment: "" - name: "title" type: "string" value: "" @@ -42,13 +49,6 @@ omc: filter: "" display: "Email Title" comment: "string, no variable support" - - name: "emailList" - type: "string" - value: "" - access: "rw" - filter: "" - display: "Email List" - comment: "" - name: "smtp" type: "string" value: "" @@ -77,14 +77,7 @@ omc: filter: "" display: "Password" comment: "" - - name: "tlsSkipVerify" - type: "bool" - value: "true" - access: "rw" - filter: "true;false" - display: "TLS Skip Verify" - comment: "If skip TLS verify (true/false)" - alarmSMSForward: + notificationSMSC: display: "Alarm SMS Forward Interface" sort: 4 list: @@ -95,27 +88,34 @@ omc: filter: "true;false" display: "Enable" comment: "Is it enabled forward alarm with SMS interface" - - name: "mobileList" + - name: "list" type: "string" value: "" access: "rw" filter: "" display: "Mobile List" comment: "Multiple mobile separated by commas" - - name: "smscAddr" + - name: "addr" type: "string" value: "" access: "rw" filter: "" display: "SMSC Address" comment: "The SMSC SMPP Address" - - name: "systemID" + - name: "systemid" type: "string" value: "" access: "rw" filter: "" display: "System ID" comment: "" + - name: "systemtype" + type: "string" + value: "" + access: "rw" + filter: "" + display: "System Type" + comment: "" - name: "password" type: "string" value: "" @@ -123,21 +123,14 @@ omc: filter: "" display: "Password" comment: "" - - name: "systemType" - type: "string" - value: "" - access: "rw" - filter: "" - display: "System Type" - comment: "" - - name: "dataCoding" + - name: "coding" type: "enum" value: "GSM7BIT" access: "rw" filter: '{"0":"GSM7BIT","1":"ASCII","2":"BINARY8BIT1","3":"LATIN1","4":"BINARY8BIT2","6":"CYRILLIC","7":"HEBREW","8":"UCS2"}' display: "Data Coding" comment: "Short message coding type" - - name: "serviceNumber" + - name: "servicenumber" type: "string" value: "OMC" access: "rw" diff --git a/local/param/udm_param_config.yaml b/local/param/udm_param_config.yaml index ecf1b9e8..fb6448cf 100644 --- a/local/param/udm_param_config.yaml +++ b/local/param/udm_param_config.yaml @@ -256,7 +256,7 @@ udm: comment: "" - name: "name" type: "string" - value: "def_ambr" + value: "lab_sar" access: "read-write" filter: "^.{1,32}$" display: "Name" From a667691fff821c775090e6a399ee247561351120 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 19:45:04 +0800 Subject: [PATCH 24/80] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E5=8A=A0=E5=85=A5go-oam?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 + go.mod | 53 ++++--------- go.sum | 223 ++++++++++-------------------------------------------- 3 files changed, 60 insertions(+), 219 deletions(-) diff --git a/README.md b/README.md index 2c88408e..5870d8c8 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@ | 33033/33034 | 信令跟踪上报 UDP/TCP | | 33060 | 性能分析 pprof | | 33040 | 网管测试 Api | +| 21/22/25 | SSH/FTP | +| 33066 | 网管连接 mysql | +| 6379 | 网管连接 redis | ## redis 配置文件相关 diff --git a/go.mod b/go.mod index 36b10023..c3cfb875 100644 --- a/go.mod +++ b/go.mod @@ -5,17 +5,13 @@ go 1.24.0 require ( github.com/creack/pty v1.1.24 github.com/dlclark/regexp2 v1.11.5 - github.com/gin-gonic/gin v1.10.0 + github.com/expr-lang/expr v1.17.5 + github.com/gin-gonic/gin v1.10.1 github.com/glebarez/sqlite v1.11.0 - github.com/go-resty/resty/v2 v2.16.5 - github.com/go-sql-driver/mysql v1.9.2 github.com/godoes/ginprom v0.3.7 github.com/golang-jwt/jwt/v5 v5.2.2 github.com/gopacket/gopacket v1.3.1 - github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 - github.com/gosnmp/gosnmp v1.40.0 - github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f github.com/linxGnu/gosmpp v0.3.1 github.com/matoous/go-nanoid/v2 v2.1.0 github.com/mojocn/base64Captcha v1.3.8 @@ -23,24 +19,22 @@ require ( github.com/penglongli/gin-metrics v0.1.13 github.com/pkg/sftp v1.13.9 github.com/prometheus-community/pro-bing v0.7.0 - github.com/redis/go-redis/v9 v9.8.0 + github.com/redis/go-redis/v9 v9.11.0 github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v4 v4.25.4 - github.com/slayercat/GoSNMPServer v0.5.2 + github.com/shirou/gopsutil/v4 v4.25.6 github.com/spf13/pflag v1.0.6 github.com/spf13/viper v1.20.1 github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.4 + github.com/tsmask/go-oam v1.0.3 + github.com/wneessen/go-mail v0.6.2 github.com/xuri/excelize/v2 v2.9.0 - golang.org/x/crypto v0.38.0 - golang.org/x/term v0.32.0 - golang.org/x/text v0.25.0 - gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + golang.org/x/crypto v0.40.0 + golang.org/x/text v0.27.0 gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.5.7 - gorm.io/gorm v1.26.1 - xorm.io/xorm v1.3.9 + gorm.io/driver/mysql v1.6.0 + gorm.io/gorm v1.30.0 ) require ( @@ -54,8 +48,7 @@ require ( github.com/cloudwego/base64x v0.1.5 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ebitengine/purego v0.8.2 // indirect - github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.1.0 // indirect @@ -68,33 +61,26 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/jonboulle/clockwork v0.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/fs v0.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect - github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.27 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.37.0 // indirect github.com/orcaman/concurrent-map/v2 v2.0.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -107,15 +93,10 @@ require ( github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.4 // indirect github.com/sagikazarmark/locafero v0.9.0 // indirect - github.com/shirou/gopsutil/v3 v3.24.5 // indirect - github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.14.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/syndtr/goleveldb v1.0.0 // indirect - github.com/tebeka/strftime v0.1.5 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect @@ -127,15 +108,13 @@ require ( golang.org/x/arch v0.16.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/image v0.26.0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sync v0.14.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/tools v0.32.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/tools v0.34.0 // indirect google.golang.org/protobuf v1.36.6 // indirect - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect modernc.org/libc v1.62.1 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.9.1 // indirect modernc.org/sqlite v1.37.0 // indirect - xorm.io/builder v0.3.13 // indirect ) diff --git a/go.sum b/go.sum index 67d7925c..2553e85d 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,5 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= -gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -23,7 +20,6 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL 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= @@ -35,14 +31,12 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= -github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= -github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k= +github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= @@ -51,8 +45,8 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= @@ -76,12 +70,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= -github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= -github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= @@ -92,49 +82,22 @@ 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/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= -github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopacket/gopacket v1.3.1 h1:ZppWyLrOJNZPe5XkdjLbtuTkfQoxQ0xyMJzQCqtqaPU= github.com/gopacket/gopacket v1.3.1/go.mod h1:3I13qcqSpB2R9fFQg866OOgzylYkZxLTmkvcXhvf6qg= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosnmp/gosnmp v1.36.2-0.20231009064202-d306ed5aa998/go.mod h1:O938QjIS4vpSag1UTcnnBq9MfNmimuOGtvQsT1NbErc= -github.com/gosnmp/gosnmp v1.40.0 h1:MvSqHZaNnhMKdn5IVhyYzCsVfXV1lgg6ZgLRku7FVcM= -github.com/gosnmp/gosnmp v1.40.0/go.mod h1:CxVS6bXqmWZlafUj9pZUnQX5e4fAltqPcijxWpCitDo= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= -github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= -github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= 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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -145,7 +108,6 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -156,15 +118,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo= -github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE= -github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4= -github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8= -github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc= -github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= github.com/linxGnu/gosmpp v0.3.1 h1:8weIv03SG8+k/vI3bO7SnZ6URjqpXy2B8EJQkPzwmjI= github.com/linxGnu/gosmpp v0.3.1/go.mod h1:H5Ca2UBCIYast4KRjc3hwgOkjzpghr4CB77jueWGQmc= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= @@ -173,8 +128,6 @@ 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/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= -github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 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= @@ -190,19 +143,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= -github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c= github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -215,7 +155,6 @@ github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw= github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA= @@ -226,11 +165,10 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= -github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= -github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= +github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= @@ -242,24 +180,10 @@ 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/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= -github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= -github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= -github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw= -github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= -github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/slayercat/GoSNMPServer v0.5.2 h1:IK2d3kz6JoiYHbAZT5H7hrQQRzAD7rxF0iJZxWrV7Ns= -github.com/slayercat/GoSNMPServer v0.5.2/go.mod h1:6taMSIwudR+7pKRO6dz2U+xoNccZds8eiMVlEN66fXY= +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/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= @@ -271,17 +195,13 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= @@ -292,35 +212,29 @@ github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+z github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg= -github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/tsmask/go-oam v1.0.3 h1:FN5Kf1aToYVDIQ3lueV2yo/TltmSBgL/FXVbqL6Duoc= +github.com/tsmask/go-oam v1.0.3/go.mod h1:HqFtN0LA9BiR1HWyHO++DY0fyYTl2sKVnRrZzuWy9n4= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 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.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= 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/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= github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE= github.com/xuri/nfp v0.0.0-20250226145837-86d5fc24b2ba h1:DhIu6n3qU0joqG9f4IO6a/Gkerd+flXrmlJ+0yX2W8U= github.com/xuri/nfp v0.0.0-20250226145837-86d5fc24b2ba/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -328,38 +242,28 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U= golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY= golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -367,53 +271,36 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +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/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= @@ -423,8 +310,9 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -434,55 +322,30 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 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/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= -gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= -gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= -gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.26.1 h1:ghB2gUI9FkS46luZtn6DLZ0f6ooBJ5IbVej2ENFDjRw= -gorm.io/gorm v1.26.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= +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= 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/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU= @@ -508,7 +371,3 @@ 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= -xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= -xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU= -xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw= From 27b5403339bf6a3b1536178b99c94c4d6a8eff69 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 16 Jul 2025 14:52:52 +0800 Subject: [PATCH 25/80] =?UTF-8?q?feat:=20=E5=91=8A=E8=AD=A6=E5=88=86?= =?UTF-8?q?=E7=BB=84=E7=BB=9F=E8=AE=A1=E6=95=B0=E9=87=8F=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../network_data/controller/all_alarm.go | 54 ++++++++++++- src/modules/network_data/network_data.go | 12 +++ src/modules/network_data/repository/alarm.go | 18 +++++ src/modules/network_data/service/alarm.go | 76 +++++++++++++++++-- 4 files changed, 153 insertions(+), 7 deletions(-) diff --git a/src/modules/network_data/controller/all_alarm.go b/src/modules/network_data/controller/all_alarm.go index b9e41d99..631028ed 100644 --- a/src/modules/network_data/controller/all_alarm.go +++ b/src/modules/network_data/controller/all_alarm.go @@ -43,7 +43,7 @@ type AlarmController struct { // @Param pvFlag query string false "PV Flag" Enums(PNF,VNF) // @Param alarmCode query string false "alarm status code" // @Param alarmType query string false "Alarm type Communication alarms=1, Equipment alarms=2, Processing faults=3, Environmental alarms=4, Quality of service alarms=5" Enums(1,2,3,4,5) -// @Param alarmStatus query string false "Alarm status 0:clear, 1:active" Enums(0,1) +// @Param alarmStatus query string false "Alarm status Clear Active" Enums(0,1) // @Param origSeverity query string false "Alarm Type 1: Critical, 2: Major, 3: Minor, 4: Warning" Enums(1,2,3,4) // @Param sortField query string false "Sort fields, fill in result fields" default(event_time) // @Param sortOrder query string false "Sort by ascending or descending order, asc desc" default(asc) @@ -139,6 +139,58 @@ func (s AlarmController) Ack(c *gin.Context) { c.JSON(200, resp.OkData(rows)) } +// 告警级别数量 +// +// GET /count/severity +func (s AlarmController) CountSeverity(c *gin.Context) { + var query struct { + AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"required,oneof=Clear Active"` // 告警状态 + } + 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 + } + + data := s.alarmService.CountSeverity(query.AlarmStatus) + c.JSON(200, resp.OkData(data)) +} + +// 告警类别数量 +// +// GET /count/type +func (s AlarmController) CountType(c *gin.Context) { + var query struct { + AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"required,oneof=Clear Active"` // 告警状态 + } + 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 + } + + data := s.alarmService.CountType(query.AlarmStatus) + c.JSON(200, resp.OkData(data)) +} + +// 告警状态前几排名 +// +// GET /count/ne +func (s AlarmController) CountNe(c *gin.Context) { + var query struct { + AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"required,oneof=Clear Active"` // 告警状态 + Top int `json:"top" form:"top" binding:"required"` // 前几 + } + 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 + } + + data := s.alarmService.CountNe(query.AlarmStatus, query.Top) + c.JSON(200, resp.OkData(data)) +} + // 告警列表导出 // // GET /export diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 2df1faab..3985cece 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -59,6 +59,18 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.alarm", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewAlarm.Export, ) + alarmGroup.GET("/count/type", + middleware.AuthorizeUser(nil), + controller.NewAlarm.CountType, + ) + alarmGroup.GET("/count/severity", + middleware.AuthorizeUser(nil), + controller.NewAlarm.CountSeverity, + ) + alarmGroup.GET("/count/ne", + middleware.AuthorizeUser(nil), + controller.NewAlarm.CountNe, + ) } // 告警日志数据信息 diff --git a/src/modules/network_data/repository/alarm.go b/src/modules/network_data/repository/alarm.go index 9cbbea1c..745662b7 100644 --- a/src/modules/network_data/repository/alarm.go +++ b/src/modules/network_data/repository/alarm.go @@ -192,3 +192,21 @@ func (r Alarm) SelectAlarmSeqLast(neType, neId string) int64 { } return alarmSeq } + +// GroupTotal 分组统计 +func (r Alarm) GroupTotal(alarmStatus string, group string, limit int) []map[string]any { + tx := db.DB("").Model(&model.Alarm{}) + tx = tx.Select("count(*) as total", group) + tx = tx.Where("alarm_status=?", alarmStatus) + tx = tx.Group(group).Order("total DESC") + // 查询数据 + var rows []map[string]any = make([]map[string]any, 0) + if limit > 0 { + tx = tx.Limit(limit) + } + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} diff --git a/src/modules/network_data/service/alarm.go b/src/modules/network_data/service/alarm.go index 737acb0b..f68958c5 100644 --- a/src/modules/network_data/service/alarm.go +++ b/src/modules/network_data/service/alarm.go @@ -6,6 +6,7 @@ import ( "time" "github.com/tsmask/go-oam" + "github.com/tsmask/go-oam/src/framework/utils/parse" "be.ems/src/framework/constants" "be.ems/src/framework/i18n" @@ -115,13 +116,76 @@ func (r Alarm) AckByIds(ids []int64, ackUser, ackState string) (int64, error) { return 0, fmt.Errorf("ack fail") } -// InsertAndForword 新增信息并转发通知 -func (s Alarm) InsertAndForword(param model.Alarm) int64 { - rows := s.alarmRepository.Insert(param) - if rows > 0 { - // 转发通知 TODO +// CountType 告警类别数量 +func (s Alarm) CountType(alarmStatus string) []map[string]any { + data := []map[string]any{} + alarmTypeArr := []string{ + oam.ALARM_TYPE_COMMUNICATION_ALARM, + oam.ALARM_TYPE_EQUIPMENT_ALARM, + oam.ALARM_TYPE_PROCESSING_FAILURE, + oam.ALARM_TYPE_ENVIRONMENTAL_ALARM, + oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM, } - return rows + for _, v := range alarmTypeArr { + data = append(data, map[string]any{ + "alarmType": v, + "total": 0, + }) + } + + // 告警类别数量 + rows := s.alarmRepository.GroupTotal(alarmStatus, "alarm_type", -1) + for _, item := range data { + for _, v := range rows { + str := fmt.Sprint(v["alarm_type"]) + if str == item["alarmType"] { + item["alarmType"] = str + item["total"] = parse.Number(v["total"]) + } + } + } + return data +} + +// CountSeverity 告警级别数量 +func (s Alarm) CountSeverity(alarmStatus string) []map[string]any { + data := []map[string]any{} + alarmTypeArr := []string{ + oam.ALARM_SEVERITY_CRITICAL, + oam.ALARM_SEVERITY_MAJOR, + oam.ALARM_SEVERITY_MINOR, + oam.ALARM_SEVERITY_WARNING, + } + for _, v := range alarmTypeArr { + data = append(data, map[string]any{ + "severity": v, + "total": 0, + }) + } + + // 数量 + rows := s.alarmRepository.GroupTotal(alarmStatus, "perceived_severity", -1) + for _, item := range data { + for _, v := range rows { + str := fmt.Sprint(v["perceived_severity"]) + if str == item["severity"] { + item["severity"] = str + item["total"] = parse.Number(v["total"]) + } + } + } + return data +} + +// CountNe 告警状态前几排名 +func (s Alarm) CountNe(alarmStatus string, top int) []map[string]any { + data := s.alarmRepository.GroupTotal(alarmStatus, "ne_type", top) + for _, v := range data { + v["neType"] = fmt.Sprint(v["ne_type"]) + v["total"] = parse.Number(v["total"]) + delete(v, "ne_type") + } + return data } // ExportXlsx 导出数据到 xlsx 文件 From 6e6c5714ec62bf12602958b8af25993fbfb43810 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 16 Jul 2025 14:53:25 +0800 Subject: [PATCH 26/80] =?UTF-8?q?style:=20=E6=9C=AC=E5=9C=B0=E5=BC=80?= =?UTF-8?q?=E5=8F=91SQL=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=E5=BC=80?= =?UTF-8?q?=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- local/omc.yaml | 2 ++ src/config/config.local.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/local/omc.yaml b/local/omc.yaml index d4987cca..f956467d 100644 --- a/local/omc.yaml +++ b/local/omc.yaml @@ -48,10 +48,12 @@ database: username: "root" # mysql username password: "1000omc@kp!" # mysql password database: "omc_db_mainv2" # mysql database + logging: true # lite: lite lite: type: "sqlite" database: "./local/omc_db.sqlite" # sqlite database + logging: true # default data source name defaultDataSourceName: "std" diff --git a/src/config/config.local.yaml b/src/config/config.local.yaml index 19e30744..12f212cb 100644 --- a/src/config/config.local.yaml +++ b/src/config/config.local.yaml @@ -26,10 +26,12 @@ database: username: "root" # mysql username password: "1000omc@kp!" # mysql password database: "omc_db" # mysql database + logging: true # lite: lite lite: type: "sqlite" database: "/usr/local/etc/omc/database/omc_db.sqlite" # sqlite database + logging: true # default data source name defaultDataSourceName: "std" From 1462563eef359979939986e4a04c54fd784cda81 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 16 Jul 2025 15:08:26 +0800 Subject: [PATCH 27/80] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=B8=89?= =?UTF-8?q?=E4=B8=AA=E5=A4=A7=E5=B1=8F=E9=A1=B5=E9=9D=A2=E7=9A=84=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_menu.sql | 3 +++ build/database/lite/upgrade/upg_sys_menu.sql | 3 +++ build/database/std/install/sys_menu.sql | 5 +++-- build/database/std/upgrade/upg_sys_menu.sql | 5 +++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/build/database/lite/install/sys_menu.sql b/build/database/lite/install/sys_menu.sql index fd85055a..1bf7da58 100644 --- a/build/database/lite/install/sys_menu.sql +++ b/build/database/lite/install/sys_menu.sql @@ -155,6 +155,8 @@ INSERT INTO "sys_menu" VALUES (2115, 'menu.system.systemResource', 1, 6, 'monito INSERT INTO "sys_menu" VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.setting.i18nRemark'); INSERT INTO "sys_menu" VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -170,6 +172,7 @@ INSERT INTO "sys_menu" VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHo INSERT INTO "sys_menu" VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/lite/upgrade/upg_sys_menu.sql b/build/database/lite/upgrade/upg_sys_menu.sql index e39b0dfd..d5c28e75 100644 --- a/build/database/lite/upgrade/upg_sys_menu.sql +++ b/build/database/lite/upgrade/upg_sys_menu.sql @@ -154,6 +154,8 @@ REPLACE INTO "sys_menu" VALUES (2115, 'menu.system.systemResource', 1, 6, 'monit REPLACE INTO "sys_menu" VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.setting.i18nRemark'); REPLACE INTO "sys_menu" VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -169,6 +171,7 @@ REPLACE INTO "sys_menu" VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neH REPLACE INTO "sys_menu" VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/std/install/sys_menu.sql b/build/database/std/install/sys_menu.sql index 19f2683f..c5025ce0 100644 --- a/build/database/std/install/sys_menu.sql +++ b/build/database/std/install/sys_menu.sql @@ -158,8 +158,8 @@ INSERT INTO `sys_menu` VALUES (2115, 'menu.system.systemResource', 1, 6, 'monito INSERT INTO `sys_menu` VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588,'system', 1728641403588, ''); --- INSERT INTO `sys_menu` VALUES (2119, 'menu.ueUser.n3iwf', 5, 8, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'neUser:n3iwf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); --- INSERT INTO `sys_menu` VALUES (2120, 'menu.ueUser.pcf', 5, 9, 'pcf', 'neUser/pcf/index', '1', '0', 'M', '1', '1', 'neUser:pcf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.setting.i18nRemark'); INSERT INTO `sys_menu` VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -177,6 +177,7 @@ INSERT INTO `sys_menu` VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHo INSERT INTO `sys_menu` VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, ''); diff --git a/build/database/std/upgrade/upg_sys_menu.sql b/build/database/std/upgrade/upg_sys_menu.sql index 6f45f6fe..555014cc 100644 --- a/build/database/std/upgrade/upg_sys_menu.sql +++ b/build/database/std/upgrade/upg_sys_menu.sql @@ -180,8 +180,8 @@ REPLACE INTO `sys_menu` VALUES (2115, 'menu.system.systemResource', 1, 6, 'monit REPLACE INTO `sys_menu` VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588,'system', 1728641403588, ''); --- REPLACE INTO `sys_menu` VALUES (2119, 'menu.ueUser.n3iwf', 5, 8, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'neUser:n3iwf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); --- REPLACE INTO `sys_menu` VALUES (2120, 'menu.ueUser.pcf', 5, 9, 'pcf', 'neUser/pcf/index', '1', '0', 'M', '1', '1', 'neUser:pcf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.setting.i18nRemark'); REPLACE INTO `sys_menu` VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -199,6 +199,7 @@ REPLACE INTO `sys_menu` VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neH REPLACE INTO `sys_menu` VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, ''); From 758843c2a8a4782719f52ebdbf4beba3dd7470a9 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 16 Jul 2025 15:56:33 +0800 Subject: [PATCH 28/80] =?UTF-8?q?fieat:=20=E7=A7=BB=E9=99=A4sshsvc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 14 ------- build/default/sshsvc.yaml | 87 --------------------------------------- 2 files changed, 101 deletions(-) delete mode 100644 build/default/sshsvc.yaml diff --git a/.gitignore b/.gitignore index 3c63e24e..77a77087 100644 --- a/.gitignore +++ b/.gitignore @@ -21,17 +21,3 @@ # Build Output local/omc_db.sqlite omc -restagent/restagent - -# Run temp file and dir -restagent/backup/ -restagent/log/ -restagent/upload/ -restagent/software/ -restagent/database/ -restagent/license/ - -sshsvc/sshsvc -sshsvc/mmllog/ -sshsvc/mmlhome/ -sshsvc/log/ diff --git a/build/default/sshsvc.yaml b/build/default/sshsvc.yaml deleted file mode 100644 index cf555d98..00000000 --- a/build/default/sshsvc.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# file: log file name -# level: /trace/debug/info/warn/error/fatal, default: debug -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation -logger: - file: /var/log/omc_sshsvc.log - level: warn - duration: 24 - count: 30 - -# file: MML log file name -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation -# level: cmd/ret log cmd/log cmd & result -logmml: - file: /var/log/omc_mml.log - duration: 24 - count: 30 - level: cmd - -# ssh service listen ipv4/v6 and port, support multiple routines -# ip: 0.0.0.0 or ::0, support IPv4/v6 -# session: single/multiple session for one user -sshd: - listenAddr: 0.0.0.0 - listenPort: 32222 - privateKey: /root/.ssh/id_rsa - maxConnNum: 2 - timeout: 1800 - session: multiple - mmlHome: /usr/local/omc/mmlhome - userName: manager - password: pass123 - authType: local - tagNE: omc - -# authType: local/omc -telnetServer: - listenAddr: 0.0.0.0 - listenPort: 32323 - maxConnNum: 2 - timeout: 1800 - session: multiple - mmlHome: /usr/local/omc/mmlhome - userName: manager - password: pass123 - authType: local - tagNE: omc - -# authproto: NoAuth/MD5/SHA -# privProto: NoPriv/DES/AES/AES192/AES256 -snmpServer: - listenAddr: '[::]' - listenPort: 34957 - userName: manager - authPass: pass123 - authproto: MD5 - privPass: "3F2A1B4C5D6E7F8A9B0C1D2E3F4A5B6C7D8E9F0A1B2C3D4E" - privProto: DES - engineID: "8000000004323030313a6462383a3a39313636" - trapPort: 34958 - trapListen: false - trapBool: false - trapTick: 60 - timeOut: 5 - trapTarget: "" - -database: - type: mysql - user: root - password: 1000omc@kp! - host: 127.0.0.1 - port: 33066 - name: omc_db - connParam: charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True - -omc: - httpUri: http://127.0.0.1:33030 - userCrypt: bcrypt - -ne: - port: 4100 - sleep: 200 - user: admin - password: admin - - From ba067c2db77cdc0b4748ba4fc07041f240354edf Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 16 Jul 2025 17:00:21 +0800 Subject: [PATCH 29/80] =?UTF-8?q?feat:=20=E5=8C=97=E5=90=91=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E7=BD=91=E5=85=83=E7=8A=B6=E6=80=81/=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E4=B8=8B=E5=8F=91=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/controller/api_rest.go | 20 ++++++++++++++++++++ src/modules/oam/oam.go | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go index 1da4e89a..c857ec90 100644 --- a/src/modules/oam/controller/api_rest.go +++ b/src/modules/oam/controller/api_rest.go @@ -8,6 +8,7 @@ import ( "github.com/gin-gonic/gin" "github.com/tsmask/go-oam" + goOamState "github.com/tsmask/go-oam/src/modules/state/service" "be.ems/src/framework/logger" "be.ems/src/framework/resp" @@ -670,3 +671,22 @@ func (s APIRestController) ResolveAlarmHistory(c *gin.Context) { } c.JSON(200, resp.Ok(nil)) } + +// QuerySystemState 查询系统状态 +// +// GET /systemManagement/v1/elementType/:elementTypeValue/objectType/systemState +func (s APIRestController) QuerySystemState(c *gin.Context) { + elementTypeValue := c.Param("elementTypeValue") + if strings.ToLower(elementTypeValue) != "omc" { + c.JSON(200, resp.ErrMsg("elementType only omc")) + return + } + c.JSON(200, goOamState.NewState.Info()) +} + +// NeConfigOMC 网元配置对端网管信息 +// +// PUT /systemManagement/v1/elementType/:elementTypeValue/objectType/config/omcNeConfig +func (s APIRestController) NeConfigOMC(c *gin.Context) { + c.JSON(204, nil) +} diff --git a/src/modules/oam/oam.go b/src/modules/oam/oam.go index 5a116ecf..fa4cac0b 100644 --- a/src/modules/oam/oam.go +++ b/src/modules/oam/oam.go @@ -24,7 +24,7 @@ func Setup(router *gin.Engine) { // 网管接收端收KPI oam.KPIReceiveRoute(router, service.NewKPI.Resolve) - // APIRest 北向接收 + // APIRest 北向定义 aprRest := controller.NewAPIRest aprRestGroup := router.Group("/api/rest") { @@ -35,6 +35,8 @@ func Setup(router *gin.Engine) { aprRestGroup.POST("/ueManagement/v1/elementType/:elementTypeValue/objectType/nbState", aprRest.ResolveNBState) 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) + aprRestGroup.PUT("/systemManagement/v1/elementType/:elementTypeValue/objectType/config/omcNeConfig", aprRest.NeConfigOMC) } } From 91eb7077e9ac5e728206ea0c9fdd75691ef440fe Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 18 Jul 2025 21:30:52 +0800 Subject: [PATCH 30/80] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=85=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E6=8C=87=E6=A0=87?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../network_data/controller/all_kpi_c.go | 183 ++++++++++++++++++ src/modules/network_data/network_data.go | 25 +++ .../network_data/repository/kpi_c_report.go | 131 ++++++++++++- .../network_data/service/kpi_c_report.go | 54 +++++- 4 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 src/modules/network_data/controller/all_kpi_c.go diff --git a/src/modules/network_data/controller/all_kpi_c.go b/src/modules/network_data/controller/all_kpi_c.go new file mode 100644 index 00000000..0952e250 --- /dev/null +++ b/src/modules/network_data/controller/all_kpi_c.go @@ -0,0 +1,183 @@ +package controller + +import ( + "fmt" + "strconv" + "strings" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/utils/parse" + "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" +) + +// 实例化控制层 KPICController 结构体 +var NewKPIC = &KPICController{ + neInfoService: neService.NewNeInfo, + kpicReportService: neDataService.NewKpiCReport, +} + +// 性能统计 +// +// PATH /kpic +type KPICController struct { + neInfoService *neService.NeInfo // 网元信息服务 + kpicReportService *neDataService.KpiCReport // 指标统计服务 +} + +// 获取统计数据 +// +// GET /data +// +// @Tags network_data/kpi +// @Accept json +// @Produce json +// @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) default(AMF) +// @Param neId query string true "NE ID" default(001) +// @Param beginTime query number true "begin time (timestamped milliseconds)" default(1729162507596) +// @Param endTime query number true "end time (timestamped milliseconds)" default(1729164187611) +// @Param interval query number true "interval" Enums(5,10,15,30,60,300,600,900,1800,3600) default(60) +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Access to statistical data +// @Description Access to statistical data +// @Router /neData/kpic/data [get] +func (s KPICController) KPIData(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var querys model.KPICQuery + if err := c.ShouldBindQuery(&querys); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID + + // 查询数据 + kpiData := s.kpicReportService.FindData(querys) + c.JSON(200, resp.OkData(kpiData)) +} + +// 自定义标题列表 +// +// GET /titlelist +func (s KPICController) ListTitle(c *gin.Context) { + query := reqctx.QueryMap(c) + if v, ok := query["status"]; ok && v == "" { + query["status"] = "1" + } + rows, total := s.kpicReportService.TitleFindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows})) +} + +// 自定义标题新增 +// +// POST /title +func (s KPICController) AddTitle(c *gin.Context) { + var body model.KpiCTitle + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 校验指标是否存在 + kpicTitles := s.kpicReportService.TitleFind(model.KpiCTitle{ + NeType: body.NeType, + KpiId: body.KpiId, + }) + if len(kpicTitles) > 0 { + for _, v := range kpicTitles { + if v.Status == "2" { + c.JSON(200, resp.ErrMsg("custom indicator already exist")) + return + } + } + } + + // 生成自定义指标ID + if body.KpiId == "" { + body.KpiId = fmt.Sprintf("%s.C.01", strings.ToUpper(body.NeType)) + } else { + // 网元类型最后指标ID + lastKpiId := s.kpicReportService.TitleLastKPIId(body.NeType) + if lastKpiId != "" { + // title like AMF.C.01 截断 .C. 并获取后面的数字部分 + parts := strings.Split(lastKpiId, ".C.") + if len(parts) == 2 { + numStr := parts[1] + if num, err := strconv.Atoi(numStr); err == nil { + num++ // 数字加 1 + // 转换为前面补零的 2 位字符串 + body.KpiId = fmt.Sprintf("%s.C.%02d", strings.ToUpper(body.NeType), num) + } + } + } + } + + body.CreatedBy = reqctx.LoginUserToUserName(c) + insertId := s.kpicReportService.TitleInsert(body) + if insertId > 0 { + c.JSON(200, resp.Ok(nil)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// 自定义标题修改 +// +// PUT /title +func (s KPICController) EditTitle(c *gin.Context) { + var body model.KpiCTitle + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + rows := s.kpicReportService.TitleUpdate(body) + if rows > 0 { + c.JSON(200, resp.Ok(nil)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// 自定义标题删除 +// +// DELETE /title/:id +func (s KPICController) RemoveTitle(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + id := c.Query("id") + if id == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + // 处理字符转id数组后去重 + uniqueIDs := parse.RemoveDuplicatesToArray(id, ",") + // 转换成int64数组类型 + ids := make([]int64, 0) + for _, v := range uniqueIDs { + ids = append(ids, parse.Number(v)) + } + + rows, err := s.kpicReportService.TitleDeleteByIds(ids) + if err != nil { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, resp.OkMsg(msg)) +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 3985cece..0cbb2fe3 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -33,6 +33,31 @@ func Setup(router *gin.Engine) { ) } + // 性能自定义统计信息 + kpicGroup := neDataGroup.Group("/kpic") + { + kpicGroup.GET("/data", + middleware.AuthorizeUser(nil), + controller.NewKPIC.KPIData, + ) + kpicGroup.GET("/title/list", + middleware.AuthorizeUser(nil), + controller.NewKPIC.ListTitle, + ) + kpicGroup.POST("/title", + middleware.AuthorizeUser(nil), + controller.NewKPIC.AddTitle, + ) + kpicGroup.PUT("/title", + middleware.AuthorizeUser(nil), + controller.NewKPIC.EditTitle, + ) + kpicGroup.DELETE("/title", + middleware.AuthorizeUser(nil), + controller.NewKPIC.RemoveTitle, + ) + } + // 告警数据信息 alarmGroup := neDataGroup.Group("/alarm") { diff --git a/src/modules/network_data/repository/kpi_c_report.go b/src/modules/network_data/repository/kpi_c_report.go index 44a8ee28..244f9d70 100644 --- a/src/modules/network_data/repository/kpi_c_report.go +++ b/src/modules/network_data/repository/kpi_c_report.go @@ -17,7 +17,7 @@ var NewKpiCReport = &KpiCReport{} type KpiCReport struct{} // SelectGoldKPI 通过网元指标数据信息 -func (r KpiCReport) SelectKPI(query model.KPIQuery) []model.KpiCReport { +func (r KpiCReport) SelectKPI(query model.KPICQuery) []model.KpiCReport { rows := []model.KpiCReport{} if query.NeType == "" { return rows @@ -87,3 +87,132 @@ func (r KpiCReport) SelectKPITitle(neType string) []model.KpiCTitle { } return rows } + +// TitleLastKPIId 查询指标标题最后kpiid +func (r KpiCReport) TitleLastKPIId(neType string) string { + tx := db.DB("").Model(&model.KpiCTitle{}) + tx = tx.Where("ne_type=?", neType) + tx = tx.Select("kpi_id").Order("kpi_id DESC") + // 查询数据 + var kpiId string = "" + if err := tx.Limit(1).Find(&kpiId).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return kpiId + } + return kpiId +} + +// SelectByPageTitle 分页查询集合 +func (r KpiCReport) TitleSelectByPage(query map[string]string) ([]model.KpiCTitle, int64) { + tx := db.DB("").Model(&model.KpiCTitle{}) + // 查询条件拼接 + if v, ok := query["neType"]; ok && v != "" { + tx = tx.Where("ne_type = ?", v) + } + if v, ok := query["status"]; ok && v != "" { + tx = tx.Where("status = ?", v) + } else { + tx = tx.Where("status != ?", "2") + } + + // 查询结果 + var total int64 = 0 + rows := []model.KpiCTitle{} + + // 查询数量 长度为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize)) + + // 排序 + if v, ok := query["sortField"]; ok && v != "" { + sortSql := v + if o, ok := query["sortOrder"]; ok && o != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + tx = tx.Order(sortSql) + } + + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query err => %v", err) + } + + return rows, total +} + +// TitleSelect 网元对应的指标名称 +func (r KpiCReport) TitleSelect(param model.KpiCTitle) []model.KpiCTitle { + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + if param.NeType != "" { + tx = tx.Where("ne_type =?", param.NeType) + } + if param.Title != "" { + tx = tx.Where("title = ?", param.Title) + } + if param.Status != "" { + tx = tx.Where("status = ?", param.Status) + } + // 查询数据 + rows := []model.KpiCTitle{} + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// TitleInsert 新增信息 +func (r KpiCReport) TitleInsert(param model.KpiCTitle) int64 { + if param.CreatedBy != "" { + param.UpdatedAt = time.Now().UnixMilli() + } + param.Status = "1" + tx := db.DB("").Create(¶m) + if err := tx.Error; err != nil { + logger.Errorf("CreateInBatches err => %v", err) + } + return param.ID +} + +// TitleUpdate 修改信息 +func (r KpiCReport) TitleUpdate(param model.KpiCTitle) int64 { + if param.ID <= 0 { + return 0 + } + param.UpdatedAt = time.Now().UnixMilli() + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + tx = tx.Where("id = ?", param.ID) + tx = tx.Omit("id", "created_by") + // 执行更新 + if err := tx.Updates(param).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// TitleDeleteByIds 批量删除信息 +func (r KpiCReport) TitleDeleteByIds(ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + if err := tx.Update("status", 2).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} diff --git a/src/modules/network_data/service/kpi_c_report.go b/src/modules/network_data/service/kpi_c_report.go index 1c70a507..4b93b8d2 100644 --- a/src/modules/network_data/service/kpi_c_report.go +++ b/src/modules/network_data/service/kpi_c_report.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "sort" + "strconv" "be.ems/src/framework/utils/parse" "be.ems/src/modules/network_data/model" @@ -21,7 +22,7 @@ type KpiCReport struct { } // FindKPI 通过网元指标数据信息 -func (s KpiCReport) FindData(query model.KPIQuery) []map[string]any { +func (s KpiCReport) FindData(query model.KPICQuery) []map[string]any { // 原始数据 rows := s.kpiCReportRepository.SelectKPI(query) if len(rows) <= 0 { @@ -100,14 +101,16 @@ func (s KpiCReport) FindData(query model.KPIQuery) []map[string]any { // 遍历kpiIds数组对lastRecord赋值 for _, kpiId := range kpiIds { if v, ok := record[kpiId]; ok { - // 特殊字段,只取一次收到的非0值 - if kpiId == "AMF.01" || kpiId == "UDM.01" || kpiId == "UDM.02" || kpiId == "UDM.03" || kpiId == "SMF.01" { - // startItem[kpiId] = parse.Number(v) - continue // startIndex的值不累加不取最后 - } else { - value := parse.Number(startItem[kpiId]) - startItem[kpiId] = value + parse.Number(v) + value := v.(float64) + startItem[kpiId].(float64) + formatted := fmt.Sprintf("%.3f", value) + formattedFloat, err := strconv.ParseFloat(formatted, 64) + if err != nil { + formattedFloat = 0 } + startItem[kpiId] = formattedFloat + + // value := parse.Number(startItem[kpiId]) + // startItem[kpiId] = value + parse.Number(v) } } } @@ -136,3 +139,38 @@ func (s KpiCReport) Insert(param model.KpiCReport) int64 { func (r KpiCReport) FindTitle(neType string) []model.KpiCTitle { return r.kpiCReportRepository.SelectKPITitle(neType) } + +// TitleLastKPIId 指标标题最后kpiid +func (r KpiCReport) TitleLastKPIId(neType string) string { + return r.kpiCReportRepository.TitleLastKPIId(neType) +} + +// FindByPage 根据条件分页查询 +func (r KpiCReport) TitleFindByPage(query map[string]string) ([]model.KpiCTitle, int64) { + return r.kpiCReportRepository.TitleSelectByPage(query) +} + +// TitleFind 查询信息 +func (r KpiCReport) TitleFind(param model.KpiCTitle) []model.KpiCTitle { + return r.kpiCReportRepository.TitleSelect(param) +} + +// TitleUpdate 更新信息 +func (r KpiCReport) TitleUpdate(param model.KpiCTitle) int64 { + return r.kpiCReportRepository.TitleUpdate(param) +} + +// TitleDeleteByIds 批量删除信息 +func (r KpiCReport) TitleDeleteByIds(ids []int64) (int64, error) { + rows := r.kpiCReportRepository.TitleDeleteByIds(ids) + if rows > 0 { + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} + +// TitleInsert 新增信息 +func (r KpiCReport) TitleInsert(param model.KpiCTitle) int64 { + return r.kpiCReportRepository.TitleInsert(param) +} From c4bd986040c6638af16c126b0ce474318fc92b76 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 18 Jul 2025 21:33:32 +0800 Subject: [PATCH 31/80] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2507.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b389b22b..8c7c8bba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # 版本发布日志 +## 2.2507.2-20250718 + +- 移除 iperf安装包,features、lib和sshsvc目录 +- 移除 将配置文件中无用配置删除精简 +- 重构 接收CDR/UE接入/告警/KPI功能 +- 新增 nssf/n3iwf直连接口 +- 新增 通知模块,暂时只有邮件和smsc发送,可在OMC配置中修改参数 +- 新增 mml到工具模块 +- 新增 北向定义网元状态/配置下发接口,oam对外开放无限制接口模块 +- 修复 服务端口监听失败每5秒重试最多10次 +- 更新 OMC/CBC/UDM参数配置映射文件 +- 更新 升级数据库表结构,依赖更新并加入go-oam +- 新增 告警分组统计数量接口 +- 新增 mt版本移动过过来的三个大屏页面的系统菜单 +- 删除 移除sshsvc服务 +- 新增 北向定义网元状态/配置下发接口 +- 新增 补充缺失的自定义指标接口 + ## 2.2507.1-20250705 - 修复 SMSC和UDM配置在lite下无法正常显示问题 From 8fe698ebc161c7743e14ae65bfbf67a229500658 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 21 Jul 2025 18:04:27 +0800 Subject: [PATCH 32/80] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0go-oam?= =?UTF-8?q?=E5=BA=93=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 4 ++-- src/modules/network_data/service/alarm.go | 2 +- src/modules/network_element/service/ne_config_omc.go | 2 +- src/modules/oam/controller/api_rest.go | 2 +- src/modules/trace/service/trace_task.go | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index c3cfb875..6433b78d 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.4 - github.com/tsmask/go-oam v1.0.3 + github.com/tsmask/go-oam v1.0.4 github.com/wneessen/go-mail v0.6.2 github.com/xuri/excelize/v2 v2.9.0 golang.org/x/crypto v0.40.0 diff --git a/go.sum b/go.sum index 2553e85d..4c3e693e 100644 --- a/go.sum +++ b/go.sum @@ -216,8 +216,8 @@ github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8O github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= -github.com/tsmask/go-oam v1.0.3 h1:FN5Kf1aToYVDIQ3lueV2yo/TltmSBgL/FXVbqL6Duoc= -github.com/tsmask/go-oam v1.0.3/go.mod h1:HqFtN0LA9BiR1HWyHO++DY0fyYTl2sKVnRrZzuWy9n4= +github.com/tsmask/go-oam v1.0.4 h1:Q3sV8paXweQweLUJ4uDyO9Pn9TjElWjeWd6cfVOFgNw= +github.com/tsmask/go-oam v1.0.4/go.mod h1:HqFtN0LA9BiR1HWyHO++DY0fyYTl2sKVnRrZzuWy9n4= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 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= diff --git a/src/modules/network_data/service/alarm.go b/src/modules/network_data/service/alarm.go index f68958c5..09a34918 100644 --- a/src/modules/network_data/service/alarm.go +++ b/src/modules/network_data/service/alarm.go @@ -6,7 +6,7 @@ import ( "time" "github.com/tsmask/go-oam" - "github.com/tsmask/go-oam/src/framework/utils/parse" + "github.com/tsmask/go-oam/framework/utils/parse" "be.ems/src/framework/constants" "be.ems/src/framework/i18n" diff --git a/src/modules/network_element/service/ne_config_omc.go b/src/modules/network_element/service/ne_config_omc.go index 7243c3e2..95e605f1 100644 --- a/src/modules/network_element/service/ne_config_omc.go +++ b/src/modules/network_element/service/ne_config_omc.go @@ -5,7 +5,7 @@ import ( "strings" "be.ems/src/framework/config" - "github.com/tsmask/go-oam/src/framework/utils/parse" + "github.com/tsmask/go-oam/framework/utils/parse" ) // GetOMCYaml 获取OMC网元配置文件 diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go index c857ec90..3675b951 100644 --- a/src/modules/oam/controller/api_rest.go +++ b/src/modules/oam/controller/api_rest.go @@ -8,7 +8,7 @@ import ( "github.com/gin-gonic/gin" "github.com/tsmask/go-oam" - goOamState "github.com/tsmask/go-oam/src/modules/state/service" + goOamState "github.com/tsmask/go-oam/modules/state/service" "be.ems/src/framework/logger" "be.ems/src/framework/resp" diff --git a/src/modules/trace/service/trace_task.go b/src/modules/trace/service/trace_task.go index be335142..d326ae06 100644 --- a/src/modules/trace/service/trace_task.go +++ b/src/modules/trace/service/trace_task.go @@ -6,7 +6,7 @@ import ( "net" "strings" - "github.com/tsmask/go-oam/src/framework/socket" + "github.com/tsmask/go-oam/framework/socket" "be.ems/src/framework/config" "be.ems/src/framework/logger" From d96303639df770a58e87e87a867c30d5e1e7f4ad Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 21 Jul 2025 18:26:17 +0800 Subject: [PATCH 33/80] =?UTF-8?q?fix:=20=E7=BD=91=E7=AE=A1=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E4=BF=A1=E6=81=AF=E8=BF=94=E5=9B=9Enil=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/controller/api_rest.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go index 3675b951..8c426b29 100644 --- a/src/modules/oam/controller/api_rest.go +++ b/src/modules/oam/controller/api_rest.go @@ -681,7 +681,11 @@ func (s APIRestController) QuerySystemState(c *gin.Context) { c.JSON(200, resp.ErrMsg("elementType only omc")) return } - c.JSON(200, goOamState.NewState.Info()) + info := goOamState.NewState.Info() + info.SerialNum = "-" + info.ExpiryDate = "-" + info.Capability = 50 + c.JSON(200, info) } // NeConfigOMC 网元配置对端网管信息 From 8fd00baf8b1f2ceea506267c5e18c02905305f9e Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 21 Jul 2025 19:03:41 +0800 Subject: [PATCH 34/80] =?UTF-8?q?fix:=20=E7=BD=91=E7=AE=A1=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E4=BF=A1=E6=81=AF=E8=BF=94=E5=9B=9E=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/controller/api_rest.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go index 8c426b29..4eb57f8e 100644 --- a/src/modules/oam/controller/api_rest.go +++ b/src/modules/oam/controller/api_rest.go @@ -10,6 +10,7 @@ import ( "github.com/tsmask/go-oam" goOamState "github.com/tsmask/go-oam/modules/state/service" + "be.ems/src/framework/config" "be.ems/src/framework/logger" "be.ems/src/framework/resp" "be.ems/src/framework/utils/date" @@ -685,6 +686,7 @@ func (s APIRestController) QuerySystemState(c *gin.Context) { info.SerialNum = "-" info.ExpiryDate = "-" info.Capability = 50 + info.Version = config.Version c.JSON(200, info) } From 7c2b8b01d85aa90cfe755b17a0e9a7de6a292bbe Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 22 Jul 2025 17:50:02 +0800 Subject: [PATCH 35/80] =?UTF-8?q?fix:=20=E5=91=8A=E8=AD=A6=E7=BA=A7?= =?UTF-8?q?=E5=88=AB=E5=88=A4=E6=96=AD=E6=88=90=E7=B1=BB=E5=9E=8B=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E4=BA=8B=E4=BB=B6=E5=AD=98=E5=82=A8=E5=88=B0=E5=91=8A?= =?UTF-8?q?=E8=AD=A6=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/service/alarm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/oam/service/alarm.go b/src/modules/oam/service/alarm.go index 0f28e935..bea08860 100644 --- a/src/modules/oam/service/alarm.go +++ b/src/modules/oam/service/alarm.go @@ -78,7 +78,7 @@ func (s *Alarm) Resolve(a oam.Alarm) error { // 进行清除 if a.AlarmStatus == oam.ALARM_STATUS_CLEAR { - if a.AlarmType == oam.ALARM_SEVERITY_EVENT { + if a.PerceivedSeverity == oam.ALARM_SEVERITY_EVENT { if err := s.clearEvent(); err != nil { logger.Warnf("resolve alarm clear event failed: %s", err.Error()) return err @@ -93,7 +93,7 @@ func (s *Alarm) Resolve(a oam.Alarm) error { } // 进行新增 if a.AlarmStatus == oam.ALARM_STATUS_ACTIVE { - if a.AlarmType == oam.ALARM_SEVERITY_EVENT { + if a.PerceivedSeverity == oam.ALARM_SEVERITY_EVENT { if err := s.addEvent(); err != nil { logger.Warnf("resolve alarm add event failed: %s", err.Error()) return err From 7ff4e5bc2bd54e7f41b6ae64d765321bda1f8f94 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 22 Jul 2025 18:52:35 +0800 Subject: [PATCH 36/80] =?UTF-8?q?fix:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=E4=B8=8D?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=B0=8F=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/service/kpi_c_report.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/modules/network_data/service/kpi_c_report.go b/src/modules/network_data/service/kpi_c_report.go index 4b93b8d2..4f5bc252 100644 --- a/src/modules/network_data/service/kpi_c_report.go +++ b/src/modules/network_data/service/kpi_c_report.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "sort" - "strconv" "be.ems/src/framework/utils/parse" "be.ems/src/modules/network_data/model" @@ -102,13 +101,7 @@ func (s KpiCReport) FindData(query model.KPICQuery) []map[string]any { for _, kpiId := range kpiIds { if v, ok := record[kpiId]; ok { value := v.(float64) + startItem[kpiId].(float64) - formatted := fmt.Sprintf("%.3f", value) - formattedFloat, err := strconv.ParseFloat(formatted, 64) - if err != nil { - formattedFloat = 0 - } - startItem[kpiId] = formattedFloat - + startItem[kpiId] = value // value := parse.Number(startItem[kpiId]) // startItem[kpiId] = value + parse.Number(v) } From 9b25be96fac8de64d4cecdc05600d4229a776843 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 22 Jul 2025 19:15:12 +0800 Subject: [PATCH 37/80] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0IMS-CDR=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E7=A0=81=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 6 +- build/database/lite/upgrade/upg_sys_i18n.sql | 931 +++++++++++++++++++ build/database/std/install/sys_i18n.sql | 6 +- build/database/std/upgrade/upg_sys_i18n.sql | 6 +- 4 files changed, 940 insertions(+), 9 deletions(-) create mode 100644 build/database/lite/upgrade/upg_sys_i18n.sql diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index 1f6f5f8f..cd0c81f1 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -611,7 +611,7 @@ INSERT INTO "sys_i18n" VALUES (541, 'dictData.cdr_sip_code.404', '404 找不到' INSERT INTO "sys_i18n" VALUES (542, 'dictData.cdr_sip_code.487', '487 请求已终止', '487 Request Terminated'); INSERT INTO "sys_i18n" VALUES (543, 'dictData.cdr_sip_code.503', '503 服务不可用', '503 Service Unavailable'); INSERT INTO "sys_i18n" VALUES (544, 'dictData.cdr_sip_code.504', '504 服务器超时', '504 Server Timeout'); -INSERT INTO "sys_i18n" VALUES (545, 'dictData.cdr_sip_code.603', '603 下降', '603 Decline'); +INSERT INTO "sys_i18n" VALUES (545, 'dictData.cdr_sip_code.603', '603 拒绝', '603 Decline'); INSERT INTO "sys_i18n" VALUES (546, 'dictData.cdr_sip_code.606', '606 不可接受', '606 Not Acceptable'); INSERT INTO "sys_i18n" VALUES (547, 'cache.name.token', '用户令牌', 'User Token'); INSERT INTO "sys_i18n" VALUES (548, 'cache.name.sys_config', '参数管理', 'Parameters Management'); @@ -839,7 +839,7 @@ INSERT INTO "sys_i18n" VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其 INSERT INTO "sys_i18n" VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); INSERT INTO "sys_i18n" VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); INSERT INTO "sys_i18n" VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -INSERT INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 用户断线', 'MO User Disconnected'); +INSERT INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); INSERT INTO "sys_i18n" VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); INSERT INTO "sys_i18n" VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); INSERT INTO "sys_i18n" VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -847,7 +847,7 @@ INSERT INTO "sys_i18n" VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 INSERT INTO "sys_i18n" VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); INSERT INTO "sys_i18n" VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); INSERT INTO "sys_i18n" VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -INSERT INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 明确拒绝通话', 'MT explicitly rejected the call'); +INSERT INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); INSERT INTO "sys_i18n" VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); INSERT INTO "sys_i18n" VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); INSERT INTO "sys_i18n" VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql new file mode 100644 index 00000000..00fcba3f --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -0,0 +1,931 @@ +-- ---------------------------- +-- Table structure for sys_i18n +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_i18n" ( + "id" integer NOT NULL, + "key_lable" text(255) NOT NULL, + "value_zh" text(2048), + "value_en" text(2048), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Records of sys_i18n +-- ---------------------------- +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (1, 'i18n', '中文', 'English'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (2, 'hello', '你好', 'Hello'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (3, 'menu.system', '系统', 'System'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (4, 'menu.monitor', '监控', 'Monitor'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (5, 'menu.tools', '工具', 'Tools'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (6, 'menu.ne', '网元', 'NE'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (7, 'menu.ue', '终端', 'UE'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (8, 'menu.systemRemark', '系统管理目录', 'System Management Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (9, 'menu.monitorRemark', '系统监控目录', 'System Monitor Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (10, 'menu.toolsRemark', '系统工具目录', 'System Tools Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (11, 'menu.neRemark', '网元配置管理目录', 'NE Configuration Management Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (12, 'menu.ueRemark', '网元终端信息目录', 'Network Element Terminal Information Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (13, 'menu.security.user', '用户管理', 'User Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (14, 'menu.security.role', '角色管理', 'Role Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (15, 'menu.security.roleUser', '分配角色', 'Assigning Roles'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (16, 'menu.system.menu', '菜单管理', 'Menu Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (17, 'menu.security.dept', '部门管理', 'Department Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (18, 'menu.security.post', '岗位管理', 'Position Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (19, 'menu.system.dictType', '字典管理', 'Dictionary Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (20, 'menu.system.dictData', '字典数据', 'Dictionary Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (21, 'menu.system.paramSet', '参数设置', 'Parameter Settings'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (22, 'menu.system.systemLog', '系统日志', 'System Log'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (23, 'menu.system.systemInfo', '系统信息', 'System Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (24, 'menu.system.cacheInfo', '缓存信息', 'Cache Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (25, 'menu.system.cache', '缓存管理', 'Cache Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (26, 'menu.security.onlineUser', '在线用户', 'Online Users'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (27, 'menu.system.job', '调度任务', 'Scheduling Tasks'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (28, 'menu.system.jobLog', '调度日志', 'Scheduling Logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (29, 'menu.tools.help', '帮助文档', 'Help Documentation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (30, 'menu.log.operat', '操作日志', 'Operation logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (31, 'menu.log.login', '安全日志', 'Security logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (32, 'menu.security.userRemark', '用户管理菜单', 'User Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (33, 'menu.security.roleRemark', '角色管理菜单', 'Role Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (34, 'menu.security.roleUserRemark', '分配角色内嵌隐藏菜单', 'Assign Roles Embedded Hidden Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (35, 'menu.system.menuRemark', '菜单管理菜单', 'Menu Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (36, 'menu.security.deptRemark', '部门管理菜单', 'Department management menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (37, 'menu.security.postRemark', '岗位管理菜单', 'Job Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (38, 'menu.system.dictTypeRemark', '字典管理菜单', 'Dictionary management menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (39, 'menu.system.dictDataRemark', '字典数据内嵌隐藏菜单', 'Dictionary data embedded hidden menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (40, 'menu.system.paramSetRemark', '参数设置菜单', 'Parameter setting menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (41, 'menu.system.systemLogRemark', '系统日志目录', 'System Log Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (42, 'menu.system.systemInfoRemark', '系统信息菜单', 'System information menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (43, 'menu.system.cacheInfoRemark', '缓存信息菜单', 'Cache Information Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (44, 'menu.system.cacheRemark', '缓存列表菜单', 'Cache List Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (45, 'menu.security.onlineUserRemark', '在线用户菜单', 'Online User Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (46, 'menu.system.jobRemark', '调度任务菜单', 'Scheduling Tasks menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (47, 'menu.system.jobLogRemark', '调度日志内嵌隐藏菜单', 'Scheduling Log Embedded Hidden Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (48, 'menu.tools.helpRemark', '帮助文档菜单', 'Help file menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (49, 'menu.log.operatRemark', '操作日志菜单', 'Operation log menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (50, 'menu.log.loginRemark', '登录日志菜单', 'Login log menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (51, 'menu.common.query', '查询', 'Inquiry'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (52, 'menu.common.add', '新增', 'Add'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (53, 'menu.common.edit', '修改', 'Modify'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (54, 'menu.common.delete', '删除', 'Delete'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (55, 'menu.common.export', '导出', 'Export'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (56, 'menu.common.import', '导入', 'Import'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (57, 'menu.common.resetPwd', '重置密码', 'Reset Password'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (58, 'menu.common.unlock', '账户解锁', 'Account Unlock'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (59, 'menu.forcedQuit.batch ', '批量强退', 'Batch Undo'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (60, 'menu.forcedQuit.single', '单条强退', 'Individual Forced Retirement'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (61, 'menu.neData.udmAuth', 'UDM鉴权用户', 'UDM Authentication'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (62, 'menu.neData.udmSub', 'UDM签约用户', 'UDM Subscribers'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (63, 'menu.neData.udmVOIP', 'VOIP鉴权用户', 'VOIP Authentication'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (64, 'menu.neData.udmVolte', 'IMS签约用户', 'IMS Subscribers'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (65, 'menu.neData.imsSub', 'IMS在线用户', 'IMS Online Users'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (66, 'menu.neData.smfSub', 'UE在线信息', 'UE Online Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (67, 'menu.neData.baseOnline', '基站在线', 'Radio Online'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (68, 'menu.trace', '跟踪', 'Trace'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (69, 'menu.trace.task', '网元跟踪任务', 'NE Trace Task'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (70, 'menu.trace.taskData', '网元跟踪任务数据', 'NE Trace Task Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (71, 'menu.trace.pcap', '信令抓包', 'Signaling Capture'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (72, 'menu.fault', '监控', 'Monitor'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (73, 'config.neData.backupDataFTP', '备份网元数据-同步FTP服务', 'Backup NE Data - Sync Data FTP Service'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (74, 'config.neData.backupDataFTPRemark', '请通过系统页面进行设置FTP信息', 'Please set the FTP information through the system page.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (75, 'job.backup_export_table_sys_log_operate_remark', 'hour: 数据时间从任务执行时间前的小时数 +tableName: 数据表名 +columns: 支持字段 +backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time +tableName: data table name +columns: support fields +backupPath: backup output path /usr/local/omc/backup/{backupPath}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (76, 'job.backup_export_table_cdr_event_ims_remark', 'hour: 数据时间从任务执行时间前的小时数 +tableName: 数据表名 +columns: 支持字段 +backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time +tableName: data table name +columns: support fields +backupPath: backup output path /usr/local/omc/backup/{backupPath}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (77, 'job.backup_export_table_cdr_event_smf_remark', 'hour: 数据时间从任务执行时间前的小时数 +tableName: 数据表名 +columns: 支持字段 +backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time +tableName: data table name +columns: support fields +backupPath: backup output path /usr/local/omc/backup/{backupPath}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (78, 'menu.traceRemark', '跟踪管理目录', 'Tracking Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (79, 'menu.trace.taskRemark', '跟踪任务菜单', 'Tracking Task Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (80, 'config.sys.user.fristPasswdChange', '用户管理-首次登录密码修改', 'User Management-First Login Password Change'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (81, 'menu.trace.pcapRemark', '信令抓包菜单', 'Signaling Capture Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (82, 'menu.faultRemark', '故障管理目录', 'Fault Management Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (83, 'menu.fault.active', '活动告警', 'Active Alarms'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (84, 'menu.log', '日志', 'Logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (85, 'menu.log.mml', 'MML日志', 'MML Logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (86, 'menu.log.alarm', '告警日志', 'Alarm Logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (87, 'menu.log.forwarding', '告警前转日志', 'Alarm Forwarding Logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (88, 'menu.log.set', '日志设置', 'Log Settings'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (89, 'menu.monitor.sessionUser', '用户会话', 'User Sessions'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (90, 'menu.fault.history', '历史告警', 'Historical Alarms'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (91, 'menu.fault.set', '设置', 'Settings'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (92, 'menu.perf', '性能', 'Performance'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (93, 'menu.fault.activemRemark', '活动告警菜单', 'Active Alarm Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (94, 'menu.logRemark', '日志管理目录', 'Log Management Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (95, 'menu.log.operatOldRemark', '操作日志旧layui菜单', 'Operation log old layui menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (96, 'menu.log.mmlRemark', '操作MML日志', 'Operation MML Log'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (97, 'menu.log.alarmRemark', '告警日志菜单', 'Alarm Log Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (98, 'menu.log.securityOldRemark', '安全日志旧layui菜单', 'Security Log Old Layui Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (99, 'menu.log.forwardingRemark', '告警前转日志菜单', 'Alarm forward log menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (100, 'menu.log.setRemark', '日志设置菜单', 'Log Settings menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (101, 'menu.monitor.sessionUserRemark', '用户会话旧layui菜单', 'User Session Old Layui Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (102, 'menu.fault.historyRemark', '历史告警菜单', 'Alarm history menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (103, 'menu.fault.setRemark', '故障通用设置菜单', 'Fault General Setup Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (104, 'menu.perfRemark', '性能目录', 'Performance Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (105, 'menu.perf.task', '任务管理', 'Performance Tasks'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (106, 'menu.perf.data', '性能数据', 'Performance Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (107, 'menu.perf.kpiOverView', '关键指标概览', 'Key Performance Overview'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (108, 'menu.perf.threshold', '性能门限', 'Performance Thresholds'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (109, 'menu.perf.kpi', '关键指标', 'Key Performance Indicators'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (110, 'menu.perf.customTarget', '自定义指标', 'Custom Indicator Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (111, 'menu.perf.kpiKeyTarget', '关键指标报表', 'Key Performance Reports'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (112, 'menu.mml', 'MML', 'MML'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (113, 'menu.mml.ne', '网元操作', 'NE Operation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (114, 'menu.mml.udm', 'UDM操作', 'UDM Operation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (115, 'menu.mml.set', 'MML设置', 'MML Settings'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (116, 'menu.mml.omc', 'OMC操作', 'OMC Operation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (117, 'menu.perf.taskRemark', '任务管理菜单', 'Task Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (118, 'menu.perf.dataRemark', '性能数据菜单', 'Performance Data Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (119, 'menu.dashboard.smscCDR.content', '可见短信内容', 'Visible SMS content'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (120, 'menu.perf.thresholdRemark', '性能门限菜单', 'Performance Threshold Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (121, 'menu.perf.kpiRemark', '黄金指标菜单', 'Key Performance Indicator Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (122, 'menu.perf.customTargetRemark', '自定义指标菜单', 'Custom Indicator Management Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (123, 'menu.dashboard.smfCDRByIMSI', '数据流量报表', 'Data Usage Report'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (124, 'menu.mmlRemark', 'MML管理目录', 'MML Management Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (125, 'menu.mml.neRemark', '网元操作菜单', 'Network Element Operations Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (126, 'menu.mml.udmRemark', '网元UDM用户数据菜单', 'Network Element UDM User Data Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (127, 'menu.mml.setRemark', 'MML设置菜单', 'MML Setup Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (128, 'menu.mml.omcRemark', 'OMC操作菜单', 'OMC Operation Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (129, 'menu.dashboard.sgwcCDR', '漫游数据话单', 'Roaming Data CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (130, 'menu.security', '安全', 'Security'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (131, 'menu.system.systemSet', '系统设置', 'System Settings'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (132, 'menu.system.systemResource', '系统资源', 'System Resources'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (133, 'log.operate.title.sgwcCDR', '漫游数据话单', 'Roaming Data CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (134, 'menu.securityRemark', '安全管理目录', 'Security Management Catalog'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (135, 'menu.system.systemSetRemark', '系统设置菜单', 'System Settings Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (136, 'menu.system.systemResourceRemark', '系统资源 cpu io network菜单', 'System Resources cpu io network menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (137, 'dictData.offline', '离线', 'Offline'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (138, 'dictData.online', '在线', 'Online'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (139, 'menu.neData.baseStation', '基站状态', 'Radio State'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (140, 'menu.noData', '没有可访问菜单数据!', 'There is no accessible menu data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (141, 'menu.errNameExists', '操作菜单【{name}】失败,菜单名称已存在', 'Failed to operate menu [{name}], menu name already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (142, 'menu.errPathExists', '操作菜单【{name}】失败,菜单路由地址已存在', 'Failed to operate menu [{name}], menu routing address already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (143, 'menu.errFramePath', '操作菜单【{name}】失败,非内部地址请以http(s)://开头', 'Failed to manipulate menu [{name}], non-internal address should start with http(s)://'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (144, 'menu.errParentStatus', '上级菜单未启用!', 'The parent menu is not enabled!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (145, 'menu.errHasChildUse', '操作菜单【{name}】失败,存在使用子菜单数:{num}', 'Operation menu [{name}] failed, number of submenus in use exists: {num}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (146, 'menu.errHasRoleUse', '操作菜单【{name}】失败,菜单已分配给角色数:{num}', 'Operation menu [{name}] failed, number of roles the menu has been assigned to: {num}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (147, 'dictData.sex.un', '未选择', 'Not Selected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (148, 'dictData.sex.male', '男', 'Male'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (149, 'dictData.sex.female', '女', 'Female'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (150, 'dictData.show', '显示', 'Show'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (151, 'dictData.hide', '隐藏', 'Hide'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (152, 'dictData.normal', '正常', 'Active'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (153, 'dictData.disable', '停用', 'Inactive'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (154, 'dictData.yes', '是', 'Yes'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (155, 'dictData.no', '否', 'No'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (156, 'dictData.success', '成功', 'Successful'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (157, 'dictData.fail', '失败', 'Failed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (158, 'dictData.jobStatus.normal', '正常', 'Active'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (159, 'dictData.jobStatus.pause', '暂停', 'Inactive'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (160, 'dictData.jobGroup.Default', '默认', 'Default'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (161, 'dictData.jobGroup.System', '系统', 'System'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (162, 'dictData.operType.other', '其他', 'Other'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (163, 'dictData.operType.add', '新增', 'New'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (164, 'dictData.operType.edit', '修改', 'Modify'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (165, 'dictData.operType.delete', '删除', 'Delete'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (166, 'dictData.operType.auth', '授权', 'Authorization'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (167, 'dictData.operType.export', '导出', 'Export'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (168, 'dictData.operType.import', '导入', 'Import'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (169, 'dictData.operType.forced quit', '强退', 'Forced Retirement'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (170, 'dictData.operType.clear', '清空', 'Clear'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (171, 'dictData.trace.interface', '接口跟踪', 'Interface Tracing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (172, 'dictData.trace.device', '设备跟踪', 'Module Tracing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (173, 'dictData.trace.user', '用户跟踪', 'User Tracing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (174, 'nbState.export.id', '编号', 'ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (175, 'nbState.export.name', '基站名称', 'Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (176, 'nbState.export.position', '基站位置', 'Position'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (177, 'nbState.export.address', 'IP地址', 'IP Address'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (178, 'nbState.export.nbName', '设备名称', 'RanNodeName'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (179, 'nbState.export.ueNum', '在线用户数', 'UE Number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (180, 'nbState.export.state', '基站状态', 'State'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (181, 'nbState.export.time', '变更时间', 'Change Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (182, 'neHost.okBySSHLink', '设置免密直连成功', 'Setting up a password-free direct connection is successful'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (183, 'neHost.banNE', '禁止操作网元', 'Do not operate the NE'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (184, 'dictData.ne_host_type.redis', 'Redis', 'Redis'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (185, 'menu.tools.ping', '网络探测测试', 'Net Probing Test'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (186, 'menu.tools.iperf', '网络性能测试', 'Net Performance Test'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (187, 'dictData.jobSaveLog.no', '不记录', 'No Record'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (188, 'dictData.jobSaveLog.yes', '记录', 'Recorded'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (189, 'dictData.neVersionStatus.upload', '已上传', 'Uploaded'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (190, 'dictData.neVersionStatus.inactive', '未激活', 'Inactivated'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (191, 'dictData.neVersionStatus.active', '已激活', 'Activated'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (192, 'dictData.alarmStatus.history', '历史告警', 'Historical Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (193, 'dictData.alarmStatus.active', '活动告警', 'Active Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (194, 'dictData.export.code', '数据代码', 'Data Code'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (195, 'dictData.export.sort', '数据排序', 'Data Sort'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (196, 'dictData.export.label', '数据标签', 'Data Key'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (197, 'dictData.export.value', '数据键值', 'Data Value'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (198, 'dictData.export.type', '数据排序', 'Data Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (199, 'dictData.export.status', '数据状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (200, 'dictData.datascope.all', '全部数据权限', 'All data permissions'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (201, 'dictData.datascope.custom', '自定数据权限', 'Customized Data Rights'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (202, 'dictData.datascope.dept', '部门数据权限', 'Departmental Data Permissions'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (203, 'dictData.datascope.deptAndChid', '部门及以下数据权限', 'Department and below'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (204, 'dictData.datascope.self', '仅本人数据权限', 'Personal data access only'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (205, 'dictData.noData', '没有可访问字典编码数据!', 'There is no accessible dictionary code data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (206, 'dictData.errLabelExists', '操作数据【{name}】失败,该字典类型下标签名已存在', 'Failed to manipulate data [{name}], tag name already exists under this dictionary type!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (207, 'dictType.sys_user_sex', '用户性别', 'User Gender'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (208, 'dictType.sys_show_hide', '菜单状态', 'Menu Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (209, 'dictType.sys_normal_disable', '系统开关', 'System switches'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (210, 'dictType.sys_job_status', '任务状态', 'Task Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (211, 'dictType.sys_job_group', '任务分组', 'Task Grouping'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (212, 'dictType.sys_yes_no', '系统是否', 'System or not'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (213, 'dictType.sys_oper_type', '操作类型', 'Operation Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (214, 'dictType.sys_common_status', '系统状态', 'System Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (215, 'dictType.trace_type', '跟踪类型', 'Trace Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (216, 'menu.tools.ps', '进程运行程序', 'Process Running Program'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (217, 'dictType.alarm_status', '告警日志类型', 'Alarm Log Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (218, 'menu.tools.net', '进程网络连接', 'Process Net Connection'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (219, 'dictType.ne_version_status', '网元软件版本状态', 'Network element software version status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (220, 'dictType.sys_user_sex_remark', '用户性别列表', 'User gender list'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (221, 'dictType.sys_show_hide_remark', '菜单状态列表', 'Menu Status List'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (222, 'dictType.sys_normal_disable_remark', '系统开关列表', 'System switch list'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (223, 'dictType.sys_job_status_remark', '任务状态列表', 'Task Status List'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (224, 'dictType.sys_job_group_remark', '任务分组列表', 'Task Grouping List'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (225, 'dictType.sys_yes_no_remark', '系统是否列表', 'System whether list'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (226, 'dictType.sys_oper_type_remark', '操作类型列表', 'Operation type list'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (227, 'dictType.sys_common_status_remark', '登录状态列表', 'Login Status List'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (228, 'dictType.trace_type_remark', '跟踪类型', 'Trace Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (229, 'dictType.alarm_status_remark', '告警日志状态类型', 'Alarm Log Status Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (230, 'menu.trace.tshark', '信令分析', 'Signaling Analysis'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (231, 'menu.trace.wireshark', '信令跟踪', 'Signaling Trace'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (232, 'dictType.ne_version_status_remark', '网元软件版本状态', 'Network element software version status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (233, 'dictType.export.id', '字典编号', 'Dictionary Number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (234, 'dictType.export.name', '字典名称', 'Dictionary Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (235, 'dictType.export.type', '字典类型', 'Dictionary Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (236, 'dictType.export.status', '字典状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (237, 'dictType.sys_role_datascope', '系统角色数据范围', 'System Role Data Range'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (238, 'dictType.sys_role_datascope_remark', '系统角色数据范围映射', 'System Role Data Range Mapping'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (239, 'dictType.noData', '没有可访问字典类型数据!', 'There is no accessible dictionary type data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (240, 'dictType.errNameExists', '操作字典【{name}】失败,字典名称已存在', 'Failed to manipulate dictionary [{name}], dictionary name already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (241, 'dictType.errTypeExists', '操作字典【{name}】失败,字典类型已存在', 'Failed to manipulate dictionary [{name}], dictionary type already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (242, 'dept.root', '系统', 'System'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (243, 'dept.root.item1', '未分配', 'Unallocated'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (244, 'dept.noData', '没有可访问部门数据!', 'There is no accessible department data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (245, 'dept.errParentDelFlag', '上级部门【{name}】已删除,不允许新增', 'The parent department [{name}] has been deleted and is not allowed to be added.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (246, 'dept.errParentStatus', '上级部门【{name}】停用,不允许新增', 'Parent department [{name}] is deactivated, additions are not allowed!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (247, 'dept.errNameExists', '操作部门【{name}】失败,部门名称已存在', 'Manipulate department [{name}] failed, department name already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (248, 'dept.errParentID', '操作部门【{name}】失败,上级部门不能是自己', 'Failed to operate department [{name}], the parent department cannot be itself.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (249, 'dept.errHasChildUse', '操作失败,该部门包含未停用的子部门数量:{num}', 'Operation failed, the department contains undeactivated sub-departments number: {num}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (250, 'dept.errHasUserUse', '不允许删除,部门已分配给用户数:{num}', 'Deletion is not allowed, number of users the department has been assigned to: {num}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (251, 'config.sys.user.initPassword', '用户管理-账号初始密码', 'User Management-Account Initial Password'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (252, 'config.sys.account.captchaEnabled', '账号自助-验证码开关', 'Account self-help-Certification code switch'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (253, 'config.sys.account.registerUser', '账号自助-是否开启用户注册功能', 'Account self-service-Whether to enable the user registration function'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (254, 'config.sys.user.maxRetryCount', '用户管理-密码最大错误次数', 'User Management-Maximum number of password errors'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (255, 'config.sys.user.lockTime', '用户管理-密码锁定时间', 'User Management-Password Lock Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (256, 'config.monitor.sysResource.storeDays', '监控-系统资源-数据保留时长', 'Monitor-System Resources-Data retention time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (257, 'config.sys.logo.type', '系统设置-LOGO类型', 'System Settings-Logo Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (258, 'config.sys.logo.filePathIcon', '系统设置-LOGO文件icon', 'System Settings-Logo File icon'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (259, 'config.sys.logo.filePathBrand', '系统设置-LOGO文件brand', 'System Settings-Logo File Brand'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (260, 'config.sys.loginBackground', '系统设置-登录界面背景', 'System Settings-Login Interface Background'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (261, 'config.sys.title', '系统设置-系统名称', 'System Settings-System Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (262, 'config.sys.copyright', '系统设置-版权声明', 'System Settings-Copyright Notice'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (263, 'config.sys.user.initPasswordRemark', '导入用户初始化密码', 'Import user initialization password'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (264, 'config.sys.account.captchaEnabledRemark', '是否开启验证码功能(true开启,false关闭)', 'Whether to enable the verification code function (true on, false off)'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (265, 'config.sys.account.registerUserRemark', '是否开启注册用户功能(true开启,false关闭)', 'Whether to enable the function of registered users (true on, false off)'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (266, 'config.sys.user.maxRetryCountRemark', '密码最大错误次数', 'Maximum number of password errors'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (267, 'config.sys.user.lockTimeRemark', '密码锁定时间,单位分钟(默认10分钟)', 'Password lock time in minutes (default 10 minutes)'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (268, 'config.monitor.sysResource.storeDaysRemark', '监控-系统资源-数据保留时长,单位天。根据当前日期,删除超过保留时长的日期数据信息。', 'Monitor-System Resources-Data retention time, in days. According to the current date, delete the date data information that exceeds the retention time.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (269, 'config.sys.logo.typeRemark', '全图:brand +小图:icon', 'Full image: brand +Small image: icon'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (270, 'config.sys.logo.filePathIconRemark', '文件支持网络地址图片和内部上传的文件路径', 'File support for web address images and file paths for internal uploads'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (271, 'config.sys.logo.filePathBrandRemark', '文件支持网络地址图片和内部上传的文件路径', 'File support for web address images and paths to internally uploaded files'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (272, 'config.sys.loginBackgroundRemark', '文件支持网络地址图片和内部上传的文件路径,默认背景用#号', 'The file supports web address images and internal upload file paths with a # in the default background'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (273, 'config.sys.titleRemark', '系统名称长度限制20位字符串', 'System name length limit of 20-digit string'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (274, 'config.sys.copyrightRemark', '底脚固定条,左侧放置版权声明', 'Footer fixing strip with copyright notice on the left side'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (275, 'config..export.id', '参数编号', 'ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (276, 'config..export.name', '参数名称', 'Config Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (277, 'config..export.key', '参数键名', 'Config Key'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (278, 'config..export.value', '参数键值', 'Config Value'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (279, 'config..export.type', '系统内置', 'Built In'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (280, 'config..export.remark', '参数说明', 'Config Description'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (281, 'config.sys.titleValue', 'Core Network', 'Core Network'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (282, 'config.sys.copyrightValue', 'Copyright ©2025 Core Network', 'Copyright ©2025 Core Network'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (283, 'config.noData', '没有可访问参数配置数据!', 'No parameter configuration data is accessible!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (284, 'config.errKey', '无效 key', 'Invalid key'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (285, 'config.errValueEq', '变更状态与旧值相等!', 'Change state is equal to the old value!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (286, 'config.errKeyExists', '操作参数配置【{name}】失败,参数键名已存在', 'Failed to manipulate parameter configuration [{name}], parameter key name already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (287, 'config.errDelete', '删除参数配置信息失败!', 'Deletion of parameter configuration information failed!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (288, 'config.errType', '操作含有内置参数,禁止删除!', 'The operation contains built-in parameters and deletion is prohibited!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (289, 'job.monitor_sys_resource', '监控-系统资源', 'Monitor-System Resources'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (290, 'job.monitor_sys_resource_remark', '系统资源CPU/IO/Netword收集 +interval单位分钟,平均分钟资源情况 +注:请根据cron表达式的时间单位分钟,传入参数interva值', 'System Resource CPU/IO/Netword Collection +interval unit minutes, average minute resource situation +Note: Please pass the value of the parameter interva according to the time unit minutes of the cron expression'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (291, 'job.delete_ne_config_backup', '删除-过期配置文件备份', 'Delete-Expired NE ETC Backup File'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (292, 'job.delete_ne_config_backup_remark', 'storeDays:表示保留最近天数的数据记录', 'storeDays: indicates that the most recent days of data records are kept.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (293, 'job.delete_alarm_record', '删除-过期告警记录', 'Delete-Expired Alarm Records'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (294, 'job.delete_alarm_record_remark', 'storeDays:表示保留最近天数的数据记录 +storeNum:保留数量,默认保留7个', 'storeDays: indicates that the most recent days of data records are kept. +storeNum: the number of reservations, the default reservation is 7.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (295, 'job.delete_kpi_record', '删除-过期指标记录', 'Delete-Expired KPI Records'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (296, 'job.delete_kpi_record_remark', 'storeDays:表示保留最近天数的数据记录 +neList:表示匹配的网元类型', 'storeDays: Indicates the most recent days of data records retained +neList: Indicates the type of network elements matched'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (297, 'menu.neData.backupData', '导出文件', 'Exponted File'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (298, 'config.sys.user.passwordPolicyNot', '未配置密码策略', 'Password policy not configured'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (299, 'job.export.jobID', '任务编号', 'ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (300, 'job.export.jobName', '任务名称', 'Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (301, 'job.export.jobGroupName', '任务组名', 'Group'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (302, 'job.export.invokeTarget', '调用目标', 'Invoke'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (303, 'job.export.targetParams', '传入参数', 'Incoming Parameters'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (304, 'job.export.cronExpression', 'cron表达式', 'Cron'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (305, 'job.export.status', '状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (306, 'job.export.remark', '备注说明', 'Description'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (307, 'job.export.jobLogID', '任务日志编号', 'ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (308, 'job.export.jobLogStatus', '任务日志状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (309, 'job.export.jobLogTime', '任务日志时间', 'Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (310, 'job.noData', '没有可访问调度任务数据!', 'There is no accessible scheduling task data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (311, 'job.errTargetParams', '操作调度任务【{name}】失败,任务传入参数json字符串不正确', 'Failed to operate scheduling task [{name}] with incorrect task incoming parameter json string!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (312, 'job.errCronExpression', '操作调度任务【{name}】失败,Cron表达式不正确', 'Scheduled task [{name}] failed with incorrect Cron expression!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (313, 'job.errJobExists', '调度任务新增【{name}】失败,同任务组内有相同任务名称', 'Failed to add a new task [{name}] to a scheduling task, same task name in the same task group'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (314, 'job.statusEq', '变更状态与旧值相等!', 'The change state is equal to the old value!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (315, 'role.system', '系统', 'System'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (316, 'role.admin', '管理人员', 'Administrator'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (317, 'role.operator', '运维人员', 'Operators'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (318, 'role.monitor', '监控人员', 'Monitor'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (319, 'role.vistor', '普通用户', 'General Users'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (320, 'role.systemRemark', '系统,无法修改删除', 'System, cannot modify or delete'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (321, 'role.adminRemark', '管理人员 可以对设备进行任何操作', 'Administrators can perform any operation on the device'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (322, 'role.operatorRemark', '运维人员 可以从设备读取数据,并对设备进行配置,但是不能对设备进行软件升级操作。', 'Operation and maintenance personnel can read data from the device and configure the device, but cannot perform software upgrade operations on the device.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (323, 'role.monitorRemark', '监控人员 只能从设备读取数据,而不能对设备进行任何设置', 'Monitoring personnel Can only read data from the device, but cannot make any settings on the device'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (324, 'role.vistorRemark', '普通用户 只可看系统相关信息', 'Ordinary users can only see system-related information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (325, 'role.export.id', '角色编号', 'Role Number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (326, 'role.export.name', '角色名称 ', 'Role Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (327, 'role.export.key', '角色键值', 'Role Key'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (328, 'role.export.sort', '角色顺序', 'Role Sort'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (329, 'role.export.dataScope', '角色数据范围', 'Role Data Range'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (330, 'role.export.status', '角色状态', 'Role Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (331, 'role.noData', '没有可访问角色数据!', 'There is no accessible role data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (332, 'role.statusEq', '变更状态与旧值相等!', 'The change status is equal to the old value!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (333, 'role.errNameExists', '操作角色【{name}】失败,角色名称已存在', 'Manipulating role [{name}] failed, role name already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (334, 'role.errKeyExists', '操作角色【{name}】失败,角色键值已存在', 'Failed to manipulate role [{name}], role key already exists!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (335, 'post.admin', '系统', 'Systems'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (336, 'post.operator', '管理', 'Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (337, 'post.monitor', '运维', 'Operation & Maintenance'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (338, 'post.visitor', '监控', 'Monitoring'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (339, 'post.export.id', '岗位编号 ', 'Position Number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (340, 'post.export.code', '岗位编码', 'Position Code'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (341, 'post.export.name', '岗位名称', 'Position Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (342, 'post.export.sort', '岗位排序', 'Position Sort'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (343, 'post.export.status', '岗位状态', 'Position Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (344, 'post.noData', '没有可访问岗位数据!', 'There is no accessible post data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (345, 'post.errNameExists', '操作岗位【{name}】失败,岗位名称已存在已存在', 'Failed to manipulate post [{name}], post name already exists already exists'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (346, 'post.errCodeExists', '操作角色【{name}】失败,角色键值已存在', 'Failed to manipulate role [{name}], role key already exists.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (347, 'user.export.id', '用户编号', 'User Number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (348, 'user.export.name', '登录账号', 'Account'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (349, 'user.export.nick', '用户昵称', 'Nick Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (350, 'user.export.email', '电子邮箱', 'E-Mail'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (351, 'user.export.phone', '手机号码', 'Cell phone number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (352, 'user.export.sex', '用户性别', 'Gender'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (353, 'user.export.status', '用户状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (354, 'user.export.deptID', '部门编号', 'Department number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (355, 'user.export.deptName', '部门名称', 'Department'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (356, 'user.export.deptLeader', '部门负责人', 'Department Head'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (357, 'user.export.loginIP', '用户登录IP', 'Login Address'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (358, 'user.export.loginDate', '用户登录时间', 'Login Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (359, 'user.noData', '没有可访问用户数据!', 'No accessible user data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (360, 'user.statusEq', '变更状态与旧值相等!', 'The change status is equal to the old value!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (361, 'user.errPasswdOld', '修改密码失败,旧密码错误', 'Change password failed, old password is wrong'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (362, 'user.errPasswdEqOld', '新密码不能与旧密码相同', 'New password cannot be the same as the old one'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (363, 'config.sys.user.passwordPolicyError', '密码至少{minLength}位,至少包含{specialChars}个特殊字符和至少{uppercase}个大写字母和至少{lowercase}个小写字母', 'Passwords are at least {minLength} digits long and contain at least {specialChars} special characters and at least {uppercase} uppercase letter and at least {lowercase} lowercase letter.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (364, 'user.errEmailFormat', '操作用户【{name}】失败,邮箱格式错误', 'Failed to operate user [{name}], mailbox format error'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (365, 'user.errEmailExists', '操作用户【{name}】失败,邮箱已存在', 'Failed to operate user [{name}], mailbox already exists.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (366, 'user.errPhoneFormat', '操作用户【{name}】失败,手机号码格式错误', 'Failed to operate user [{name}], cell phone number format is wrong.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (367, 'user.errPhoneExists', '操作用户【{name}】失败,手机号码已存在', 'Failed to operate user [{name}], cell phone number already exists.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (368, 'user.errNameExists', '操作用户【{name}】失败,登录账号已存在', 'Failed to operate user [{name}], login account already exists.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (369, 'user.import.mustItem', '表格中必填列表项,{text}', 'Required list item in form, {text}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (370, 'user.import.phoneExist', '用户编号:{id} 手机号码 {phone} 已存在', 'User ID: {id} cell phone number {phone} Existing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (371, 'user.import.phoneFormat', '用户编号:{id} 手机号码 {phone} 格式错误', 'User ID: {id} cell phone number {phone} Wrong format'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (372, 'user.import.emailExist', '用户编号:{id} 用户邮箱:{email} 已存在', 'User ID: {id} User Email: {email} Existing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (373, 'user.import.emailFormat', '用户编号:{id} 用户邮箱:{email} 格式错误', 'User ID: {id} Email: {email} Wrong Format'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (374, 'user.import.success', '用户编号:{id} 登录名称:{name} 导入成功', 'User ID:{id} Login name:{name} Imported successfully!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (375, 'user.import.fail', '用户编号:{id} 登录名称:{name} 导入失败', 'User ID: {id} Login name: {name} Import failed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (376, 'user.import.successUpdate', '用户编号:{id} 登录名称:{name} 更新成功', 'User ID: {id} Login name: {name} Update success'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (377, 'user.import.failUpdate', '用户编号:{id} 登录名称:{name} 更新失败', 'User ID: {id} Login Name: {name} Update Failed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (378, 'user.import.failTip', '很抱歉,导入失败!共 {num} 条数据格式不正确,错误如下:', 'Sorry, the import failed! A total of {num} entries were not formatted correctly, the error is below:'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (379, 'user.import.successTip', '恭喜您,数据已全部导入成功!共 {num} 条,数据如下:', 'Congratulations, the data has been imported successfully! There are {num} entries with the following data:'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (380, 'app.common.err403', '无权访问 {method} {requestURI}', 'Unauthorized access {method} {requestURI}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (381, 'app.common.err401', '无效身份授权', 'Invalid authorization'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (382, 'app.common.err400', '参数错误', 'Parameter error'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (383, 'app.common.exportEmpty', '导出数据记录为空', 'Export data record is empty'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (384, 'app.common.errOperateAdmin', '不允许操作内置用户', 'Built-in users are not allowed to operate'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (385, 'app.common.errOperateRole', '不允许操作内置角色', 'Built-in roles are not allowed to be operated'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (386, 'app.common.deleteSuccess', '删除成功:{num}', 'Deleted successfully: {num}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (387, 'app.common.loginSuccess', '登录成功', 'Login Success'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (388, 'app.common.logoutSuccess', '注销成功', 'Logout Successful'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (389, 'app.common.errUnlock', '该用户未被锁定', 'The user is not locked'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (390, 'app.common.noLoginUser', '登录用户信息无效', 'Invalid login user information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (391, 'app.common.rateLimitTip', '访问过于频繁,请稍候再试', 'Access too often, please try again later'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (392, 'log.operate.export.id', '操作编号', 'Log ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (393, 'log.operate.export.title', '模块名称', 'Module Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (394, 'log.operate.export.businessType', '业务类型', 'Business Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (395, 'log.operate.export.method', '操作方法', 'Operation Method'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (396, 'log.operate.export.requestMethod', '请求方式 ', 'Request Method'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (397, 'log.operate.export.operatorType', '操作类型', 'Operation Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (398, 'log.operate.export.operName', '操作人员', 'Operator'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (399, 'log.operate.export.deptName', '操作人员部门名称', 'Operator Department Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (400, 'log.operate.export.url', '请求链接地址', 'Request URL'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (401, 'log.operate.export.ip', '请求主机 ', 'Request Host'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (402, 'log.operate.export.location', '请求地址', 'Request Address'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (403, 'log.operate.export.param', '请求参数', 'Request Parameters'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (404, 'log.operate.export.msg', '操作信息', 'Operation Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (405, 'log.operate.export.status', '操作状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (406, 'log.operate.export.costTime', '消耗时间(毫秒)', 'Time Consumption (ms)'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (407, 'log.operate.export.operTime', '操作时间', 'Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (408, 'log.login.export.id', '记录编号', 'Log ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (409, 'log.login.export.userName', '登录账号', 'Login Account'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (410, 'log.login.export.status', '登录状态', 'Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (411, 'log.login.export.ip', '登录地址', 'Login Address'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (412, 'log.login.export.location', '登录地点', 'Login Location'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (413, 'log.login.export.browser', '浏览器', 'Browser'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (414, 'log.login.export.os', '操作系统', 'Operating System'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (415, 'log.login.export.msg', '登录信息', 'Login Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (416, 'log.login.export.time', '登录时间', 'Login Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (417, 'trace.tcpdump.noData', '找不到 {type} {id} 对应网元信息', 'Can it find {type} {id} information of the corresponding network element.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (418, 'register.errUsername', '账号不能以数字开头,可包含大写小写字母,数字,且不少于5位', 'The account number cannot start with a number, but can contain upper and lower case letters, numbers, and not less than 5 digits.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (419, 'login.errPasswdExpire', '登录密码已过期', 'Login password has expired'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (420, 'register.errPasswdNotEq', '用户确认输入密码不一致', 'User confirms password inconsistency'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (421, 'register.success', '注册成功', 'Successful registration'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (422, 'register.successMsg', '{name} 注册成功 {id}', '{name} Register Successful {id}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (423, 'log.operate.title.sysJobLog', '调度任务日志', 'Scheduling Task Logs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (424, 'log.operate.title.sysJob', '调度任务', 'Scheduling Tasks'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (425, 'log.operate.title.tcpdump', '信令抓包', 'Signaling Capture'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (426, 'log.operate.title.sysConfig', '参数配置', 'Parameter Configuration'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (427, 'log.operate.title.sysDept', '部门', 'Sector'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (428, 'log.operate.title.sysDictData', '字典数据', 'Dictionary Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (429, 'log.operate.title.sysDictType', '字典类型', 'Dictionary type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (430, 'log.operate.title.sysMenu', '菜单', 'Menu'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (431, 'log.operate.title.sysPost', '岗位', 'Positions'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (432, 'log.operate.title.sysProfile', '个人信息', 'Personal Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (433, 'log.operate.title.sysProfileAvatar', '个人头像', 'Personal avatar'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (434, 'log.operate.title.sysRole', '角色', 'Roles'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (435, 'log.operate.title.sysUser', '用户', 'User'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (436, 'log.operate.title.sysLogOper', '操作日志记录', 'Operation Logging'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (437, 'log.operate.title.sysLogLogin', '登录日志记录', 'Operation Logging'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (438, 'login.errNameOrPasswd', '用户不存在或密码错误', 'User does not exist or password is wrong'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (439, 'login.errDelFlag', '对不起,您的账号已被删除', 'Sorry, your account has been deleted'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (440, 'login.errStatus', '对不起,您的帐户已被禁用', 'Sorry, your account has been disabled'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (441, 'login.errRetryPasswd', '密码输入错误多次,帐户已被锁定', 'Password was entered incorrectly several times, account has been locked'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (442, 'captcha.err', '验证码错误', 'Captcha Error'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (443, 'captcha.errValid', '验证码已失效', 'Captcha is invalid'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (444, 'app.common.noUaOsBrowser', '未知 未知', 'Unknown Unknown'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (445, 'app.common.noIPregion', '内网', 'Intranet'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (446, 'app.common.unknown', '未知', 'Unknown'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (447, 'app.common.noNEInfo', '未找到匹配网元信息', 'No matching network element information found'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (448, 'ne.udm.errImportUserAuthFileFormat', '请上传.csv或.txt的格式文件。英文逗号分割txt格式:imsi, ki, algo, amf, opc', 'Please upload a file in the format of. csv or. txt. English comma separated txt format: imsi, ki, algo, amf, opc'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (449, 'ne.udm.errExportType', '导出文件类型支持CSV和txt', 'Export file types support CSV and txt'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (450, 'ne.udm.errImportUserSubFileFormat', '请上传.csv或.txt的格式文件。英文逗号分割txt格式:imsi, msisdn, ambr, nssai, arfb, sar, rat, cn, smf_sel, sm_dat, eps_dat', 'Please upload files in .csv or .txt format. English comma-separated txt format: imsi, msisdn, ambr, nssai, arfb, sar, rat, cn, smf_sel, sm_dat, eps_dat'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (451, 'log.operate.title.udmAuth', 'UDM鉴权用户', 'UDM Authentication'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (452, 'log.operate.title.udmSub', 'UDM签约用户', 'UDM Subscriber'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (453, 'dictType.active_alarm_type', '活动告警类型', 'Event Alarm Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (454, 'dictType.active_alarm_type_remark', '活动告警类型列表', 'List of Active Alarm Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (455, 'dictData.active_alarm_type.communication', '通信告警', 'Communication Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (456, 'dictData.active_alarm_type.equipment', '设备告警', 'Equipment Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (457, 'dictData.active_alarm_type.processing', '处理错误', 'Processing Failure Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (458, 'dictData.active_alarm_type.environmental', '环境告警', 'Environmental Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (459, 'dictData.active_alarm_type.qualityOfService', '服务质量', 'Quality of Service Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (460, 'dictType.active_clear_type', '告警清除类型', 'Alarm Clearing Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (461, 'dictType.active_clear_type_remark', '告警清除类型列表', 'List of Alarm Clearing Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (462, 'dictData.active_clear_type.notCleared', '告警未清除', 'Not cleared'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (463, 'dictData.active_clear_type.hand', '手动清除', 'Manually cleared'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (464, 'dictData.active_clear_type.auto', '自动清除', 'Automatically cleared'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (465, 'dictType.active_ack_state', '告警确认类型', 'Alarm Acknowledgement Types'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (466, 'dictType.active_ack_state_remark', '告警确认类型列表', 'Alarm Acknowledgement Type List'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (467, 'dictData.active_ack_state.unconfirmed', '未确认', 'Not Confirm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (468, 'dictData.active_ack_state.confirmed', '已确认', 'Confirm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (469, 'dictType.active_alarm_severity', '严重程度', 'Severity'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (470, 'dictType.active_alarm_severity_remark', '严重程度列表', 'Severity List'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (471, 'dictData.active_alarm_severity.critical', '严重告警', 'Critical'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (472, 'dictData.active_alarm_severity.major', '主要告警', 'Major'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (473, 'dictData.active_alarm_severity.minor', '次要告警', 'Minor'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (474, 'dictData.active_alarm_severity.warning', '警告告警', 'Warning'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (475, 'dictData.active_alarm_severity.event', '事件告警', 'Event'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (476, 'config.sys.officialUrl', '系统设置-官网链接', 'System Settings - Official Website Links'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (477, 'config.sys.helpDoc', '系统设置-系统使用文档', 'System Settings-System Documentation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (478, 'config.sys.officialUrlRemark', '默认无地址用#号', 'Default no address with # sign'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (479, 'config.sys.helpDocRemark', '静态文件目录地址,使用{language}区分语言文件', 'Static file directory address, use {language} to distinguish language files'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (480, 'log.operate.title.neAction', '网元处理', 'Network Element Processing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (481, 'log.operate.title.helpDoc', '系统使用文档', 'System Usage Documentation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (482, 'menu.ueUser.n3iwf', 'N3IWF在线用户', 'N3IWF Online User'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (483, 'menu.neData.pcfSub', '用户策略控制信息', 'User PCC Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (484, 'menu.system.user.editRole', '修改用户角色', 'Modifying User Role'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (485, 'config.sys.i18nOpen', '国际化切换', 'Internationalization Switching'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (486, 'config.sys.i18nDefault', '国际化默认语言', 'Internationalization Default Language'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (487, 'user.export.role', '用户角色', 'Role'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (488, 'menu.system.setting.i18n', '国际化切换', 'Internationalization Switch'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (489, 'menu.system.setting.i18nRemark', '国际化多语言的切换选择', 'Internationalized multilingual switching options'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (490, 'dictType.index_status', '首页状态', 'Home Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (491, 'dictType.index_status_remark', '首页的网元状态颜色', 'Network element status colors on the home page'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (492, 'dictType.index_status.normal', '正常', 'Normal'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (493, 'dictType.index_status.abnormal', '异常', 'Abnormal'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (494, 'menu.log.neFile', '网元日志文件', 'NE Log File'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (495, 'menu.dashboard.overview.smfUeNum', '展示数据会话数', 'Display data session number'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (496, 'menu.dashboard.overview.imsUeNum', '展示语音会话数', 'Display the number of voice sessions'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (497, 'menu.dashboard.overview.gnbBase', '展示5G基站在线信息', 'Display 5G base station online information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (498, 'menu.dashboard.overview.enbBase', '展示4G基站在线信息', 'Display 4G base station online information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (499, 'job.ne_alarm_state_check', '网元告警-状态检查', 'NE Alarm-Health State Check'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (500, 'job.ne_alarm_state_check_remark', '检查网元的健康状况,在出现异常时发出警报。 + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4', 'Checks the health of network elements and sends alerts in case of anomalies. + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (501, 'menu.neUser.nssf', 'NSSF在线订阅数', 'NSSF Subscription Info'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (502, 'menu.neUser.nssfAmf', 'NSSF可用的注册AMF', 'NSSF Available AMFs'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (503, 'menu.monitor.topology', '拓扑信息', 'Topology Info'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (504, 'menu.monitor.topologyBuild', '拓扑图组编辑', 'Topological Graph Build'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (505, 'log.operate.title.chartGraph', '拓扑图组', 'Topological Graph'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (506, 'menu.monitor.topologyArchitecture', '网元拓扑组网', 'NE System Topology'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (507, 'menu.alarm', '告警', 'Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (508, 'menu.topology', '拓扑', 'Topology'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (509, 'config.sys.lockTime', '系统设置-锁屏超时时长', 'System Settings - Screen Lock Timeout Duration'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (510, 'config.sys.lockTimeRemark', '无操作时锁屏超时时长,单位(秒)。0表示无锁屏超时', 'Timeout of lock screen when no operation, unit (sec), 0 means no timeout of lock screen'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (511, 'sys.account.captchaType', '账号自助-验证码类型', 'Account Self Service - Captcha Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (512, 'sys.account.captchaTypeRemark', '使用验证码类型(math数值计算,char字符验证)', 'Using CAPTCHA types (math numeric calculation, char character validation)'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (513, 'menu.dashboard', '仪表盘', 'Dashboard'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (514, 'menu.dashboard.overview', '总览', 'Overview'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (515, 'menu.dashboard.imsCDR', '语音话单', 'Voice CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (516, 'dictType.cdr_sip_code', 'IMS-Voice-SIP响应代码类别类型', 'IMS-Voice-SIP Response Code Category Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (517, 'dictType.cdr_call_type', 'IMS-呼叫类型', 'IMS-Call Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (518, 'dictType.ue_auth_code', 'UE 事件认证代码类型', 'UE Event Authentication Code Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (519, 'dictType.ue_event_type', 'UE 事件类型', 'UE Event Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (520, 'dictData.cdr_sip_code.200', '200 正常通话', '200 OK'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (521, 'dictData.cdr_sip_code.403', '403 禁止访问', '403 Forbidden'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (522, 'dictData.cdr_sip_code.408', '408 请求超时', '408 Request Timeout'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (523, 'dictData.cdr_sip_code.500', '500 内部服务器错误', '500 Internal Server Error'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (524, 'dictData.cdr_call_type.audio', '语音', 'Voice'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (525, 'dictData.cdr_call_type.video', '视频', 'Video'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (526, 'dictData.ue_auth_code.200', '成功', 'Success'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (527, 'dictData.ue_auth_code.001', '网络失败', 'Network Failure'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (528, 'dictData.ue_auth_code.002', '接口失败', 'Interface Failure'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (529, 'dictData.ue_auth_code.003', 'MAC失败', 'MAC Failure'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (530, 'dictData.ue_auth_code.004', '同步失败', 'Synchronization failure'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (531, 'dictData.ue_auth_code.005', '不接受非5G认证', 'Non-5G Authentication Not Accepted'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (532, 'dictData.ue_auth_code.006', '响应失败', 'Response Failure'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (533, 'dictData.ue_auth_code.007', '未知', 'Unknown'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (534, 'dictData.ue_event_type.auth', '认证', 'Authentication'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (535, 'dictData.ue_event_type.detach', '注销', 'Detach'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (536, 'dictData.ue_event_type.state', 'CM状态', 'CM Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (537, 'dictType.ue_event_cm_state', 'UE 事件CM状态', 'UE Event CM Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (538, 'dictData.ue_event_cm_state.connected', '连接', 'Connected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (539, 'dictData.ue_event_cm_state.idle', '空闲', 'Idle'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (540, 'dictData.ue_event_cm_state.inactive', '不活动', 'Inactive'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (541, 'dictData.cdr_sip_code.404', '404 找不到', '404 Not Found'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (542, 'dictData.cdr_sip_code.487', '487 请求已终止', '487 Request Terminated'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (543, 'dictData.cdr_sip_code.503', '503 服务不可用', '503 Service Unavailable'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (544, 'dictData.cdr_sip_code.504', '504 服务器超时', '504 Server Timeout'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (545, 'dictData.cdr_sip_code.603', '603 拒绝', '603 Decline'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (546, 'dictData.cdr_sip_code.606', '606 不可接受', '606 Not Acceptable'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (547, 'cache.name.token', '用户令牌', 'User Token'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (548, 'cache.name.sys_config', '参数管理', 'Parameters Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (549, 'cache.name.sys_dict', '字典管理', 'Dictionary Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (550, 'cache.name.captcha_codes', '验证码', 'Captcha'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (551, 'cache.name.repeat_submit', '防重提交', 'Resubmit'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (552, 'cache.name.rate_limit', '限流', 'Limit Traffic'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (553, 'cache.name.pwd_err_cnt', '登录账户密码错误次数', 'Number of Password Errors'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (554, 'cache.name.ne_info', '网元信息管理', 'NE Info Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (555, 'cache.name.ne_data', '网元数据管理', 'NE Data Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (556, 'dictData.cdr_call_type.sms', '短信', 'SMS'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (557, 'dictData.cdr_sip_code.202', '202 已接受', '202 Accepted'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (558, 'dictData.cdr_sip_code.488', '488 这里不接受', '488 Not Acceptable Here'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (559, 'dictData.cdr_sip_code.0', '0 原因不明', '0 Unknown Reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (560, 'log.operate.title.ws', 'WS会话', 'WS Sessions'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (561, 'log.operate.title.neHost', '网元主机', 'NE Host'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (562, 'neHost.noData', '没有可访问主机信息数据!', 'There is no accessible host information data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (563, 'neHost.errKeyExists', '主机信息操作【{name}】失败,同组内名称已存在', 'Host information operation [{name}] failed, name already exists in the same group'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (564, 'neHost.errByHostInfo', '连接失败,请检查连接参数后重试', 'Connection Failed, Please check connection parameters and retry'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (565, 'dictType.ne_host_type', '网元主机连接类型', 'Network element host connection type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (566, 'dictType.ne_host_groupId', '网元主机分组', 'Network element host grouping'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (567, 'dictType.ne_host_authMode', '网元主机认证模式', 'Network element host authentication mode'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (568, 'dictData.ne_host_type.ssh', 'SSH', 'SSH'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (569, 'dictData.ne_host_type.telnet', 'Telnet', 'Telnet'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (570, 'dictData.ne_host_groupId.0', '其他', 'Other'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (571, 'dictData.ne_host_groupId.1', '网元', 'Network Elements'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (572, 'dictData.ne_host_groupId.2', '系统', 'System'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (573, 'dictData.ne_host_authMode.0', '密码认证', 'Password Authentication'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (574, 'dictData.ne_host_authMode.1', '私钥认证', 'Private key authentication'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (575, 'menu.tools.terminal', '主机终端', 'Host Terminal'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (576, 'menu.ne.neHost', '网元主机', 'NE Host'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (577, 'menu.ne.neHostCommand', '网元主机命令', 'NE Host CMD'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (578, 'log.operate.title.neHostCmd', '网元主机命令', 'NE Host CMD'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (579, 'neHostCmd.noData', '没有可访问主机命令数据!', 'No accessible host command data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (580, 'neHostCmd.errKeyExists', '主机命令操作【{name}】失败,同组内名称已存在', 'Host command operation [{name}] failed, name already exists in the same group'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (581, 'dictType.ne_host_cmd_groupId', '网元主机命令分组', 'Network element host command grouping'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (582, 'dictData.ne_host_cmd_groupId.0', '默认', 'Default'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (583, 'dictData.ne_host_cmd_groupId.1', '快速命令', 'Quick Commands'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (584, 'menu.ne.neInfo', '网元信息', 'NE Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (585, 'log.operate.title.neInfo', '网元信息', 'NE Information'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (586, 'neInfo.noData', '没有可访问网元信息数据!', 'There is no accessible network element information data!'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (587, 'neInfo.errKeyExists', '网元信息操作【{key}】失败,同类型下标识已存在', 'NE info operation [{key}] failed, identifier already exists under the same type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (588, 'log.operate.title.imsCDR', '通话话单', 'Voice CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (589, 'menu.dashboard.amfUE', '5G 终端事件', '5G UE Events'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (590, 'log.operate.title.amfUE', '5G 终端事件', '5G UE Events'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (591, 'dictData.ne_info_status.0', '离线', 'Offline'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (592, 'dictData.ne_info_status.1', '在线', 'Active'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (593, 'dictData.ne_info_status.2', '等待同步', 'Wait Sync'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (594, 'dictData.ne_info_status.3', '待机', 'Standby'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (595, 'dictType.ne_info_status', '网元信息状态', 'NE Info State'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (596, 'menu.ne.neQuickSetup', '网元快速安装', 'NE Quick Setup'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (597, 'log.operate.title.neConfig', '网元参数配置', 'NE Parameter Configuration'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (598, 'menu.ne.neLicense', '网元许可', 'NE License'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (599, 'log.operate.title.neLicense', '网元许可', 'NE License'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (600, 'menu.ne.neSoftware', '网元软件包', 'NE Software'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (601, 'log.operate.title.neSoftware', '网元软件包', 'NE Software'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (602, 'log.operate.title.neVersion', '网元版本', 'NE Version'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (603, 'menu.ne.neVersion', '网元版本', 'Ne Version'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (604, 'dictType.ne_license_status', '网元许可状态', 'NE License Status'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (605, 'dictData.ne_license_status.0', '无效', 'Invalid'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (606, 'dictData.ne_license_status.1', '有效', 'Valid'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (607, 'menu.dashboard.mocn', 'MOCN', 'MOCN'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (608, 'menu.monitor.cdr', '话单', 'CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (609, 'menu.monitor.event', '事件', 'Events'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (610, 'post.export.time', '创建时间', 'Creation Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (611, 'role.export.time', '创建时间', 'Creation Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (612, 'dictData.ne_host_authMode.2', '免密认证', 'Confidentiality Auth Mode'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (613, 'menu.ne.neConfig', '网元配置', 'NE Config'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (614, 'dictData.ne_version_status.0', '无', 'Nothing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (615, 'dictData.ne_version_status.1', '已是最新', 'Updated'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (616, 'dictData.ne_version_status.2', '上一版本', 'Previous'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (617, 'dictData.ne_version_status.3', '有新版本', 'Has New'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (618, 'menu.fault.event', '事件通知', 'Event Notification'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (619, 'menu.dashboard.smfCDR', '数据话单', 'Data CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (620, 'log.operate.title.smfCDR', '数据话单', 'Data CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (621, 'config.sys.i18nDefaultRemark', '国际化默认语言可选择 en_US、zh_CN', 'Internationalization default language selectable en_US、zh_CN'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (622, 'config.sys.i18nOpenRemark', '是否显示切换的控件 true/false', 'Whether to display switched controls true/false'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (623, 'menu.dashboard.mmeUE', '4G 终端事件', '4G UE Events'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (624, 'log.operate.title.mmeUE', '4G 终端事件', '4G UE Events'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (625, 'menu.system.user.editPost', '修改用户岗位', 'Modify User Post'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (626, 'menu.dashboard.smscCDR', '短信话单', 'SMS CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (627, 'log.operate.title.smscCDR', '短信话单', 'SMS CDR'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (628, 'menu.trace.pcapFile', '信令抓包文件', 'Signaling Capture File'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (629, 'menu.trace.taskAnalyze', '网元跟踪任务分析', 'NE Trace Task Analysis'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (630, 'job.ne_data_udm', '网元数据-UDM用户数据同步', 'NE Data-Sync UDM Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (631, 'menu.system.setting.doc', '系统使用文档', 'System User Documentation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (632, 'menu.system.setting.official', '官网链接', 'Official Website'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (633, 'menu.system.setting.lock', '锁屏操作', 'Lockscreen Operation'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (634, 'menu.ne.neConfigBackup', '网元配置备份', 'NE Config Backups'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (635, 'job.ne_config_backup', '网元-配置文件定期备份', 'NE-Config Backup Regularly'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (636, 'job.ne_config_backup_remark', '网元配置文件定期备份到网管服务器 +可查看网元配置备份记录进行下载或通过网元信息操作导入配置', 'Network Element Configuration files are regularly backed up to the OMC +View network element configuration backup records for downloading or importing configurations through network element information operations.'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (637, 'job.backup_export_table_sys_log_operate', '备份-操作日志表定期导出', 'Backup-Operation Log Table Periodic Export'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (638, 'job.backup_export_table_cdr_event_ims', '备份-语音话单表定期导出', 'Backup-Regular Export of voice bill forms'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (639, 'job.backup_export_table_cdr_event_smf', '备份-数据话单表定期导出', 'Backup-Regular Export of data sheet tables'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (640, 'cache.name.oauth2_codes', '客户端授权码', 'Oauth2 Client Code'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (641, 'cache.name.oauth2_devices', '客户端令牌', 'Oauth2 Token'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (642, 'job.backup_export_cdr', '备份-CDR数据定期导出', 'Backup-Periodic export of CDR Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (643, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc +fileType: 文件类型 csv/xlsx +hour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support ims/smf/sgwc/smsc +fileType: file type csv/xlsx +hour: data time from the hour before the task execution time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (644, 'menu.log.exportFile', '导出文件', 'Exported File'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (645, 'menu.perf.kpiCReport', '自定义指标数据', 'Custom Indicator Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (646, 'menu.trace.taskHLR', 'HLR 跟踪任务', 'HLR Trace Task'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (647, 'dictType.cdr_cause_code', 'CDR 响应原因代码类别类型', 'CDR Response Reason Code Category Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (648, 'dictData.cdr_cause_code.0', '未知错误', 'Unknown Error'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (649, 'dictData.cdr_cause_code.8', '运营者确定的禁止', 'Operator determined barring'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (650, 'dictData.cdr_cause_code.10', '禁止呼叫', 'Call Barred'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (651, 'dictData.cdr_cause_code.21', '呼叫被拒', 'Call rejected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (652, 'dictData.cdr_cause_code.22', '数量已更改', 'Number changed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (653, 'dictData.cdr_cause_code.27', '目的地出错', 'Destination out of order'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (654, 'dictData.cdr_cause_code.28', '数字格式无效(数字不完整)', 'Invalid number format (incomplete number)'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (655, 'dictData.cdr_cause_code.29', '设施被拒', 'Facility rejected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (656, 'dictData.cdr_cause_code.30', '回复状态查询', 'Response to STATUS ENQUIRY'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (657, 'dictData.cdr_cause_code.38', '网络故障', 'Network out of order'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (658, 'dictData.cdr_cause_code.41', '临时故障', 'Temporary failure'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (659, 'dictData.cdr_cause_code.42', '交换设备拥塞', 'Switching equipment congestion'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (660, 'dictData.cdr_cause_code.47', '资源不可用', 'Resource unavailable, unspecified'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (661, 'dictData.cdr_cause_code.50', '请求的设施未订阅', 'Requested facility not subscribed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (662, 'job.backup_export_table_cdr_event_smsc', '备份-短信话单表定期导出', 'Backup-Regular Export of SMS call list'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (663, 'job.backup_remove_file', '备份-定期删除备份目录下文件', 'Backup-Periodically Delete Directory Files'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (664, 'config.sys.homePage', '自定义主页', 'Custom Home Page'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (665, 'config.sys.homePageRemark', '选择列表中的任一页面作为主页路径', 'Select any page in the list as the homepage'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (666, 'menu.ne.neOverview', '网元概览', 'NE Overview'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (667, 'menu.ne.neOverviewRemark', '显示所有网元状态配置和license等概览信息', 'Displays overview information such as status, configuration and license of all network elements'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (668, 'job.backup_export_table_cdr_event_sgwc', '备份-漫游数据话单表定期导出', 'Backup-Regular Export of Roaming Data table'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (669, 'cache.name.i18n', '国际化语言管理', 'Internationalized Language Management'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (670, 'config.sys.user.passwordPolicy', '用户管理-默认密码策略强度', 'User Management-Default Password Policy Strength'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (671, 'config.sys.user.passwordPolicyRemark', 'minLength:密码至少8个字符 +specialChars:至少包含2个特殊字符(例如:!@#$%^&*()) +uppercase:至少包含一个大写字母 +lowercase:至少包含一个小写字母', 'minLength: password should be at least 8 characters long +specialChars: at least 2 special characters (e.g. ! @#$%^&*()) +uppercase: contain at least one uppercase letter +lowercase: contains at least one lowercase letter'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (672, 'config.sys.user.passwdExpire', '用户管理-密码有效期', 'User Management-Password Expiration Date'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (673, 'config.sys.user.passwdExpireRemark', '数值单位(小时) +expHours为过期时间,0表示不启用 +alertHours即将到期提醒时间', 'Numerical unit (hours) +expHours for the expiration time, 0 means not enabled +alertHours upcoming expiration reminder time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (674, 'config.sys.user.passwdNotAllowedHistory', '用户管理-不允许使用最近密码次数', 'User Management-Not Allowed Recent Passwords'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (675, 'config.sys.user.passwdNotAllowedHistoryRemark', '创建新密码不等于之前使用的x次中的密码', 'Creating a new password that is not equal to the previously used password in x times'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (676, 'login.errPasswdHistory', '不允许使用最近密码', 'Recent passwords not allowed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (677, 'log.operate.title.oauth2client', 'Oauth2客户端授权', 'Oauth2 Client Authorization'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (678, 'log.operate.title.pcfRule', '终端策略规则', 'UE PCC Rule'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (679, 'dictType.trace_msg_type', '跟踪消息类型', 'Trace Message Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (680, 'dictData.trace_msg_type.0', '请求', 'Request'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (681, 'dictData.trace_msg_type.1', '响应', 'Response'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (682, 'dictType.trace_msg_direct', '跟踪消息方向', 'Track Message Direction'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (683, 'dictData.trace_msg_direct.0', '接收', 'Receive'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (684, 'dictData.trace_msg_direct.1', '发送', 'Send'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (685, 'dictData.trace_interfaces.1', 'N1', 'N1'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (686, 'dictData.trace_interfaces.2', 'N2', 'N2'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (687, 'dictData.trace_interfaces.3', 'N1/N2', 'N1/N2'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (688, 'dictData.trace_interfaces.4', 'N4', 'N4'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (689, 'dictData.trace_interfaces.8', 'N8', 'N8'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (690, 'dictData.trace_interfaces.10', 'N10', 'N10'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (691, 'dictData.trace_interfaces.11', 'N11', 'N11'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (692, 'dictData.trace_interfaces.12', 'N12', 'N12'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (693, 'dictData.trace_interfaces.13', 'N13', 'N13'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (694, 'dictData.trace_interfaces.7', 'N7', 'N7'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (695, 'dictData.trace_interfaces.15', 'N15', 'N15'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (696, 'dictData.trace_interfaces.17', 'N17', 'N17'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (697, 'dictData.trace_interfaces.20', 'N20', 'N20'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (698, 'dictData.trace_interfaces.22', 'N22', 'N22'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (699, 'dictData.trace_interfaces.40', 'N40', 'N40'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (700, 'dictData.cdr_sip_code.302', '302 原因不明', '302 Unknown Reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (701, 'dictData.cdr_sip_code.402', '402 原因不明', '402 Unknown Reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (702, 'dictData.cdr_sip_code.480', '480 被叫挂断/拒接', '480 Temporarily Unavailable'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (703, 'dictData.cdr_sip_code.481', '481 原因不明', '481 Unknown Reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (704, 'dictData.cdr_sip_code.482', '482 发现环路', '482 Loop Detected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (705, 'dictData.cdr_sip_code.486', '486 这里很忙', '486 Busy Here'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (706, 'dictData.cdr_sip_code.489', '489 原因不明', '489 Unknown Reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (707, 'dictData.cdr_sip_code.580', '580 原因不明', '580 Unknown Reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (708, 'alarm.export.alarmType', '告警类型', 'Alarm Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (709, 'alarm.export.origSeverity', '告警级别', 'Severity'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (710, 'alarm.export.alarmTitle', '告警标题', 'Alarm Title'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (711, 'alarm.export.eventTime', '告警产生时间', 'Event Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (712, 'alarm.export.alarmId', '告警唯一标识', 'Alarm ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (713, 'alarm.export.clearUser', '告警清除用户', 'Clear User'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (714, 'alarm.export.clearType', '告警清除类型', 'Clear Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (715, 'alarm.export.clearTime', '告警清除时间', 'Clear Time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (716, 'log.operate.title.alarm', '告警', 'Alarm'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (717, 'ne.common.neType', '网元类型', 'NE Type'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (718, 'ne.common.neName', '网元名称', 'NE Name'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (719, 'ne.common.neId', '网元标识', 'NE ID'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (720, 'log.operate.title.udmVOIP', 'VOIP用户', 'UDM VOIP'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (721, 'log.operate.title.udmVolteIMS', 'VolteIMS用户', 'UDM VolteIMS'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (722, 'log.operate.title.backup', '备份', 'Backup'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (723, 'job.backup_export_table_cdr_event_smsc_remark', 'hour: 数据时间从任务执行时间前的小时数 +tableName: 数据表名 +columns: 支持字段 +backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time +tableName: data table name +columns: support fields +backupPath: backup output path /usr/local/omc/backup/{backupPath}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (724, 'job.backup_export_table_cdr_event_sgwc_remark', 'hour: 数据时间从任务执行时间前的小时数 +tableName: 数据表名 +columns: 支持字段 +backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time +tableName: data table name +columns: support fields +backupPath: backup output path /usr/local/omc/backup/{backupPath}'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (725, 'job.backup_remove_file_remark', 'backupPath: 备份路径 /usr/local/omc/backup/{backupPath} +storeDays: 保留天数 +storeNum: 保留数量,默认保留7', 'backupPath: backup path /usr/local/omc/backup/{backupPath} +storeDays: retention days +storeNum: retention number, default retention 7'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (726, 'job.backup_export_udm', '备份-UDM数据定期导出', 'Backup-Periodic export of UDM Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (727, 'job.backup_export_udm_remark', 'dataType: 类型支持 auth/sub/voip/volte +fileType: 文件类型 csv/txt', 'Backup-Periodic export of dataType: type support auth/sub/voip/volte +fileType: file type csv/txt'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (728, 'dictData.cdr_sip_code_cause.0', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常通话清除', 'Normal Call Clearing'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务器本身出了问题', 'Something went wrong inside the server itself'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (751, 'job.backup_export_log_remark', 'dataType: 类型支持 operate/login +fileType: 文件类型 csv/xlsx +hour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support operate/login +fileType: file type csv/xlsx +hour: data time from the hour before the task execution time'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (752, 'job.ne_alarm_state_check_cmd', '网元告警-内存/CPU/磁盘检查', 'NE Alarm-Memory/CPU/Disk Checks'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (753, 'job.ne_alarm_state_check_cmd_remark', '检查网元的内存/CPU/磁盘检查健康状况,在出现过阈值时发出警报。 + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: 告警补充信息 +cpuUseGt: CPU使用率大于, 范围0~100*CPU核心数 +memUseGt: 内存使用率大于, 范围0~100% +diskUseGt: 磁盘使用率大于, 范围0~100%', 'Checks the memory/CPU/disk check health of the network element and sends alerts when thresholds are crossed. + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: Additional information on alarms +cpuUseGt: CPU utilization is greater than, range 0~100*number of CPU cores +memUseGt: Memory utilization greater than, range 0 to 100% +diskUseGt: Disk utilization greater than, range 0 to 100%'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (754, 'job.ne_alarm_state_check_license', '网元告警-License到期检查', 'NE Alarm-License Expire Check'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。 + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: 告警补充信息 +dayLt: 天数小于,默认30天', 'Checks if the network element is License is about to expire and sends an alert if a threshold is crossed. + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: Additional information on alarms +dayLt: Days less than, default 30 days'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (756, 'dictData.trace_interfaces.14', 'N14', 'N14'); +REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (757, 'dictData.trace_interfaces.5', 'N5', 'N5'); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index dd8a49a2..3078cb13 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -559,7 +559,7 @@ INSERT INTO `sys_i18n` VALUES (541, 'dictData.cdr_sip_code.404', '404 找不到' INSERT INTO `sys_i18n` VALUES (542, 'dictData.cdr_sip_code.487', '487 请求已终止', '487 Request Terminated'); INSERT INTO `sys_i18n` VALUES (543, 'dictData.cdr_sip_code.503', '503 服务不可用', '503 Service Unavailable'); INSERT INTO `sys_i18n` VALUES (544, 'dictData.cdr_sip_code.504', '504 服务器超时', '504 Server Timeout'); -INSERT INTO `sys_i18n` VALUES (545, 'dictData.cdr_sip_code.603', '603 下降', '603 Decline'); +INSERT INTO `sys_i18n` VALUES (545, 'dictData.cdr_sip_code.603', '603 拒绝', '603 Decline'); INSERT INTO `sys_i18n` VALUES (546, 'dictData.cdr_sip_code.606', '606 不可接受', '606 Not Acceptable'); INSERT INTO `sys_i18n` VALUES (547, 'cache.name.token', '用户令牌', 'User Token'); INSERT INTO `sys_i18n` VALUES (548, 'cache.name.sys_config', '参数管理', 'Parameters Management'); @@ -753,7 +753,7 @@ INSERT INTO `sys_i18n` VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其 INSERT INTO `sys_i18n` VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); INSERT INTO `sys_i18n` VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); INSERT INTO `sys_i18n` VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -INSERT INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 用户断线', 'MO User Disconnected'); +INSERT INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); INSERT INTO `sys_i18n` VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); INSERT INTO `sys_i18n` VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); INSERT INTO `sys_i18n` VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -761,7 +761,7 @@ INSERT INTO `sys_i18n` VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 INSERT INTO `sys_i18n` VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); INSERT INTO `sys_i18n` VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); INSERT INTO `sys_i18n` VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -INSERT INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 明确拒绝通话', 'MT explicitly rejected the call'); +INSERT INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); INSERT INTO `sys_i18n` VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); INSERT INTO `sys_i18n` VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); INSERT INTO `sys_i18n` VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index 625f533a..f5558c26 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -556,7 +556,7 @@ REPLACE INTO `sys_i18n` VALUES (541, 'dictData.cdr_sip_code.404', '404 找不到 REPLACE INTO `sys_i18n` VALUES (542, 'dictData.cdr_sip_code.487', '487 请求已终止', '487 Request Terminated'); REPLACE INTO `sys_i18n` VALUES (543, 'dictData.cdr_sip_code.503', '503 服务不可用', '503 Service Unavailable'); REPLACE INTO `sys_i18n` VALUES (544, 'dictData.cdr_sip_code.504', '504 服务器超时', '504 Server Timeout'); -REPLACE INTO `sys_i18n` VALUES (545, 'dictData.cdr_sip_code.603', '603 下降', '603 Decline'); +REPLACE INTO `sys_i18n` VALUES (545, 'dictData.cdr_sip_code.603', '603 拒绝', '603 Decline'); REPLACE INTO `sys_i18n` VALUES (546, 'dictData.cdr_sip_code.606', '606 不可接受', '606 Not Acceptable'); REPLACE INTO `sys_i18n` VALUES (547, 'cache.name.token', '用户令牌', 'User Token'); REPLACE INTO `sys_i18n` VALUES (548, 'cache.name.sys_config', '参数管理', 'Parameters Management'); @@ -750,7 +750,7 @@ REPLACE INTO `sys_i18n` VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其 REPLACE INTO `sys_i18n` VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); REPLACE INTO `sys_i18n` VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); REPLACE INTO `sys_i18n` VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -REPLACE INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 用户断线', 'MO User Disconnected'); +REPLACE INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); REPLACE INTO `sys_i18n` VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); REPLACE INTO `sys_i18n` VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); REPLACE INTO `sys_i18n` VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -758,7 +758,7 @@ REPLACE INTO `sys_i18n` VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 REPLACE INTO `sys_i18n` VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); REPLACE INTO `sys_i18n` VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); REPLACE INTO `sys_i18n` VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 明确拒绝通话', 'MT explicitly rejected the call'); +REPLACE INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); REPLACE INTO `sys_i18n` VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); REPLACE INTO `sys_i18n` VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); REPLACE INTO `sys_i18n` VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); From be5f929f1fadae46b2c5f2bb2deacab14a95c738 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 22 Jul 2025 19:56:24 +0800 Subject: [PATCH 38/80] =?UTF-8?q?fix:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=8D=95=E4=BD=8D=E7=B4=AF=E5=8A=A0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../network_data/service/kpi_c_report.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/modules/network_data/service/kpi_c_report.go b/src/modules/network_data/service/kpi_c_report.go index 4f5bc252..6e30181c 100644 --- a/src/modules/network_data/service/kpi_c_report.go +++ b/src/modules/network_data/service/kpi_c_report.go @@ -22,6 +22,12 @@ type KpiCReport struct { // FindKPI 通过网元指标数据信息 func (s KpiCReport) FindData(query model.KPICQuery) []map[string]any { + // 标题单位映射 + kpicTitles := s.kpiCReportRepository.SelectKPITitle(query.NeType) + kpicTitleUnitMap := map[string]string{} + for _, v := range kpicTitles { + kpicTitleUnitMap[v.KpiId] = v.Unit + } // 原始数据 rows := s.kpiCReportRepository.SelectKPI(query) if len(rows) <= 0 { @@ -107,6 +113,17 @@ func (s KpiCReport) FindData(query model.KPICQuery) []map[string]any { } } } + // 处理单位 + for _, kpiId := range kpiIds { + unit, ok := kpicTitleUnitMap[kpiId] + if !ok { + continue + } + // "Mbps" "%" + if unit == "%" { + startItem[kpiId] = startItem[kpiId].(float64) / float64(len(records)) + } + } } data = append(data, startItem) } From 0b4f04c33cd4bab9a75b604381de01c5952cc4b1 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 23 Jul 2025 10:57:51 +0800 Subject: [PATCH 39/80] =?UTF-8?q?fix:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=95=B0=E6=8D=AE=E8=AE=A1=E7=AE=97=E5=B0=8F?= =?UTF-8?q?=E4=BA=8E0=E5=B0=B1=E5=BC=BA=E5=88=B6=E4=B8=BA0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/service/kpi.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/modules/oam/service/kpi.go b/src/modules/oam/service/kpi.go index 3d73d8c4..832f4c7d 100644 --- a/src/modules/oam/service/kpi.go +++ b/src/modules/oam/service/kpi.go @@ -183,11 +183,14 @@ func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { item["err"] = err.Error() } else { if v.Unit == "%" { - resultInt64 := parse.Number(result) - if resultInt64 > 100 { + resultV, ok := result.(float64) + if !ok { + resultV = 0 + } + if resultV > 100 { result = 100 } - if resultInt64 < 0 { + if resultV < 0 { result = 0 } } From d8d3a979eb5fec98e3d2b8a51b8087c61076349c Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 23 Jul 2025 10:58:52 +0800 Subject: [PATCH 40/80] =?UTF-8?q?fix:=20=E5=91=8A=E8=AD=A6=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E8=BF=94=E5=9B=9E=E7=8A=B6=E6=80=81=E4=B8=BA=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=EF=BC=8C=E8=BF=87=E7=A8=8B=E9=94=99=E8=AF=AF=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=BF=94=E5=9B=9E=E5=88=B0=E5=93=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/controller/api_rest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go index 4eb57f8e..955ad745 100644 --- a/src/modules/oam/controller/api_rest.go +++ b/src/modules/oam/controller/api_rest.go @@ -667,7 +667,7 @@ func (s APIRestController) ResolveAlarmHistory(c *gin.Context) { } if len(errArr) > 0 { - c.JSON(200, resp.ErrData(errArr)) + c.JSON(200, resp.OkData(errArr)) return } c.JSON(200, resp.Ok(nil)) From 4ae66abbb3f3557d0c42e73e61eb118e50e596a8 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 23 Jul 2025 10:59:31 +0800 Subject: [PATCH 41/80] =?UTF-8?q?feat:=20=E5=91=8A=E8=AD=A6=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E8=A1=A8=E6=A0=BC=E6=A0=87=E9=A2=98=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E7=BF=BB=E8=AF=91=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 1 + build/database/lite/upgrade/upg_sys_i18n.sql | 1515 +++++++++--------- build/database/std/install/sys_i18n.sql | 1 + build/database/std/upgrade/upg_sys_i18n.sql | 1 + 4 files changed, 761 insertions(+), 757 deletions(-) diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index cd0c81f1..53186caa 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -930,3 +930,4 @@ AddInfo: Additional information on alarms dayLt: Days less than, default 30 days'); 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"); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index 00fcba3f..5bddf13d 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -12,534 +12,534 @@ CREATE TABLE IF NOT EXISTS "sys_i18n" ( -- ---------------------------- -- Records of sys_i18n -- ---------------------------- -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (1, 'i18n', '中文', 'English'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (2, 'hello', '你好', 'Hello'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (3, 'menu.system', '系统', 'System'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (4, 'menu.monitor', '监控', 'Monitor'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (5, 'menu.tools', '工具', 'Tools'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (6, 'menu.ne', '网元', 'NE'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (7, 'menu.ue', '终端', 'UE'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (8, 'menu.systemRemark', '系统管理目录', 'System Management Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (9, 'menu.monitorRemark', '系统监控目录', 'System Monitor Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (10, 'menu.toolsRemark', '系统工具目录', 'System Tools Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (11, 'menu.neRemark', '网元配置管理目录', 'NE Configuration Management Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (12, 'menu.ueRemark', '网元终端信息目录', 'Network Element Terminal Information Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (13, 'menu.security.user', '用户管理', 'User Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (14, 'menu.security.role', '角色管理', 'Role Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (15, 'menu.security.roleUser', '分配角色', 'Assigning Roles'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (16, 'menu.system.menu', '菜单管理', 'Menu Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (17, 'menu.security.dept', '部门管理', 'Department Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (18, 'menu.security.post', '岗位管理', 'Position Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (19, 'menu.system.dictType', '字典管理', 'Dictionary Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (20, 'menu.system.dictData', '字典数据', 'Dictionary Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (21, 'menu.system.paramSet', '参数设置', 'Parameter Settings'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (22, 'menu.system.systemLog', '系统日志', 'System Log'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (23, 'menu.system.systemInfo', '系统信息', 'System Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (24, 'menu.system.cacheInfo', '缓存信息', 'Cache Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (25, 'menu.system.cache', '缓存管理', 'Cache Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (26, 'menu.security.onlineUser', '在线用户', 'Online Users'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (27, 'menu.system.job', '调度任务', 'Scheduling Tasks'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (28, 'menu.system.jobLog', '调度日志', 'Scheduling Logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (29, 'menu.tools.help', '帮助文档', 'Help Documentation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (30, 'menu.log.operat', '操作日志', 'Operation logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (31, 'menu.log.login', '安全日志', 'Security logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (32, 'menu.security.userRemark', '用户管理菜单', 'User Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (33, 'menu.security.roleRemark', '角色管理菜单', 'Role Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (34, 'menu.security.roleUserRemark', '分配角色内嵌隐藏菜单', 'Assign Roles Embedded Hidden Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (35, 'menu.system.menuRemark', '菜单管理菜单', 'Menu Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (36, 'menu.security.deptRemark', '部门管理菜单', 'Department management menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (37, 'menu.security.postRemark', '岗位管理菜单', 'Job Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (38, 'menu.system.dictTypeRemark', '字典管理菜单', 'Dictionary management menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (39, 'menu.system.dictDataRemark', '字典数据内嵌隐藏菜单', 'Dictionary data embedded hidden menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (40, 'menu.system.paramSetRemark', '参数设置菜单', 'Parameter setting menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (41, 'menu.system.systemLogRemark', '系统日志目录', 'System Log Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (42, 'menu.system.systemInfoRemark', '系统信息菜单', 'System information menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (43, 'menu.system.cacheInfoRemark', '缓存信息菜单', 'Cache Information Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (44, 'menu.system.cacheRemark', '缓存列表菜单', 'Cache List Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (45, 'menu.security.onlineUserRemark', '在线用户菜单', 'Online User Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (46, 'menu.system.jobRemark', '调度任务菜单', 'Scheduling Tasks menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (47, 'menu.system.jobLogRemark', '调度日志内嵌隐藏菜单', 'Scheduling Log Embedded Hidden Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (48, 'menu.tools.helpRemark', '帮助文档菜单', 'Help file menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (49, 'menu.log.operatRemark', '操作日志菜单', 'Operation log menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (50, 'menu.log.loginRemark', '登录日志菜单', 'Login log menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (51, 'menu.common.query', '查询', 'Inquiry'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (52, 'menu.common.add', '新增', 'Add'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (53, 'menu.common.edit', '修改', 'Modify'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (54, 'menu.common.delete', '删除', 'Delete'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (55, 'menu.common.export', '导出', 'Export'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (56, 'menu.common.import', '导入', 'Import'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (57, 'menu.common.resetPwd', '重置密码', 'Reset Password'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (58, 'menu.common.unlock', '账户解锁', 'Account Unlock'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (59, 'menu.forcedQuit.batch ', '批量强退', 'Batch Undo'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (60, 'menu.forcedQuit.single', '单条强退', 'Individual Forced Retirement'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (61, 'menu.neData.udmAuth', 'UDM鉴权用户', 'UDM Authentication'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (62, 'menu.neData.udmSub', 'UDM签约用户', 'UDM Subscribers'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (63, 'menu.neData.udmVOIP', 'VOIP鉴权用户', 'VOIP Authentication'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (64, 'menu.neData.udmVolte', 'IMS签约用户', 'IMS Subscribers'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (65, 'menu.neData.imsSub', 'IMS在线用户', 'IMS Online Users'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (66, 'menu.neData.smfSub', 'UE在线信息', 'UE Online Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (67, 'menu.neData.baseOnline', '基站在线', 'Radio Online'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (68, 'menu.trace', '跟踪', 'Trace'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (69, 'menu.trace.task', '网元跟踪任务', 'NE Trace Task'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (70, 'menu.trace.taskData', '网元跟踪任务数据', 'NE Trace Task Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (71, 'menu.trace.pcap', '信令抓包', 'Signaling Capture'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (72, 'menu.fault', '监控', 'Monitor'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (73, 'config.neData.backupDataFTP', '备份网元数据-同步FTP服务', 'Backup NE Data - Sync Data FTP Service'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (74, 'config.neData.backupDataFTPRemark', '请通过系统页面进行设置FTP信息', 'Please set the FTP information through the system page.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (75, 'job.backup_export_table_sys_log_operate_remark', 'hour: 数据时间从任务执行时间前的小时数 +REPLACE INTO "sys_i18n" VALUES (1, 'i18n', '中文', 'English'); +REPLACE INTO "sys_i18n" VALUES (2, 'hello', '你好', 'Hello'); +REPLACE INTO "sys_i18n" VALUES (3, 'menu.system', '系统', 'System'); +REPLACE INTO "sys_i18n" VALUES (4, 'menu.monitor', '监控', 'Monitor'); +REPLACE INTO "sys_i18n" VALUES (5, 'menu.tools', '工具', 'Tools'); +REPLACE INTO "sys_i18n" VALUES (6, 'menu.ne', '网元', 'NE'); +REPLACE INTO "sys_i18n" VALUES (7, 'menu.ue', '终端', 'UE'); +REPLACE INTO "sys_i18n" VALUES (8, 'menu.systemRemark', '系统管理目录', 'System Management Catalog'); +REPLACE INTO "sys_i18n" VALUES (9, 'menu.monitorRemark', '系统监控目录', 'System Monitor Catalog'); +REPLACE INTO "sys_i18n" VALUES (10, 'menu.toolsRemark', '系统工具目录', 'System Tools Catalog'); +REPLACE INTO "sys_i18n" VALUES (11, 'menu.neRemark', '网元配置管理目录', 'NE Configuration Management Catalog'); +REPLACE INTO "sys_i18n" VALUES (12, 'menu.ueRemark', '网元终端信息目录', 'Network Element Terminal Information Catalog'); +REPLACE INTO "sys_i18n" VALUES (13, 'menu.security.user', '用户管理', 'User Management'); +REPLACE INTO "sys_i18n" VALUES (14, 'menu.security.role', '角色管理', 'Role Management'); +REPLACE INTO "sys_i18n" VALUES (15, 'menu.security.roleUser', '分配角色', 'Assigning Roles'); +REPLACE INTO "sys_i18n" VALUES (16, 'menu.system.menu', '菜单管理', 'Menu Management'); +REPLACE INTO "sys_i18n" VALUES (17, 'menu.security.dept', '部门管理', 'Department Management'); +REPLACE INTO "sys_i18n" VALUES (18, 'menu.security.post', '岗位管理', 'Position Management'); +REPLACE INTO "sys_i18n" VALUES (19, 'menu.system.dictType', '字典管理', 'Dictionary Management'); +REPLACE INTO "sys_i18n" VALUES (20, 'menu.system.dictData', '字典数据', 'Dictionary Data'); +REPLACE INTO "sys_i18n" VALUES (21, 'menu.system.paramSet', '参数设置', 'Parameter Settings'); +REPLACE INTO "sys_i18n" VALUES (22, 'menu.system.systemLog', '系统日志', 'System Log'); +REPLACE INTO "sys_i18n" VALUES (23, 'menu.system.systemInfo', '系统信息', 'System Information'); +REPLACE INTO "sys_i18n" VALUES (24, 'menu.system.cacheInfo', '缓存信息', 'Cache Information'); +REPLACE INTO "sys_i18n" VALUES (25, 'menu.system.cache', '缓存管理', 'Cache Management'); +REPLACE INTO "sys_i18n" VALUES (26, 'menu.security.onlineUser', '在线用户', 'Online Users'); +REPLACE INTO "sys_i18n" VALUES (27, 'menu.system.job', '调度任务', 'Scheduling Tasks'); +REPLACE INTO "sys_i18n" VALUES (28, 'menu.system.jobLog', '调度日志', 'Scheduling Logs'); +REPLACE INTO "sys_i18n" VALUES (29, 'menu.tools.help', '帮助文档', 'Help Documentation'); +REPLACE INTO "sys_i18n" VALUES (30, 'menu.log.operat', '操作日志', 'Operation logs'); +REPLACE INTO "sys_i18n" VALUES (31, 'menu.log.login', '安全日志', 'Security logs'); +REPLACE INTO "sys_i18n" VALUES (32, 'menu.security.userRemark', '用户管理菜单', 'User Management Menu'); +REPLACE INTO "sys_i18n" VALUES (33, 'menu.security.roleRemark', '角色管理菜单', 'Role Management Menu'); +REPLACE INTO "sys_i18n" VALUES (34, 'menu.security.roleUserRemark', '分配角色内嵌隐藏菜单', 'Assign Roles Embedded Hidden Menu'); +REPLACE INTO "sys_i18n" VALUES (35, 'menu.system.menuRemark', '菜单管理菜单', 'Menu Management Menu'); +REPLACE INTO "sys_i18n" VALUES (36, 'menu.security.deptRemark', '部门管理菜单', 'Department management menu'); +REPLACE INTO "sys_i18n" VALUES (37, 'menu.security.postRemark', '岗位管理菜单', 'Job Management Menu'); +REPLACE INTO "sys_i18n" VALUES (38, 'menu.system.dictTypeRemark', '字典管理菜单', 'Dictionary management menu'); +REPLACE INTO "sys_i18n" VALUES (39, 'menu.system.dictDataRemark', '字典数据内嵌隐藏菜单', 'Dictionary data embedded hidden menu'); +REPLACE INTO "sys_i18n" VALUES (40, 'menu.system.paramSetRemark', '参数设置菜单', 'Parameter setting menu'); +REPLACE INTO "sys_i18n" VALUES (41, 'menu.system.systemLogRemark', '系统日志目录', 'System Log Catalog'); +REPLACE INTO "sys_i18n" VALUES (42, 'menu.system.systemInfoRemark', '系统信息菜单', 'System information menu'); +REPLACE INTO "sys_i18n" VALUES (43, 'menu.system.cacheInfoRemark', '缓存信息菜单', 'Cache Information Menu'); +REPLACE INTO "sys_i18n" VALUES (44, 'menu.system.cacheRemark', '缓存列表菜单', 'Cache List Menu'); +REPLACE INTO "sys_i18n" VALUES (45, 'menu.security.onlineUserRemark', '在线用户菜单', 'Online User Menu'); +REPLACE INTO "sys_i18n" VALUES (46, 'menu.system.jobRemark', '调度任务菜单', 'Scheduling Tasks menu'); +REPLACE INTO "sys_i18n" VALUES (47, 'menu.system.jobLogRemark', '调度日志内嵌隐藏菜单', 'Scheduling Log Embedded Hidden Menu'); +REPLACE INTO "sys_i18n" VALUES (48, 'menu.tools.helpRemark', '帮助文档菜单', 'Help file menu'); +REPLACE INTO "sys_i18n" VALUES (49, 'menu.log.operatRemark', '操作日志菜单', 'Operation log menu'); +REPLACE INTO "sys_i18n" VALUES (50, 'menu.log.loginRemark', '登录日志菜单', 'Login log menu'); +REPLACE INTO "sys_i18n" VALUES (51, 'menu.common.query', '查询', 'Inquiry'); +REPLACE INTO "sys_i18n" VALUES (52, 'menu.common.add', '新增', 'Add'); +REPLACE INTO "sys_i18n" VALUES (53, 'menu.common.edit', '修改', 'Modify'); +REPLACE INTO "sys_i18n" VALUES (54, 'menu.common.delete', '删除', 'Delete'); +REPLACE INTO "sys_i18n" VALUES (55, 'menu.common.export', '导出', 'Export'); +REPLACE INTO "sys_i18n" VALUES (56, 'menu.common.import', '导入', 'Import'); +REPLACE INTO "sys_i18n" VALUES (57, 'menu.common.resetPwd', '重置密码', 'Reset Password'); +REPLACE INTO "sys_i18n" VALUES (58, 'menu.common.unlock', '账户解锁', 'Account Unlock'); +REPLACE INTO "sys_i18n" VALUES (59, 'menu.forcedQuit.batch ', '批量强退', 'Batch Undo'); +REPLACE INTO "sys_i18n" VALUES (60, 'menu.forcedQuit.single', '单条强退', 'Individual Forced Retirement'); +REPLACE INTO "sys_i18n" VALUES (61, 'menu.neData.udmAuth', 'UDM鉴权用户', 'UDM Authentication'); +REPLACE INTO "sys_i18n" VALUES (62, 'menu.neData.udmSub', 'UDM签约用户', 'UDM Subscribers'); +REPLACE INTO "sys_i18n" VALUES (63, 'menu.neData.udmVOIP', 'VOIP鉴权用户', 'VOIP Authentication'); +REPLACE INTO "sys_i18n" VALUES (64, 'menu.neData.udmVolte', 'IMS签约用户', 'IMS Subscribers'); +REPLACE INTO "sys_i18n" VALUES (65, 'menu.neData.imsSub', 'IMS在线用户', 'IMS Online Users'); +REPLACE INTO "sys_i18n" VALUES (66, 'menu.neData.smfSub', 'UE在线信息', 'UE Online Information'); +REPLACE INTO "sys_i18n" VALUES (67, 'menu.neData.baseOnline', '基站在线', 'Radio Online'); +REPLACE INTO "sys_i18n" VALUES (68, 'menu.trace', '跟踪', 'Trace'); +REPLACE INTO "sys_i18n" VALUES (69, 'menu.trace.task', '网元跟踪任务', 'NE Trace Task'); +REPLACE INTO "sys_i18n" VALUES (70, 'menu.trace.taskData', '网元跟踪任务数据', 'NE Trace Task Data'); +REPLACE INTO "sys_i18n" VALUES (71, 'menu.trace.pcap', '信令抓包', 'Signaling Capture'); +REPLACE INTO "sys_i18n" VALUES (72, 'menu.fault', '监控', 'Monitor'); +REPLACE INTO "sys_i18n" VALUES (73, 'config.neData.backupDataFTP', '备份网元数据-同步FTP服务', 'Backup NE Data - Sync Data FTP Service'); +REPLACE INTO "sys_i18n" VALUES (74, 'config.neData.backupDataFTPRemark', '请通过系统页面进行设置FTP信息', 'Please set the FTP information through the system page.'); +REPLACE INTO "sys_i18n" VALUES (75, 'job.backup_export_table_sys_log_operate_remark', 'hour: 数据时间从任务执行时间前的小时数 tableName: 数据表名 columns: 支持字段 backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time tableName: data table name columns: support fields backupPath: backup output path /usr/local/omc/backup/{backupPath}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (76, 'job.backup_export_table_cdr_event_ims_remark', 'hour: 数据时间从任务执行时间前的小时数 +REPLACE INTO "sys_i18n" VALUES (76, 'job.backup_export_table_cdr_event_ims_remark', 'hour: 数据时间从任务执行时间前的小时数 tableName: 数据表名 columns: 支持字段 backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time tableName: data table name columns: support fields backupPath: backup output path /usr/local/omc/backup/{backupPath}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (77, 'job.backup_export_table_cdr_event_smf_remark', 'hour: 数据时间从任务执行时间前的小时数 +REPLACE INTO "sys_i18n" VALUES (77, 'job.backup_export_table_cdr_event_smf_remark', 'hour: 数据时间从任务执行时间前的小时数 tableName: 数据表名 columns: 支持字段 backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time tableName: data table name columns: support fields backupPath: backup output path /usr/local/omc/backup/{backupPath}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (78, 'menu.traceRemark', '跟踪管理目录', 'Tracking Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (79, 'menu.trace.taskRemark', '跟踪任务菜单', 'Tracking Task Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (80, 'config.sys.user.fristPasswdChange', '用户管理-首次登录密码修改', 'User Management-First Login Password Change'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (81, 'menu.trace.pcapRemark', '信令抓包菜单', 'Signaling Capture Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (82, 'menu.faultRemark', '故障管理目录', 'Fault Management Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (83, 'menu.fault.active', '活动告警', 'Active Alarms'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (84, 'menu.log', '日志', 'Logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (85, 'menu.log.mml', 'MML日志', 'MML Logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (86, 'menu.log.alarm', '告警日志', 'Alarm Logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (87, 'menu.log.forwarding', '告警前转日志', 'Alarm Forwarding Logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (88, 'menu.log.set', '日志设置', 'Log Settings'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (89, 'menu.monitor.sessionUser', '用户会话', 'User Sessions'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (90, 'menu.fault.history', '历史告警', 'Historical Alarms'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (91, 'menu.fault.set', '设置', 'Settings'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (92, 'menu.perf', '性能', 'Performance'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (93, 'menu.fault.activemRemark', '活动告警菜单', 'Active Alarm Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (94, 'menu.logRemark', '日志管理目录', 'Log Management Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (95, 'menu.log.operatOldRemark', '操作日志旧layui菜单', 'Operation log old layui menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (96, 'menu.log.mmlRemark', '操作MML日志', 'Operation MML Log'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (97, 'menu.log.alarmRemark', '告警日志菜单', 'Alarm Log Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (98, 'menu.log.securityOldRemark', '安全日志旧layui菜单', 'Security Log Old Layui Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (99, 'menu.log.forwardingRemark', '告警前转日志菜单', 'Alarm forward log menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (100, 'menu.log.setRemark', '日志设置菜单', 'Log Settings menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (101, 'menu.monitor.sessionUserRemark', '用户会话旧layui菜单', 'User Session Old Layui Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (102, 'menu.fault.historyRemark', '历史告警菜单', 'Alarm history menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (103, 'menu.fault.setRemark', '故障通用设置菜单', 'Fault General Setup Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (104, 'menu.perfRemark', '性能目录', 'Performance Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (105, 'menu.perf.task', '任务管理', 'Performance Tasks'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (106, 'menu.perf.data', '性能数据', 'Performance Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (107, 'menu.perf.kpiOverView', '关键指标概览', 'Key Performance Overview'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (108, 'menu.perf.threshold', '性能门限', 'Performance Thresholds'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (109, 'menu.perf.kpi', '关键指标', 'Key Performance Indicators'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (110, 'menu.perf.customTarget', '自定义指标', 'Custom Indicator Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (111, 'menu.perf.kpiKeyTarget', '关键指标报表', 'Key Performance Reports'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (112, 'menu.mml', 'MML', 'MML'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (113, 'menu.mml.ne', '网元操作', 'NE Operation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (114, 'menu.mml.udm', 'UDM操作', 'UDM Operation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (115, 'menu.mml.set', 'MML设置', 'MML Settings'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (116, 'menu.mml.omc', 'OMC操作', 'OMC Operation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (117, 'menu.perf.taskRemark', '任务管理菜单', 'Task Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (118, 'menu.perf.dataRemark', '性能数据菜单', 'Performance Data Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (119, 'menu.dashboard.smscCDR.content', '可见短信内容', 'Visible SMS content'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (120, 'menu.perf.thresholdRemark', '性能门限菜单', 'Performance Threshold Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (121, 'menu.perf.kpiRemark', '黄金指标菜单', 'Key Performance Indicator Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (122, 'menu.perf.customTargetRemark', '自定义指标菜单', 'Custom Indicator Management Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (123, 'menu.dashboard.smfCDRByIMSI', '数据流量报表', 'Data Usage Report'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (124, 'menu.mmlRemark', 'MML管理目录', 'MML Management Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (125, 'menu.mml.neRemark', '网元操作菜单', 'Network Element Operations Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (126, 'menu.mml.udmRemark', '网元UDM用户数据菜单', 'Network Element UDM User Data Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (127, 'menu.mml.setRemark', 'MML设置菜单', 'MML Setup Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (128, 'menu.mml.omcRemark', 'OMC操作菜单', 'OMC Operation Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (129, 'menu.dashboard.sgwcCDR', '漫游数据话单', 'Roaming Data CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (130, 'menu.security', '安全', 'Security'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (131, 'menu.system.systemSet', '系统设置', 'System Settings'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (132, 'menu.system.systemResource', '系统资源', 'System Resources'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (133, 'log.operate.title.sgwcCDR', '漫游数据话单', 'Roaming Data CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (134, 'menu.securityRemark', '安全管理目录', 'Security Management Catalog'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (135, 'menu.system.systemSetRemark', '系统设置菜单', 'System Settings Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (136, 'menu.system.systemResourceRemark', '系统资源 cpu io network菜单', 'System Resources cpu io network menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (137, 'dictData.offline', '离线', 'Offline'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (138, 'dictData.online', '在线', 'Online'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (139, 'menu.neData.baseStation', '基站状态', 'Radio State'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (140, 'menu.noData', '没有可访问菜单数据!', 'There is no accessible menu data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (141, 'menu.errNameExists', '操作菜单【{name}】失败,菜单名称已存在', 'Failed to operate menu [{name}], menu name already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (142, 'menu.errPathExists', '操作菜单【{name}】失败,菜单路由地址已存在', 'Failed to operate menu [{name}], menu routing address already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (143, 'menu.errFramePath', '操作菜单【{name}】失败,非内部地址请以http(s)://开头', 'Failed to manipulate menu [{name}], non-internal address should start with http(s)://'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (144, 'menu.errParentStatus', '上级菜单未启用!', 'The parent menu is not enabled!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (145, 'menu.errHasChildUse', '操作菜单【{name}】失败,存在使用子菜单数:{num}', 'Operation menu [{name}] failed, number of submenus in use exists: {num}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (146, 'menu.errHasRoleUse', '操作菜单【{name}】失败,菜单已分配给角色数:{num}', 'Operation menu [{name}] failed, number of roles the menu has been assigned to: {num}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (147, 'dictData.sex.un', '未选择', 'Not Selected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (148, 'dictData.sex.male', '男', 'Male'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (149, 'dictData.sex.female', '女', 'Female'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (150, 'dictData.show', '显示', 'Show'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (151, 'dictData.hide', '隐藏', 'Hide'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (152, 'dictData.normal', '正常', 'Active'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (153, 'dictData.disable', '停用', 'Inactive'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (154, 'dictData.yes', '是', 'Yes'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (155, 'dictData.no', '否', 'No'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (156, 'dictData.success', '成功', 'Successful'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (157, 'dictData.fail', '失败', 'Failed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (158, 'dictData.jobStatus.normal', '正常', 'Active'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (159, 'dictData.jobStatus.pause', '暂停', 'Inactive'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (160, 'dictData.jobGroup.Default', '默认', 'Default'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (161, 'dictData.jobGroup.System', '系统', 'System'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (162, 'dictData.operType.other', '其他', 'Other'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (163, 'dictData.operType.add', '新增', 'New'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (164, 'dictData.operType.edit', '修改', 'Modify'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (165, 'dictData.operType.delete', '删除', 'Delete'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (166, 'dictData.operType.auth', '授权', 'Authorization'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (167, 'dictData.operType.export', '导出', 'Export'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (168, 'dictData.operType.import', '导入', 'Import'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (169, 'dictData.operType.forced quit', '强退', 'Forced Retirement'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (170, 'dictData.operType.clear', '清空', 'Clear'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (171, 'dictData.trace.interface', '接口跟踪', 'Interface Tracing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (172, 'dictData.trace.device', '设备跟踪', 'Module Tracing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (173, 'dictData.trace.user', '用户跟踪', 'User Tracing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (174, 'nbState.export.id', '编号', 'ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (175, 'nbState.export.name', '基站名称', 'Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (176, 'nbState.export.position', '基站位置', 'Position'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (177, 'nbState.export.address', 'IP地址', 'IP Address'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (178, 'nbState.export.nbName', '设备名称', 'RanNodeName'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (179, 'nbState.export.ueNum', '在线用户数', 'UE Number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (180, 'nbState.export.state', '基站状态', 'State'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (181, 'nbState.export.time', '变更时间', 'Change Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (182, 'neHost.okBySSHLink', '设置免密直连成功', 'Setting up a password-free direct connection is successful'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (183, 'neHost.banNE', '禁止操作网元', 'Do not operate the NE'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (184, 'dictData.ne_host_type.redis', 'Redis', 'Redis'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (185, 'menu.tools.ping', '网络探测测试', 'Net Probing Test'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (186, 'menu.tools.iperf', '网络性能测试', 'Net Performance Test'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (187, 'dictData.jobSaveLog.no', '不记录', 'No Record'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (188, 'dictData.jobSaveLog.yes', '记录', 'Recorded'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (189, 'dictData.neVersionStatus.upload', '已上传', 'Uploaded'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (190, 'dictData.neVersionStatus.inactive', '未激活', 'Inactivated'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (191, 'dictData.neVersionStatus.active', '已激活', 'Activated'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (192, 'dictData.alarmStatus.history', '历史告警', 'Historical Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (193, 'dictData.alarmStatus.active', '活动告警', 'Active Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (194, 'dictData.export.code', '数据代码', 'Data Code'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (195, 'dictData.export.sort', '数据排序', 'Data Sort'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (196, 'dictData.export.label', '数据标签', 'Data Key'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (197, 'dictData.export.value', '数据键值', 'Data Value'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (198, 'dictData.export.type', '数据排序', 'Data Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (199, 'dictData.export.status', '数据状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (200, 'dictData.datascope.all', '全部数据权限', 'All data permissions'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (201, 'dictData.datascope.custom', '自定数据权限', 'Customized Data Rights'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (202, 'dictData.datascope.dept', '部门数据权限', 'Departmental Data Permissions'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (203, 'dictData.datascope.deptAndChid', '部门及以下数据权限', 'Department and below'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (204, 'dictData.datascope.self', '仅本人数据权限', 'Personal data access only'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (205, 'dictData.noData', '没有可访问字典编码数据!', 'There is no accessible dictionary code data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (206, 'dictData.errLabelExists', '操作数据【{name}】失败,该字典类型下标签名已存在', 'Failed to manipulate data [{name}], tag name already exists under this dictionary type!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (207, 'dictType.sys_user_sex', '用户性别', 'User Gender'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (208, 'dictType.sys_show_hide', '菜单状态', 'Menu Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (209, 'dictType.sys_normal_disable', '系统开关', 'System switches'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (210, 'dictType.sys_job_status', '任务状态', 'Task Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (211, 'dictType.sys_job_group', '任务分组', 'Task Grouping'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (212, 'dictType.sys_yes_no', '系统是否', 'System or not'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (213, 'dictType.sys_oper_type', '操作类型', 'Operation Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (214, 'dictType.sys_common_status', '系统状态', 'System Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (215, 'dictType.trace_type', '跟踪类型', 'Trace Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (216, 'menu.tools.ps', '进程运行程序', 'Process Running Program'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (217, 'dictType.alarm_status', '告警日志类型', 'Alarm Log Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (218, 'menu.tools.net', '进程网络连接', 'Process Net Connection'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (219, 'dictType.ne_version_status', '网元软件版本状态', 'Network element software version status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (220, 'dictType.sys_user_sex_remark', '用户性别列表', 'User gender list'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (221, 'dictType.sys_show_hide_remark', '菜单状态列表', 'Menu Status List'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (222, 'dictType.sys_normal_disable_remark', '系统开关列表', 'System switch list'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (223, 'dictType.sys_job_status_remark', '任务状态列表', 'Task Status List'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (224, 'dictType.sys_job_group_remark', '任务分组列表', 'Task Grouping List'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (225, 'dictType.sys_yes_no_remark', '系统是否列表', 'System whether list'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (226, 'dictType.sys_oper_type_remark', '操作类型列表', 'Operation type list'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (227, 'dictType.sys_common_status_remark', '登录状态列表', 'Login Status List'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (228, 'dictType.trace_type_remark', '跟踪类型', 'Trace Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (229, 'dictType.alarm_status_remark', '告警日志状态类型', 'Alarm Log Status Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (230, 'menu.trace.tshark', '信令分析', 'Signaling Analysis'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (231, 'menu.trace.wireshark', '信令跟踪', 'Signaling Trace'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (232, 'dictType.ne_version_status_remark', '网元软件版本状态', 'Network element software version status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (233, 'dictType.export.id', '字典编号', 'Dictionary Number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (234, 'dictType.export.name', '字典名称', 'Dictionary Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (235, 'dictType.export.type', '字典类型', 'Dictionary Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (236, 'dictType.export.status', '字典状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (237, 'dictType.sys_role_datascope', '系统角色数据范围', 'System Role Data Range'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (238, 'dictType.sys_role_datascope_remark', '系统角色数据范围映射', 'System Role Data Range Mapping'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (239, 'dictType.noData', '没有可访问字典类型数据!', 'There is no accessible dictionary type data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (240, 'dictType.errNameExists', '操作字典【{name}】失败,字典名称已存在', 'Failed to manipulate dictionary [{name}], dictionary name already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (241, 'dictType.errTypeExists', '操作字典【{name}】失败,字典类型已存在', 'Failed to manipulate dictionary [{name}], dictionary type already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (242, 'dept.root', '系统', 'System'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (243, 'dept.root.item1', '未分配', 'Unallocated'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (244, 'dept.noData', '没有可访问部门数据!', 'There is no accessible department data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (245, 'dept.errParentDelFlag', '上级部门【{name}】已删除,不允许新增', 'The parent department [{name}] has been deleted and is not allowed to be added.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (246, 'dept.errParentStatus', '上级部门【{name}】停用,不允许新增', 'Parent department [{name}] is deactivated, additions are not allowed!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (247, 'dept.errNameExists', '操作部门【{name}】失败,部门名称已存在', 'Manipulate department [{name}] failed, department name already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (248, 'dept.errParentID', '操作部门【{name}】失败,上级部门不能是自己', 'Failed to operate department [{name}], the parent department cannot be itself.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (249, 'dept.errHasChildUse', '操作失败,该部门包含未停用的子部门数量:{num}', 'Operation failed, the department contains undeactivated sub-departments number: {num}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (250, 'dept.errHasUserUse', '不允许删除,部门已分配给用户数:{num}', 'Deletion is not allowed, number of users the department has been assigned to: {num}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (251, 'config.sys.user.initPassword', '用户管理-账号初始密码', 'User Management-Account Initial Password'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (252, 'config.sys.account.captchaEnabled', '账号自助-验证码开关', 'Account self-help-Certification code switch'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (253, 'config.sys.account.registerUser', '账号自助-是否开启用户注册功能', 'Account self-service-Whether to enable the user registration function'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (254, 'config.sys.user.maxRetryCount', '用户管理-密码最大错误次数', 'User Management-Maximum number of password errors'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (255, 'config.sys.user.lockTime', '用户管理-密码锁定时间', 'User Management-Password Lock Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (256, 'config.monitor.sysResource.storeDays', '监控-系统资源-数据保留时长', 'Monitor-System Resources-Data retention time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (257, 'config.sys.logo.type', '系统设置-LOGO类型', 'System Settings-Logo Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (258, 'config.sys.logo.filePathIcon', '系统设置-LOGO文件icon', 'System Settings-Logo File icon'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (259, 'config.sys.logo.filePathBrand', '系统设置-LOGO文件brand', 'System Settings-Logo File Brand'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (260, 'config.sys.loginBackground', '系统设置-登录界面背景', 'System Settings-Login Interface Background'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (261, 'config.sys.title', '系统设置-系统名称', 'System Settings-System Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (262, 'config.sys.copyright', '系统设置-版权声明', 'System Settings-Copyright Notice'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (263, 'config.sys.user.initPasswordRemark', '导入用户初始化密码', 'Import user initialization password'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (264, 'config.sys.account.captchaEnabledRemark', '是否开启验证码功能(true开启,false关闭)', 'Whether to enable the verification code function (true on, false off)'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (265, 'config.sys.account.registerUserRemark', '是否开启注册用户功能(true开启,false关闭)', 'Whether to enable the function of registered users (true on, false off)'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (266, 'config.sys.user.maxRetryCountRemark', '密码最大错误次数', 'Maximum number of password errors'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (267, 'config.sys.user.lockTimeRemark', '密码锁定时间,单位分钟(默认10分钟)', 'Password lock time in minutes (default 10 minutes)'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (268, 'config.monitor.sysResource.storeDaysRemark', '监控-系统资源-数据保留时长,单位天。根据当前日期,删除超过保留时长的日期数据信息。', 'Monitor-System Resources-Data retention time, in days. According to the current date, delete the date data information that exceeds the retention time.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (269, 'config.sys.logo.typeRemark', '全图:brand +REPLACE INTO "sys_i18n" VALUES (78, 'menu.traceRemark', '跟踪管理目录', 'Tracking Management Menu'); +REPLACE INTO "sys_i18n" VALUES (79, 'menu.trace.taskRemark', '跟踪任务菜单', 'Tracking Task Menu'); +REPLACE INTO "sys_i18n" VALUES (80, 'config.sys.user.fristPasswdChange', '用户管理-首次登录密码修改', 'User Management-First Login Password Change'); +REPLACE INTO "sys_i18n" VALUES (81, 'menu.trace.pcapRemark', '信令抓包菜单', 'Signaling Capture Menu'); +REPLACE INTO "sys_i18n" VALUES (82, 'menu.faultRemark', '故障管理目录', 'Fault Management Catalog'); +REPLACE INTO "sys_i18n" VALUES (83, 'menu.fault.active', '活动告警', 'Active Alarms'); +REPLACE INTO "sys_i18n" VALUES (84, 'menu.log', '日志', 'Logs'); +REPLACE INTO "sys_i18n" VALUES (85, 'menu.log.mml', 'MML日志', 'MML Logs'); +REPLACE INTO "sys_i18n" VALUES (86, 'menu.log.alarm', '告警日志', 'Alarm Logs'); +REPLACE INTO "sys_i18n" VALUES (87, 'menu.log.forwarding', '告警前转日志', 'Alarm Forwarding Logs'); +REPLACE INTO "sys_i18n" VALUES (88, 'menu.log.set', '日志设置', 'Log Settings'); +REPLACE INTO "sys_i18n" VALUES (89, 'menu.monitor.sessionUser', '用户会话', 'User Sessions'); +REPLACE INTO "sys_i18n" VALUES (90, 'menu.fault.history', '历史告警', 'Historical Alarms'); +REPLACE INTO "sys_i18n" VALUES (91, 'menu.fault.set', '设置', 'Settings'); +REPLACE INTO "sys_i18n" VALUES (92, 'menu.perf', '性能', 'Performance'); +REPLACE INTO "sys_i18n" VALUES (93, 'menu.fault.activemRemark', '活动告警菜单', 'Active Alarm Menu'); +REPLACE INTO "sys_i18n" VALUES (94, 'menu.logRemark', '日志管理目录', 'Log Management Catalog'); +REPLACE INTO "sys_i18n" VALUES (95, 'menu.log.operatOldRemark', '操作日志旧layui菜单', 'Operation log old layui menu'); +REPLACE INTO "sys_i18n" VALUES (96, 'menu.log.mmlRemark', '操作MML日志', 'Operation MML Log'); +REPLACE INTO "sys_i18n" VALUES (97, 'menu.log.alarmRemark', '告警日志菜单', 'Alarm Log Menu'); +REPLACE INTO "sys_i18n" VALUES (98, 'menu.log.securityOldRemark', '安全日志旧layui菜单', 'Security Log Old Layui Menu'); +REPLACE INTO "sys_i18n" VALUES (99, 'menu.log.forwardingRemark', '告警前转日志菜单', 'Alarm forward log menu'); +REPLACE INTO "sys_i18n" VALUES (100, 'menu.log.setRemark', '日志设置菜单', 'Log Settings menu'); +REPLACE INTO "sys_i18n" VALUES (101, 'menu.monitor.sessionUserRemark', '用户会话旧layui菜单', 'User Session Old Layui Menu'); +REPLACE INTO "sys_i18n" VALUES (102, 'menu.fault.historyRemark', '历史告警菜单', 'Alarm history menu'); +REPLACE INTO "sys_i18n" VALUES (103, 'menu.fault.setRemark', '故障通用设置菜单', 'Fault General Setup Menu'); +REPLACE INTO "sys_i18n" VALUES (104, 'menu.perfRemark', '性能目录', 'Performance Catalog'); +REPLACE INTO "sys_i18n" VALUES (105, 'menu.perf.task', '任务管理', 'Performance Tasks'); +REPLACE INTO "sys_i18n" VALUES (106, 'menu.perf.data', '性能数据', 'Performance Data'); +REPLACE INTO "sys_i18n" VALUES (107, 'menu.perf.kpiOverView', '关键指标概览', 'Key Performance Overview'); +REPLACE INTO "sys_i18n" VALUES (108, 'menu.perf.threshold', '性能门限', 'Performance Thresholds'); +REPLACE INTO "sys_i18n" VALUES (109, 'menu.perf.kpi', '关键指标', 'Key Performance Indicators'); +REPLACE INTO "sys_i18n" VALUES (110, 'menu.perf.customTarget', '自定义指标', 'Custom Indicator Management'); +REPLACE INTO "sys_i18n" VALUES (111, 'menu.perf.kpiKeyTarget', '关键指标报表', 'Key Performance Reports'); +REPLACE INTO "sys_i18n" VALUES (112, 'menu.mml', 'MML', 'MML'); +REPLACE INTO "sys_i18n" VALUES (113, 'menu.mml.ne', '网元操作', 'NE Operation'); +REPLACE INTO "sys_i18n" VALUES (114, 'menu.mml.udm', 'UDM操作', 'UDM Operation'); +REPLACE INTO "sys_i18n" VALUES (115, 'menu.mml.set', 'MML设置', 'MML Settings'); +REPLACE INTO "sys_i18n" VALUES (116, 'menu.mml.omc', 'OMC操作', 'OMC Operation'); +REPLACE INTO "sys_i18n" VALUES (117, 'menu.perf.taskRemark', '任务管理菜单', 'Task Management Menu'); +REPLACE INTO "sys_i18n" VALUES (118, 'menu.perf.dataRemark', '性能数据菜单', 'Performance Data Menu'); +REPLACE INTO "sys_i18n" VALUES (119, 'menu.dashboard.smscCDR.content', '可见短信内容', 'Visible SMS content'); +REPLACE INTO "sys_i18n" VALUES (120, 'menu.perf.thresholdRemark', '性能门限菜单', 'Performance Threshold Menu'); +REPLACE INTO "sys_i18n" VALUES (121, 'menu.perf.kpiRemark', '黄金指标菜单', 'Key Performance Indicator Menu'); +REPLACE INTO "sys_i18n" VALUES (122, 'menu.perf.customTargetRemark', '自定义指标菜单', 'Custom Indicator Management Menu'); +REPLACE INTO "sys_i18n" VALUES (123, 'menu.dashboard.smfCDRByIMSI', '数据流量报表', 'Data Usage Report'); +REPLACE INTO "sys_i18n" VALUES (124, 'menu.mmlRemark', 'MML管理目录', 'MML Management Catalog'); +REPLACE INTO "sys_i18n" VALUES (125, 'menu.mml.neRemark', '网元操作菜单', 'Network Element Operations Menu'); +REPLACE INTO "sys_i18n" VALUES (126, 'menu.mml.udmRemark', '网元UDM用户数据菜单', 'Network Element UDM User Data Menu'); +REPLACE INTO "sys_i18n" VALUES (127, 'menu.mml.setRemark', 'MML设置菜单', 'MML Setup Menu'); +REPLACE INTO "sys_i18n" VALUES (128, 'menu.mml.omcRemark', 'OMC操作菜单', 'OMC Operation Menu'); +REPLACE INTO "sys_i18n" VALUES (129, 'menu.dashboard.sgwcCDR', '漫游数据话单', 'Roaming Data CDR'); +REPLACE INTO "sys_i18n" VALUES (130, 'menu.security', '安全', 'Security'); +REPLACE INTO "sys_i18n" VALUES (131, 'menu.system.systemSet', '系统设置', 'System Settings'); +REPLACE INTO "sys_i18n" VALUES (132, 'menu.system.systemResource', '系统资源', 'System Resources'); +REPLACE INTO "sys_i18n" VALUES (133, 'log.operate.title.sgwcCDR', '漫游数据话单', 'Roaming Data CDR'); +REPLACE INTO "sys_i18n" VALUES (134, 'menu.securityRemark', '安全管理目录', 'Security Management Catalog'); +REPLACE INTO "sys_i18n" VALUES (135, 'menu.system.systemSetRemark', '系统设置菜单', 'System Settings Menu'); +REPLACE INTO "sys_i18n" VALUES (136, 'menu.system.systemResourceRemark', '系统资源 cpu io network菜单', 'System Resources cpu io network menu'); +REPLACE INTO "sys_i18n" VALUES (137, 'dictData.offline', '离线', 'Offline'); +REPLACE INTO "sys_i18n" VALUES (138, 'dictData.online', '在线', 'Online'); +REPLACE INTO "sys_i18n" VALUES (139, 'menu.neData.baseStation', '基站状态', 'Radio State'); +REPLACE INTO "sys_i18n" VALUES (140, 'menu.noData', '没有可访问菜单数据!', 'There is no accessible menu data!'); +REPLACE INTO "sys_i18n" VALUES (141, 'menu.errNameExists', '操作菜单【{name}】失败,菜单名称已存在', 'Failed to operate menu [{name}], menu name already exists!'); +REPLACE INTO "sys_i18n" VALUES (142, 'menu.errPathExists', '操作菜单【{name}】失败,菜单路由地址已存在', 'Failed to operate menu [{name}], menu routing address already exists!'); +REPLACE INTO "sys_i18n" VALUES (143, 'menu.errFramePath', '操作菜单【{name}】失败,非内部地址请以http(s)://开头', 'Failed to manipulate menu [{name}], non-internal address should start with http(s)://'); +REPLACE INTO "sys_i18n" VALUES (144, 'menu.errParentStatus', '上级菜单未启用!', 'The parent menu is not enabled!'); +REPLACE INTO "sys_i18n" VALUES (145, 'menu.errHasChildUse', '操作菜单【{name}】失败,存在使用子菜单数:{num}', 'Operation menu [{name}] failed, number of submenus in use exists: {num}'); +REPLACE INTO "sys_i18n" VALUES (146, 'menu.errHasRoleUse', '操作菜单【{name}】失败,菜单已分配给角色数:{num}', 'Operation menu [{name}] failed, number of roles the menu has been assigned to: {num}'); +REPLACE INTO "sys_i18n" VALUES (147, 'dictData.sex.un', '未选择', 'Not Selected'); +REPLACE INTO "sys_i18n" VALUES (148, 'dictData.sex.male', '男', 'Male'); +REPLACE INTO "sys_i18n" VALUES (149, 'dictData.sex.female', '女', 'Female'); +REPLACE INTO "sys_i18n" VALUES (150, 'dictData.show', '显示', 'Show'); +REPLACE INTO "sys_i18n" VALUES (151, 'dictData.hide', '隐藏', 'Hide'); +REPLACE INTO "sys_i18n" VALUES (152, 'dictData.normal', '正常', 'Active'); +REPLACE INTO "sys_i18n" VALUES (153, 'dictData.disable', '停用', 'Inactive'); +REPLACE INTO "sys_i18n" VALUES (154, 'dictData.yes', '是', 'Yes'); +REPLACE INTO "sys_i18n" VALUES (155, 'dictData.no', '否', 'No'); +REPLACE INTO "sys_i18n" VALUES (156, 'dictData.success', '成功', 'Successful'); +REPLACE INTO "sys_i18n" VALUES (157, 'dictData.fail', '失败', 'Failed'); +REPLACE INTO "sys_i18n" VALUES (158, 'dictData.jobStatus.normal', '正常', 'Active'); +REPLACE INTO "sys_i18n" VALUES (159, 'dictData.jobStatus.pause', '暂停', 'Inactive'); +REPLACE INTO "sys_i18n" VALUES (160, 'dictData.jobGroup.Default', '默认', 'Default'); +REPLACE INTO "sys_i18n" VALUES (161, 'dictData.jobGroup.System', '系统', 'System'); +REPLACE INTO "sys_i18n" VALUES (162, 'dictData.operType.other', '其他', 'Other'); +REPLACE INTO "sys_i18n" VALUES (163, 'dictData.operType.add', '新增', 'New'); +REPLACE INTO "sys_i18n" VALUES (164, 'dictData.operType.edit', '修改', 'Modify'); +REPLACE INTO "sys_i18n" VALUES (165, 'dictData.operType.delete', '删除', 'Delete'); +REPLACE INTO "sys_i18n" VALUES (166, 'dictData.operType.auth', '授权', 'Authorization'); +REPLACE INTO "sys_i18n" VALUES (167, 'dictData.operType.export', '导出', 'Export'); +REPLACE INTO "sys_i18n" VALUES (168, 'dictData.operType.import', '导入', 'Import'); +REPLACE INTO "sys_i18n" VALUES (169, 'dictData.operType.forced quit', '强退', 'Forced Retirement'); +REPLACE INTO "sys_i18n" VALUES (170, 'dictData.operType.clear', '清空', 'Clear'); +REPLACE INTO "sys_i18n" VALUES (171, 'dictData.trace.interface', '接口跟踪', 'Interface Tracing'); +REPLACE INTO "sys_i18n" VALUES (172, 'dictData.trace.device', '设备跟踪', 'Module Tracing'); +REPLACE INTO "sys_i18n" VALUES (173, 'dictData.trace.user', '用户跟踪', 'User Tracing'); +REPLACE INTO "sys_i18n" VALUES (174, 'nbState.export.id', '编号', 'ID'); +REPLACE INTO "sys_i18n" VALUES (175, 'nbState.export.name', '基站名称', 'Name'); +REPLACE INTO "sys_i18n" VALUES (176, 'nbState.export.position', '基站位置', 'Position'); +REPLACE INTO "sys_i18n" VALUES (177, 'nbState.export.address', 'IP地址', 'IP Address'); +REPLACE INTO "sys_i18n" VALUES (178, 'nbState.export.nbName', '设备名称', 'RanNodeName'); +REPLACE INTO "sys_i18n" VALUES (179, 'nbState.export.ueNum', '在线用户数', 'UE Number'); +REPLACE INTO "sys_i18n" VALUES (180, 'nbState.export.state', '基站状态', 'State'); +REPLACE INTO "sys_i18n" VALUES (181, 'nbState.export.time', '变更时间', 'Change Time'); +REPLACE INTO "sys_i18n" VALUES (182, 'neHost.okBySSHLink', '设置免密直连成功', 'Setting up a password-free direct connection is successful'); +REPLACE INTO "sys_i18n" VALUES (183, 'neHost.banNE', '禁止操作网元', 'Do not operate the NE'); +REPLACE INTO "sys_i18n" VALUES (184, 'dictData.ne_host_type.redis', 'Redis', 'Redis'); +REPLACE INTO "sys_i18n" VALUES (185, 'menu.tools.ping', '网络探测测试', 'Net Probing Test'); +REPLACE INTO "sys_i18n" VALUES (186, 'menu.tools.iperf', '网络性能测试', 'Net Performance Test'); +REPLACE INTO "sys_i18n" VALUES (187, 'dictData.jobSaveLog.no', '不记录', 'No Record'); +REPLACE INTO "sys_i18n" VALUES (188, 'dictData.jobSaveLog.yes', '记录', 'Recorded'); +REPLACE INTO "sys_i18n" VALUES (189, 'dictData.neVersionStatus.upload', '已上传', 'Uploaded'); +REPLACE INTO "sys_i18n" VALUES (190, 'dictData.neVersionStatus.inactive', '未激活', 'Inactivated'); +REPLACE INTO "sys_i18n" VALUES (191, 'dictData.neVersionStatus.active', '已激活', 'Activated'); +REPLACE INTO "sys_i18n" VALUES (192, 'dictData.alarmStatus.history', '历史告警', 'Historical Alarm'); +REPLACE INTO "sys_i18n" VALUES (193, 'dictData.alarmStatus.active', '活动告警', 'Active Alarm'); +REPLACE INTO "sys_i18n" VALUES (194, 'dictData.export.code', '数据代码', 'Data Code'); +REPLACE INTO "sys_i18n" VALUES (195, 'dictData.export.sort', '数据排序', 'Data Sort'); +REPLACE INTO "sys_i18n" VALUES (196, 'dictData.export.label', '数据标签', 'Data Key'); +REPLACE INTO "sys_i18n" VALUES (197, 'dictData.export.value', '数据键值', 'Data Value'); +REPLACE INTO "sys_i18n" VALUES (198, 'dictData.export.type', '数据排序', 'Data Type'); +REPLACE INTO "sys_i18n" VALUES (199, 'dictData.export.status', '数据状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (200, 'dictData.datascope.all', '全部数据权限', 'All data permissions'); +REPLACE INTO "sys_i18n" VALUES (201, 'dictData.datascope.custom', '自定数据权限', 'Customized Data Rights'); +REPLACE INTO "sys_i18n" VALUES (202, 'dictData.datascope.dept', '部门数据权限', 'Departmental Data Permissions'); +REPLACE INTO "sys_i18n" VALUES (203, 'dictData.datascope.deptAndChid', '部门及以下数据权限', 'Department and below'); +REPLACE INTO "sys_i18n" VALUES (204, 'dictData.datascope.self', '仅本人数据权限', 'Personal data access only'); +REPLACE INTO "sys_i18n" VALUES (205, 'dictData.noData', '没有可访问字典编码数据!', 'There is no accessible dictionary code data!'); +REPLACE INTO "sys_i18n" VALUES (206, 'dictData.errLabelExists', '操作数据【{name}】失败,该字典类型下标签名已存在', 'Failed to manipulate data [{name}], tag name already exists under this dictionary type!'); +REPLACE INTO "sys_i18n" VALUES (207, 'dictType.sys_user_sex', '用户性别', 'User Gender'); +REPLACE INTO "sys_i18n" VALUES (208, 'dictType.sys_show_hide', '菜单状态', 'Menu Status'); +REPLACE INTO "sys_i18n" VALUES (209, 'dictType.sys_normal_disable', '系统开关', 'System switches'); +REPLACE INTO "sys_i18n" VALUES (210, 'dictType.sys_job_status', '任务状态', 'Task Status'); +REPLACE INTO "sys_i18n" VALUES (211, 'dictType.sys_job_group', '任务分组', 'Task Grouping'); +REPLACE INTO "sys_i18n" VALUES (212, 'dictType.sys_yes_no', '系统是否', 'System or not'); +REPLACE INTO "sys_i18n" VALUES (213, 'dictType.sys_oper_type', '操作类型', 'Operation Type'); +REPLACE INTO "sys_i18n" VALUES (214, 'dictType.sys_common_status', '系统状态', 'System Status'); +REPLACE INTO "sys_i18n" VALUES (215, 'dictType.trace_type', '跟踪类型', 'Trace Types'); +REPLACE INTO "sys_i18n" VALUES (216, 'menu.tools.ps', '进程运行程序', 'Process Running Program'); +REPLACE INTO "sys_i18n" VALUES (217, 'dictType.alarm_status', '告警日志类型', 'Alarm Log Type'); +REPLACE INTO "sys_i18n" VALUES (218, 'menu.tools.net', '进程网络连接', 'Process Net Connection'); +REPLACE INTO "sys_i18n" VALUES (219, 'dictType.ne_version_status', '网元软件版本状态', 'Network element software version status'); +REPLACE INTO "sys_i18n" VALUES (220, 'dictType.sys_user_sex_remark', '用户性别列表', 'User gender list'); +REPLACE INTO "sys_i18n" VALUES (221, 'dictType.sys_show_hide_remark', '菜单状态列表', 'Menu Status List'); +REPLACE INTO "sys_i18n" VALUES (222, 'dictType.sys_normal_disable_remark', '系统开关列表', 'System switch list'); +REPLACE INTO "sys_i18n" VALUES (223, 'dictType.sys_job_status_remark', '任务状态列表', 'Task Status List'); +REPLACE INTO "sys_i18n" VALUES (224, 'dictType.sys_job_group_remark', '任务分组列表', 'Task Grouping List'); +REPLACE INTO "sys_i18n" VALUES (225, 'dictType.sys_yes_no_remark', '系统是否列表', 'System whether list'); +REPLACE INTO "sys_i18n" VALUES (226, 'dictType.sys_oper_type_remark', '操作类型列表', 'Operation type list'); +REPLACE INTO "sys_i18n" VALUES (227, 'dictType.sys_common_status_remark', '登录状态列表', 'Login Status List'); +REPLACE INTO "sys_i18n" VALUES (228, 'dictType.trace_type_remark', '跟踪类型', 'Trace Types'); +REPLACE INTO "sys_i18n" VALUES (229, 'dictType.alarm_status_remark', '告警日志状态类型', 'Alarm Log Status Type'); +REPLACE INTO "sys_i18n" VALUES (230, 'menu.trace.tshark', '信令分析', 'Signaling Analysis'); +REPLACE INTO "sys_i18n" VALUES (231, 'menu.trace.wireshark', '信令跟踪', 'Signaling Trace'); +REPLACE INTO "sys_i18n" VALUES (232, 'dictType.ne_version_status_remark', '网元软件版本状态', 'Network element software version status'); +REPLACE INTO "sys_i18n" VALUES (233, 'dictType.export.id', '字典编号', 'Dictionary Number'); +REPLACE INTO "sys_i18n" VALUES (234, 'dictType.export.name', '字典名称', 'Dictionary Name'); +REPLACE INTO "sys_i18n" VALUES (235, 'dictType.export.type', '字典类型', 'Dictionary Type'); +REPLACE INTO "sys_i18n" VALUES (236, 'dictType.export.status', '字典状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (237, 'dictType.sys_role_datascope', '系统角色数据范围', 'System Role Data Range'); +REPLACE INTO "sys_i18n" VALUES (238, 'dictType.sys_role_datascope_remark', '系统角色数据范围映射', 'System Role Data Range Mapping'); +REPLACE INTO "sys_i18n" VALUES (239, 'dictType.noData', '没有可访问字典类型数据!', 'There is no accessible dictionary type data!'); +REPLACE INTO "sys_i18n" VALUES (240, 'dictType.errNameExists', '操作字典【{name}】失败,字典名称已存在', 'Failed to manipulate dictionary [{name}], dictionary name already exists!'); +REPLACE INTO "sys_i18n" VALUES (241, 'dictType.errTypeExists', '操作字典【{name}】失败,字典类型已存在', 'Failed to manipulate dictionary [{name}], dictionary type already exists!'); +REPLACE INTO "sys_i18n" VALUES (242, 'dept.root', '系统', 'System'); +REPLACE INTO "sys_i18n" VALUES (243, 'dept.root.item1', '未分配', 'Unallocated'); +REPLACE INTO "sys_i18n" VALUES (244, 'dept.noData', '没有可访问部门数据!', 'There is no accessible department data!'); +REPLACE INTO "sys_i18n" VALUES (245, 'dept.errParentDelFlag', '上级部门【{name}】已删除,不允许新增', 'The parent department [{name}] has been deleted and is not allowed to be added.'); +REPLACE INTO "sys_i18n" VALUES (246, 'dept.errParentStatus', '上级部门【{name}】停用,不允许新增', 'Parent department [{name}] is deactivated, additions are not allowed!'); +REPLACE INTO "sys_i18n" VALUES (247, 'dept.errNameExists', '操作部门【{name}】失败,部门名称已存在', 'Manipulate department [{name}] failed, department name already exists!'); +REPLACE INTO "sys_i18n" VALUES (248, 'dept.errParentID', '操作部门【{name}】失败,上级部门不能是自己', 'Failed to operate department [{name}], the parent department cannot be itself.'); +REPLACE INTO "sys_i18n" VALUES (249, 'dept.errHasChildUse', '操作失败,该部门包含未停用的子部门数量:{num}', 'Operation failed, the department contains undeactivated sub-departments number: {num}'); +REPLACE INTO "sys_i18n" VALUES (250, 'dept.errHasUserUse', '不允许删除,部门已分配给用户数:{num}', 'Deletion is not allowed, number of users the department has been assigned to: {num}'); +REPLACE INTO "sys_i18n" VALUES (251, 'config.sys.user.initPassword', '用户管理-账号初始密码', 'User Management-Account Initial Password'); +REPLACE INTO "sys_i18n" VALUES (252, 'config.sys.account.captchaEnabled', '账号自助-验证码开关', 'Account self-help-Certification code switch'); +REPLACE INTO "sys_i18n" VALUES (253, 'config.sys.account.registerUser', '账号自助-是否开启用户注册功能', 'Account self-service-Whether to enable the user registration function'); +REPLACE INTO "sys_i18n" VALUES (254, 'config.sys.user.maxRetryCount', '用户管理-密码最大错误次数', 'User Management-Maximum number of password errors'); +REPLACE INTO "sys_i18n" VALUES (255, 'config.sys.user.lockTime', '用户管理-密码锁定时间', 'User Management-Password Lock Time'); +REPLACE INTO "sys_i18n" VALUES (256, 'config.monitor.sysResource.storeDays', '监控-系统资源-数据保留时长', 'Monitor-System Resources-Data retention time'); +REPLACE INTO "sys_i18n" VALUES (257, 'config.sys.logo.type', '系统设置-LOGO类型', 'System Settings-Logo Type'); +REPLACE INTO "sys_i18n" VALUES (258, 'config.sys.logo.filePathIcon', '系统设置-LOGO文件icon', 'System Settings-Logo File icon'); +REPLACE INTO "sys_i18n" VALUES (259, 'config.sys.logo.filePathBrand', '系统设置-LOGO文件brand', 'System Settings-Logo File Brand'); +REPLACE INTO "sys_i18n" VALUES (260, 'config.sys.loginBackground', '系统设置-登录界面背景', 'System Settings-Login Interface Background'); +REPLACE INTO "sys_i18n" VALUES (261, 'config.sys.title', '系统设置-系统名称', 'System Settings-System Name'); +REPLACE INTO "sys_i18n" VALUES (262, 'config.sys.copyright', '系统设置-版权声明', 'System Settings-Copyright Notice'); +REPLACE INTO "sys_i18n" VALUES (263, 'config.sys.user.initPasswordRemark', '导入用户初始化密码', 'Import user initialization password'); +REPLACE INTO "sys_i18n" VALUES (264, 'config.sys.account.captchaEnabledRemark', '是否开启验证码功能(true开启,false关闭)', 'Whether to enable the verification code function (true on, false off)'); +REPLACE INTO "sys_i18n" VALUES (265, 'config.sys.account.registerUserRemark', '是否开启注册用户功能(true开启,false关闭)', 'Whether to enable the function of registered users (true on, false off)'); +REPLACE INTO "sys_i18n" VALUES (266, 'config.sys.user.maxRetryCountRemark', '密码最大错误次数', 'Maximum number of password errors'); +REPLACE INTO "sys_i18n" VALUES (267, 'config.sys.user.lockTimeRemark', '密码锁定时间,单位分钟(默认10分钟)', 'Password lock time in minutes (default 10 minutes)'); +REPLACE INTO "sys_i18n" VALUES (268, 'config.monitor.sysResource.storeDaysRemark', '监控-系统资源-数据保留时长,单位天。根据当前日期,删除超过保留时长的日期数据信息。', 'Monitor-System Resources-Data retention time, in days. According to the current date, delete the date data information that exceeds the retention time.'); +REPLACE INTO "sys_i18n" VALUES (269, 'config.sys.logo.typeRemark', '全图:brand 小图:icon', 'Full image: brand Small image: icon'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (270, 'config.sys.logo.filePathIconRemark', '文件支持网络地址图片和内部上传的文件路径', 'File support for web address images and file paths for internal uploads'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (271, 'config.sys.logo.filePathBrandRemark', '文件支持网络地址图片和内部上传的文件路径', 'File support for web address images and paths to internally uploaded files'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (272, 'config.sys.loginBackgroundRemark', '文件支持网络地址图片和内部上传的文件路径,默认背景用#号', 'The file supports web address images and internal upload file paths with a # in the default background'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (273, 'config.sys.titleRemark', '系统名称长度限制20位字符串', 'System name length limit of 20-digit string'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (274, 'config.sys.copyrightRemark', '底脚固定条,左侧放置版权声明', 'Footer fixing strip with copyright notice on the left side'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (275, 'config..export.id', '参数编号', 'ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (276, 'config..export.name', '参数名称', 'Config Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (277, 'config..export.key', '参数键名', 'Config Key'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (278, 'config..export.value', '参数键值', 'Config Value'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (279, 'config..export.type', '系统内置', 'Built In'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (280, 'config..export.remark', '参数说明', 'Config Description'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (281, 'config.sys.titleValue', 'Core Network', 'Core Network'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (282, 'config.sys.copyrightValue', 'Copyright ©2025 Core Network', 'Copyright ©2025 Core Network'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (283, 'config.noData', '没有可访问参数配置数据!', 'No parameter configuration data is accessible!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (284, 'config.errKey', '无效 key', 'Invalid key'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (285, 'config.errValueEq', '变更状态与旧值相等!', 'Change state is equal to the old value!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (286, 'config.errKeyExists', '操作参数配置【{name}】失败,参数键名已存在', 'Failed to manipulate parameter configuration [{name}], parameter key name already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (287, 'config.errDelete', '删除参数配置信息失败!', 'Deletion of parameter configuration information failed!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (288, 'config.errType', '操作含有内置参数,禁止删除!', 'The operation contains built-in parameters and deletion is prohibited!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (289, 'job.monitor_sys_resource', '监控-系统资源', 'Monitor-System Resources'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (290, 'job.monitor_sys_resource_remark', '系统资源CPU/IO/Netword收集 +REPLACE INTO "sys_i18n" VALUES (270, 'config.sys.logo.filePathIconRemark', '文件支持网络地址图片和内部上传的文件路径', 'File support for web address images and file paths for internal uploads'); +REPLACE INTO "sys_i18n" VALUES (271, 'config.sys.logo.filePathBrandRemark', '文件支持网络地址图片和内部上传的文件路径', 'File support for web address images and paths to internally uploaded files'); +REPLACE INTO "sys_i18n" VALUES (272, 'config.sys.loginBackgroundRemark', '文件支持网络地址图片和内部上传的文件路径,默认背景用#号', 'The file supports web address images and internal upload file paths with a # in the default background'); +REPLACE INTO "sys_i18n" VALUES (273, 'config.sys.titleRemark', '系统名称长度限制20位字符串', 'System name length limit of 20-digit string'); +REPLACE INTO "sys_i18n" VALUES (274, 'config.sys.copyrightRemark', '底脚固定条,左侧放置版权声明', 'Footer fixing strip with copyright notice on the left side'); +REPLACE INTO "sys_i18n" VALUES (275, 'config..export.id', '参数编号', 'ID'); +REPLACE INTO "sys_i18n" VALUES (276, 'config..export.name', '参数名称', 'Config Name'); +REPLACE INTO "sys_i18n" VALUES (277, 'config..export.key', '参数键名', 'Config Key'); +REPLACE INTO "sys_i18n" VALUES (278, 'config..export.value', '参数键值', 'Config Value'); +REPLACE INTO "sys_i18n" VALUES (279, 'config..export.type', '系统内置', 'Built In'); +REPLACE INTO "sys_i18n" VALUES (280, 'config..export.remark', '参数说明', 'Config Description'); +REPLACE INTO "sys_i18n" VALUES (281, 'config.sys.titleValue', 'Core Network', 'Core Network'); +REPLACE INTO "sys_i18n" VALUES (282, 'config.sys.copyrightValue', 'Copyright ©2025 Core Network', 'Copyright ©2025 Core Network'); +REPLACE INTO "sys_i18n" VALUES (283, 'config.noData', '没有可访问参数配置数据!', 'No parameter configuration data is accessible!'); +REPLACE INTO "sys_i18n" VALUES (284, 'config.errKey', '无效 key', 'Invalid key'); +REPLACE INTO "sys_i18n" VALUES (285, 'config.errValueEq', '变更状态与旧值相等!', 'Change state is equal to the old value!'); +REPLACE INTO "sys_i18n" VALUES (286, 'config.errKeyExists', '操作参数配置【{name}】失败,参数键名已存在', 'Failed to manipulate parameter configuration [{name}], parameter key name already exists!'); +REPLACE INTO "sys_i18n" VALUES (287, 'config.errDelete', '删除参数配置信息失败!', 'Deletion of parameter configuration information failed!'); +REPLACE INTO "sys_i18n" VALUES (288, 'config.errType', '操作含有内置参数,禁止删除!', 'The operation contains built-in parameters and deletion is prohibited!'); +REPLACE INTO "sys_i18n" VALUES (289, 'job.monitor_sys_resource', '监控-系统资源', 'Monitor-System Resources'); +REPLACE INTO "sys_i18n" VALUES (290, 'job.monitor_sys_resource_remark', '系统资源CPU/IO/Netword收集 interval单位分钟,平均分钟资源情况 注:请根据cron表达式的时间单位分钟,传入参数interva值', 'System Resource CPU/IO/Netword Collection interval unit minutes, average minute resource situation Note: Please pass the value of the parameter interva according to the time unit minutes of the cron expression'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (291, 'job.delete_ne_config_backup', '删除-过期配置文件备份', 'Delete-Expired NE ETC Backup File'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (292, 'job.delete_ne_config_backup_remark', 'storeDays:表示保留最近天数的数据记录', 'storeDays: indicates that the most recent days of data records are kept.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (293, 'job.delete_alarm_record', '删除-过期告警记录', 'Delete-Expired Alarm Records'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (294, 'job.delete_alarm_record_remark', 'storeDays:表示保留最近天数的数据记录 +REPLACE INTO "sys_i18n" VALUES (291, 'job.delete_ne_config_backup', '删除-过期配置文件备份', 'Delete-Expired NE ETC Backup File'); +REPLACE INTO "sys_i18n" VALUES (292, 'job.delete_ne_config_backup_remark', 'storeDays:表示保留最近天数的数据记录', 'storeDays: indicates that the most recent days of data records are kept.'); +REPLACE INTO "sys_i18n" VALUES (293, 'job.delete_alarm_record', '删除-过期告警记录', 'Delete-Expired Alarm Records'); +REPLACE INTO "sys_i18n" VALUES (294, 'job.delete_alarm_record_remark', 'storeDays:表示保留最近天数的数据记录 storeNum:保留数量,默认保留7个', 'storeDays: indicates that the most recent days of data records are kept. storeNum: the number of reservations, the default reservation is 7.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (295, 'job.delete_kpi_record', '删除-过期指标记录', 'Delete-Expired KPI Records'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (296, 'job.delete_kpi_record_remark', 'storeDays:表示保留最近天数的数据记录 +REPLACE INTO "sys_i18n" VALUES (295, 'job.delete_kpi_record', '删除-过期指标记录', 'Delete-Expired KPI Records'); +REPLACE INTO "sys_i18n" VALUES (296, 'job.delete_kpi_record_remark', 'storeDays:表示保留最近天数的数据记录 neList:表示匹配的网元类型', 'storeDays: Indicates the most recent days of data records retained neList: Indicates the type of network elements matched'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (297, 'menu.neData.backupData', '导出文件', 'Exponted File'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (298, 'config.sys.user.passwordPolicyNot', '未配置密码策略', 'Password policy not configured'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (299, 'job.export.jobID', '任务编号', 'ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (300, 'job.export.jobName', '任务名称', 'Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (301, 'job.export.jobGroupName', '任务组名', 'Group'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (302, 'job.export.invokeTarget', '调用目标', 'Invoke'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (303, 'job.export.targetParams', '传入参数', 'Incoming Parameters'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (304, 'job.export.cronExpression', 'cron表达式', 'Cron'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (305, 'job.export.status', '状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (306, 'job.export.remark', '备注说明', 'Description'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (307, 'job.export.jobLogID', '任务日志编号', 'ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (308, 'job.export.jobLogStatus', '任务日志状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (309, 'job.export.jobLogTime', '任务日志时间', 'Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (310, 'job.noData', '没有可访问调度任务数据!', 'There is no accessible scheduling task data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (311, 'job.errTargetParams', '操作调度任务【{name}】失败,任务传入参数json字符串不正确', 'Failed to operate scheduling task [{name}] with incorrect task incoming parameter json string!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (312, 'job.errCronExpression', '操作调度任务【{name}】失败,Cron表达式不正确', 'Scheduled task [{name}] failed with incorrect Cron expression!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (313, 'job.errJobExists', '调度任务新增【{name}】失败,同任务组内有相同任务名称', 'Failed to add a new task [{name}] to a scheduling task, same task name in the same task group'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (314, 'job.statusEq', '变更状态与旧值相等!', 'The change state is equal to the old value!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (315, 'role.system', '系统', 'System'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (316, 'role.admin', '管理人员', 'Administrator'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (317, 'role.operator', '运维人员', 'Operators'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (318, 'role.monitor', '监控人员', 'Monitor'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (319, 'role.vistor', '普通用户', 'General Users'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (320, 'role.systemRemark', '系统,无法修改删除', 'System, cannot modify or delete'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (321, 'role.adminRemark', '管理人员 可以对设备进行任何操作', 'Administrators can perform any operation on the device'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (322, 'role.operatorRemark', '运维人员 可以从设备读取数据,并对设备进行配置,但是不能对设备进行软件升级操作。', 'Operation and maintenance personnel can read data from the device and configure the device, but cannot perform software upgrade operations on the device.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (323, 'role.monitorRemark', '监控人员 只能从设备读取数据,而不能对设备进行任何设置', 'Monitoring personnel Can only read data from the device, but cannot make any settings on the device'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (324, 'role.vistorRemark', '普通用户 只可看系统相关信息', 'Ordinary users can only see system-related information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (325, 'role.export.id', '角色编号', 'Role Number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (326, 'role.export.name', '角色名称 ', 'Role Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (327, 'role.export.key', '角色键值', 'Role Key'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (328, 'role.export.sort', '角色顺序', 'Role Sort'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (329, 'role.export.dataScope', '角色数据范围', 'Role Data Range'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (330, 'role.export.status', '角色状态', 'Role Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (331, 'role.noData', '没有可访问角色数据!', 'There is no accessible role data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (332, 'role.statusEq', '变更状态与旧值相等!', 'The change status is equal to the old value!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (333, 'role.errNameExists', '操作角色【{name}】失败,角色名称已存在', 'Manipulating role [{name}] failed, role name already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (334, 'role.errKeyExists', '操作角色【{name}】失败,角色键值已存在', 'Failed to manipulate role [{name}], role key already exists!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (335, 'post.admin', '系统', 'Systems'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (336, 'post.operator', '管理', 'Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (337, 'post.monitor', '运维', 'Operation & Maintenance'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (338, 'post.visitor', '监控', 'Monitoring'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (339, 'post.export.id', '岗位编号 ', 'Position Number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (340, 'post.export.code', '岗位编码', 'Position Code'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (341, 'post.export.name', '岗位名称', 'Position Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (342, 'post.export.sort', '岗位排序', 'Position Sort'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (343, 'post.export.status', '岗位状态', 'Position Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (344, 'post.noData', '没有可访问岗位数据!', 'There is no accessible post data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (345, 'post.errNameExists', '操作岗位【{name}】失败,岗位名称已存在已存在', 'Failed to manipulate post [{name}], post name already exists already exists'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (346, 'post.errCodeExists', '操作角色【{name}】失败,角色键值已存在', 'Failed to manipulate role [{name}], role key already exists.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (347, 'user.export.id', '用户编号', 'User Number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (348, 'user.export.name', '登录账号', 'Account'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (349, 'user.export.nick', '用户昵称', 'Nick Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (350, 'user.export.email', '电子邮箱', 'E-Mail'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (351, 'user.export.phone', '手机号码', 'Cell phone number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (352, 'user.export.sex', '用户性别', 'Gender'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (353, 'user.export.status', '用户状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (354, 'user.export.deptID', '部门编号', 'Department number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (355, 'user.export.deptName', '部门名称', 'Department'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (356, 'user.export.deptLeader', '部门负责人', 'Department Head'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (357, 'user.export.loginIP', '用户登录IP', 'Login Address'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (358, 'user.export.loginDate', '用户登录时间', 'Login Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (359, 'user.noData', '没有可访问用户数据!', 'No accessible user data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (360, 'user.statusEq', '变更状态与旧值相等!', 'The change status is equal to the old value!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (361, 'user.errPasswdOld', '修改密码失败,旧密码错误', 'Change password failed, old password is wrong'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (362, 'user.errPasswdEqOld', '新密码不能与旧密码相同', 'New password cannot be the same as the old one'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (363, 'config.sys.user.passwordPolicyError', '密码至少{minLength}位,至少包含{specialChars}个特殊字符和至少{uppercase}个大写字母和至少{lowercase}个小写字母', 'Passwords are at least {minLength} digits long and contain at least {specialChars} special characters and at least {uppercase} uppercase letter and at least {lowercase} lowercase letter.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (364, 'user.errEmailFormat', '操作用户【{name}】失败,邮箱格式错误', 'Failed to operate user [{name}], mailbox format error'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (365, 'user.errEmailExists', '操作用户【{name}】失败,邮箱已存在', 'Failed to operate user [{name}], mailbox already exists.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (366, 'user.errPhoneFormat', '操作用户【{name}】失败,手机号码格式错误', 'Failed to operate user [{name}], cell phone number format is wrong.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (367, 'user.errPhoneExists', '操作用户【{name}】失败,手机号码已存在', 'Failed to operate user [{name}], cell phone number already exists.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (368, 'user.errNameExists', '操作用户【{name}】失败,登录账号已存在', 'Failed to operate user [{name}], login account already exists.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (369, 'user.import.mustItem', '表格中必填列表项,{text}', 'Required list item in form, {text}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (370, 'user.import.phoneExist', '用户编号:{id} 手机号码 {phone} 已存在', 'User ID: {id} cell phone number {phone} Existing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (371, 'user.import.phoneFormat', '用户编号:{id} 手机号码 {phone} 格式错误', 'User ID: {id} cell phone number {phone} Wrong format'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (372, 'user.import.emailExist', '用户编号:{id} 用户邮箱:{email} 已存在', 'User ID: {id} User Email: {email} Existing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (373, 'user.import.emailFormat', '用户编号:{id} 用户邮箱:{email} 格式错误', 'User ID: {id} Email: {email} Wrong Format'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (374, 'user.import.success', '用户编号:{id} 登录名称:{name} 导入成功', 'User ID:{id} Login name:{name} Imported successfully!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (375, 'user.import.fail', '用户编号:{id} 登录名称:{name} 导入失败', 'User ID: {id} Login name: {name} Import failed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (376, 'user.import.successUpdate', '用户编号:{id} 登录名称:{name} 更新成功', 'User ID: {id} Login name: {name} Update success'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (377, 'user.import.failUpdate', '用户编号:{id} 登录名称:{name} 更新失败', 'User ID: {id} Login Name: {name} Update Failed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (378, 'user.import.failTip', '很抱歉,导入失败!共 {num} 条数据格式不正确,错误如下:', 'Sorry, the import failed! A total of {num} entries were not formatted correctly, the error is below:'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (379, 'user.import.successTip', '恭喜您,数据已全部导入成功!共 {num} 条,数据如下:', 'Congratulations, the data has been imported successfully! There are {num} entries with the following data:'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (380, 'app.common.err403', '无权访问 {method} {requestURI}', 'Unauthorized access {method} {requestURI}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (381, 'app.common.err401', '无效身份授权', 'Invalid authorization'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (382, 'app.common.err400', '参数错误', 'Parameter error'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (383, 'app.common.exportEmpty', '导出数据记录为空', 'Export data record is empty'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (384, 'app.common.errOperateAdmin', '不允许操作内置用户', 'Built-in users are not allowed to operate'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (385, 'app.common.errOperateRole', '不允许操作内置角色', 'Built-in roles are not allowed to be operated'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (386, 'app.common.deleteSuccess', '删除成功:{num}', 'Deleted successfully: {num}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (387, 'app.common.loginSuccess', '登录成功', 'Login Success'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (388, 'app.common.logoutSuccess', '注销成功', 'Logout Successful'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (389, 'app.common.errUnlock', '该用户未被锁定', 'The user is not locked'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (390, 'app.common.noLoginUser', '登录用户信息无效', 'Invalid login user information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (391, 'app.common.rateLimitTip', '访问过于频繁,请稍候再试', 'Access too often, please try again later'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (392, 'log.operate.export.id', '操作编号', 'Log ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (393, 'log.operate.export.title', '模块名称', 'Module Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (394, 'log.operate.export.businessType', '业务类型', 'Business Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (395, 'log.operate.export.method', '操作方法', 'Operation Method'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (396, 'log.operate.export.requestMethod', '请求方式 ', 'Request Method'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (397, 'log.operate.export.operatorType', '操作类型', 'Operation Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (398, 'log.operate.export.operName', '操作人员', 'Operator'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (399, 'log.operate.export.deptName', '操作人员部门名称', 'Operator Department Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (400, 'log.operate.export.url', '请求链接地址', 'Request URL'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (401, 'log.operate.export.ip', '请求主机 ', 'Request Host'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (402, 'log.operate.export.location', '请求地址', 'Request Address'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (403, 'log.operate.export.param', '请求参数', 'Request Parameters'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (404, 'log.operate.export.msg', '操作信息', 'Operation Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (405, 'log.operate.export.status', '操作状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (406, 'log.operate.export.costTime', '消耗时间(毫秒)', 'Time Consumption (ms)'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (407, 'log.operate.export.operTime', '操作时间', 'Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (408, 'log.login.export.id', '记录编号', 'Log ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (409, 'log.login.export.userName', '登录账号', 'Login Account'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (410, 'log.login.export.status', '登录状态', 'Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (411, 'log.login.export.ip', '登录地址', 'Login Address'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (412, 'log.login.export.location', '登录地点', 'Login Location'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (413, 'log.login.export.browser', '浏览器', 'Browser'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (414, 'log.login.export.os', '操作系统', 'Operating System'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (415, 'log.login.export.msg', '登录信息', 'Login Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (416, 'log.login.export.time', '登录时间', 'Login Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (417, 'trace.tcpdump.noData', '找不到 {type} {id} 对应网元信息', 'Can it find {type} {id} information of the corresponding network element.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (418, 'register.errUsername', '账号不能以数字开头,可包含大写小写字母,数字,且不少于5位', 'The account number cannot start with a number, but can contain upper and lower case letters, numbers, and not less than 5 digits.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (419, 'login.errPasswdExpire', '登录密码已过期', 'Login password has expired'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (420, 'register.errPasswdNotEq', '用户确认输入密码不一致', 'User confirms password inconsistency'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (421, 'register.success', '注册成功', 'Successful registration'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (422, 'register.successMsg', '{name} 注册成功 {id}', '{name} Register Successful {id}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (423, 'log.operate.title.sysJobLog', '调度任务日志', 'Scheduling Task Logs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (424, 'log.operate.title.sysJob', '调度任务', 'Scheduling Tasks'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (425, 'log.operate.title.tcpdump', '信令抓包', 'Signaling Capture'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (426, 'log.operate.title.sysConfig', '参数配置', 'Parameter Configuration'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (427, 'log.operate.title.sysDept', '部门', 'Sector'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (428, 'log.operate.title.sysDictData', '字典数据', 'Dictionary Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (429, 'log.operate.title.sysDictType', '字典类型', 'Dictionary type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (430, 'log.operate.title.sysMenu', '菜单', 'Menu'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (431, 'log.operate.title.sysPost', '岗位', 'Positions'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (432, 'log.operate.title.sysProfile', '个人信息', 'Personal Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (433, 'log.operate.title.sysProfileAvatar', '个人头像', 'Personal avatar'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (434, 'log.operate.title.sysRole', '角色', 'Roles'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (435, 'log.operate.title.sysUser', '用户', 'User'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (436, 'log.operate.title.sysLogOper', '操作日志记录', 'Operation Logging'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (437, 'log.operate.title.sysLogLogin', '登录日志记录', 'Operation Logging'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (438, 'login.errNameOrPasswd', '用户不存在或密码错误', 'User does not exist or password is wrong'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (439, 'login.errDelFlag', '对不起,您的账号已被删除', 'Sorry, your account has been deleted'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (440, 'login.errStatus', '对不起,您的帐户已被禁用', 'Sorry, your account has been disabled'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (441, 'login.errRetryPasswd', '密码输入错误多次,帐户已被锁定', 'Password was entered incorrectly several times, account has been locked'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (442, 'captcha.err', '验证码错误', 'Captcha Error'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (443, 'captcha.errValid', '验证码已失效', 'Captcha is invalid'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (444, 'app.common.noUaOsBrowser', '未知 未知', 'Unknown Unknown'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (445, 'app.common.noIPregion', '内网', 'Intranet'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (446, 'app.common.unknown', '未知', 'Unknown'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (447, 'app.common.noNEInfo', '未找到匹配网元信息', 'No matching network element information found'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (448, 'ne.udm.errImportUserAuthFileFormat', '请上传.csv或.txt的格式文件。英文逗号分割txt格式:imsi, ki, algo, amf, opc', 'Please upload a file in the format of. csv or. txt. English comma separated txt format: imsi, ki, algo, amf, opc'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (449, 'ne.udm.errExportType', '导出文件类型支持CSV和txt', 'Export file types support CSV and txt'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (450, 'ne.udm.errImportUserSubFileFormat', '请上传.csv或.txt的格式文件。英文逗号分割txt格式:imsi, msisdn, ambr, nssai, arfb, sar, rat, cn, smf_sel, sm_dat, eps_dat', 'Please upload files in .csv or .txt format. English comma-separated txt format: imsi, msisdn, ambr, nssai, arfb, sar, rat, cn, smf_sel, sm_dat, eps_dat'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (451, 'log.operate.title.udmAuth', 'UDM鉴权用户', 'UDM Authentication'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (452, 'log.operate.title.udmSub', 'UDM签约用户', 'UDM Subscriber'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (453, 'dictType.active_alarm_type', '活动告警类型', 'Event Alarm Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (454, 'dictType.active_alarm_type_remark', '活动告警类型列表', 'List of Active Alarm Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (455, 'dictData.active_alarm_type.communication', '通信告警', 'Communication Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (456, 'dictData.active_alarm_type.equipment', '设备告警', 'Equipment Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (457, 'dictData.active_alarm_type.processing', '处理错误', 'Processing Failure Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (458, 'dictData.active_alarm_type.environmental', '环境告警', 'Environmental Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (459, 'dictData.active_alarm_type.qualityOfService', '服务质量', 'Quality of Service Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (460, 'dictType.active_clear_type', '告警清除类型', 'Alarm Clearing Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (461, 'dictType.active_clear_type_remark', '告警清除类型列表', 'List of Alarm Clearing Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (462, 'dictData.active_clear_type.notCleared', '告警未清除', 'Not cleared'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (463, 'dictData.active_clear_type.hand', '手动清除', 'Manually cleared'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (464, 'dictData.active_clear_type.auto', '自动清除', 'Automatically cleared'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (465, 'dictType.active_ack_state', '告警确认类型', 'Alarm Acknowledgement Types'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (466, 'dictType.active_ack_state_remark', '告警确认类型列表', 'Alarm Acknowledgement Type List'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (467, 'dictData.active_ack_state.unconfirmed', '未确认', 'Not Confirm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (468, 'dictData.active_ack_state.confirmed', '已确认', 'Confirm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (469, 'dictType.active_alarm_severity', '严重程度', 'Severity'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (470, 'dictType.active_alarm_severity_remark', '严重程度列表', 'Severity List'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (471, 'dictData.active_alarm_severity.critical', '严重告警', 'Critical'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (472, 'dictData.active_alarm_severity.major', '主要告警', 'Major'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (473, 'dictData.active_alarm_severity.minor', '次要告警', 'Minor'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (474, 'dictData.active_alarm_severity.warning', '警告告警', 'Warning'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (475, 'dictData.active_alarm_severity.event', '事件告警', 'Event'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (476, 'config.sys.officialUrl', '系统设置-官网链接', 'System Settings - Official Website Links'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (477, 'config.sys.helpDoc', '系统设置-系统使用文档', 'System Settings-System Documentation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (478, 'config.sys.officialUrlRemark', '默认无地址用#号', 'Default no address with # sign'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (479, 'config.sys.helpDocRemark', '静态文件目录地址,使用{language}区分语言文件', 'Static file directory address, use {language} to distinguish language files'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (480, 'log.operate.title.neAction', '网元处理', 'Network Element Processing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (481, 'log.operate.title.helpDoc', '系统使用文档', 'System Usage Documentation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (482, 'menu.ueUser.n3iwf', 'N3IWF在线用户', 'N3IWF Online User'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (483, 'menu.neData.pcfSub', '用户策略控制信息', 'User PCC Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (484, 'menu.system.user.editRole', '修改用户角色', 'Modifying User Role'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (485, 'config.sys.i18nOpen', '国际化切换', 'Internationalization Switching'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (486, 'config.sys.i18nDefault', '国际化默认语言', 'Internationalization Default Language'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (487, 'user.export.role', '用户角色', 'Role'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (488, 'menu.system.setting.i18n', '国际化切换', 'Internationalization Switch'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (489, 'menu.system.setting.i18nRemark', '国际化多语言的切换选择', 'Internationalized multilingual switching options'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (490, 'dictType.index_status', '首页状态', 'Home Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (491, 'dictType.index_status_remark', '首页的网元状态颜色', 'Network element status colors on the home page'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (492, 'dictType.index_status.normal', '正常', 'Normal'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (493, 'dictType.index_status.abnormal', '异常', 'Abnormal'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (494, 'menu.log.neFile', '网元日志文件', 'NE Log File'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (495, 'menu.dashboard.overview.smfUeNum', '展示数据会话数', 'Display data session number'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (496, 'menu.dashboard.overview.imsUeNum', '展示语音会话数', 'Display the number of voice sessions'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (497, 'menu.dashboard.overview.gnbBase', '展示5G基站在线信息', 'Display 5G base station online information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (498, 'menu.dashboard.overview.enbBase', '展示4G基站在线信息', 'Display 4G base station online information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (499, 'job.ne_alarm_state_check', '网元告警-状态检查', 'NE Alarm-Health State Check'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (500, 'job.ne_alarm_state_check_remark', '检查网元的健康状况,在出现异常时发出警报。 +REPLACE INTO "sys_i18n" VALUES (297, 'menu.neData.backupData', '导出文件', 'Exponted File'); +REPLACE INTO "sys_i18n" VALUES (298, 'config.sys.user.passwordPolicyNot', '未配置密码策略', 'Password policy not configured'); +REPLACE INTO "sys_i18n" VALUES (299, 'job.export.jobID', '任务编号', 'ID'); +REPLACE INTO "sys_i18n" VALUES (300, 'job.export.jobName', '任务名称', 'Name'); +REPLACE INTO "sys_i18n" VALUES (301, 'job.export.jobGroupName', '任务组名', 'Group'); +REPLACE INTO "sys_i18n" VALUES (302, 'job.export.invokeTarget', '调用目标', 'Invoke'); +REPLACE INTO "sys_i18n" VALUES (303, 'job.export.targetParams', '传入参数', 'Incoming Parameters'); +REPLACE INTO "sys_i18n" VALUES (304, 'job.export.cronExpression', 'cron表达式', 'Cron'); +REPLACE INTO "sys_i18n" VALUES (305, 'job.export.status', '状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (306, 'job.export.remark', '备注说明', 'Description'); +REPLACE INTO "sys_i18n" VALUES (307, 'job.export.jobLogID', '任务日志编号', 'ID'); +REPLACE INTO "sys_i18n" VALUES (308, 'job.export.jobLogStatus', '任务日志状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (309, 'job.export.jobLogTime', '任务日志时间', 'Time'); +REPLACE INTO "sys_i18n" VALUES (310, 'job.noData', '没有可访问调度任务数据!', 'There is no accessible scheduling task data!'); +REPLACE INTO "sys_i18n" VALUES (311, 'job.errTargetParams', '操作调度任务【{name}】失败,任务传入参数json字符串不正确', 'Failed to operate scheduling task [{name}] with incorrect task incoming parameter json string!'); +REPLACE INTO "sys_i18n" VALUES (312, 'job.errCronExpression', '操作调度任务【{name}】失败,Cron表达式不正确', 'Scheduled task [{name}] failed with incorrect Cron expression!'); +REPLACE INTO "sys_i18n" VALUES (313, 'job.errJobExists', '调度任务新增【{name}】失败,同任务组内有相同任务名称', 'Failed to add a new task [{name}] to a scheduling task, same task name in the same task group'); +REPLACE INTO "sys_i18n" VALUES (314, 'job.statusEq', '变更状态与旧值相等!', 'The change state is equal to the old value!'); +REPLACE INTO "sys_i18n" VALUES (315, 'role.system', '系统', 'System'); +REPLACE INTO "sys_i18n" VALUES (316, 'role.admin', '管理人员', 'Administrator'); +REPLACE INTO "sys_i18n" VALUES (317, 'role.operator', '运维人员', 'Operators'); +REPLACE INTO "sys_i18n" VALUES (318, 'role.monitor', '监控人员', 'Monitor'); +REPLACE INTO "sys_i18n" VALUES (319, 'role.vistor', '普通用户', 'General Users'); +REPLACE INTO "sys_i18n" VALUES (320, 'role.systemRemark', '系统,无法修改删除', 'System, cannot modify or delete'); +REPLACE INTO "sys_i18n" VALUES (321, 'role.adminRemark', '管理人员 可以对设备进行任何操作', 'Administrators can perform any operation on the device'); +REPLACE INTO "sys_i18n" VALUES (322, 'role.operatorRemark', '运维人员 可以从设备读取数据,并对设备进行配置,但是不能对设备进行软件升级操作。', 'Operation and maintenance personnel can read data from the device and configure the device, but cannot perform software upgrade operations on the device.'); +REPLACE INTO "sys_i18n" VALUES (323, 'role.monitorRemark', '监控人员 只能从设备读取数据,而不能对设备进行任何设置', 'Monitoring personnel Can only read data from the device, but cannot make any settings on the device'); +REPLACE INTO "sys_i18n" VALUES (324, 'role.vistorRemark', '普通用户 只可看系统相关信息', 'Ordinary users can only see system-related information'); +REPLACE INTO "sys_i18n" VALUES (325, 'role.export.id', '角色编号', 'Role Number'); +REPLACE INTO "sys_i18n" VALUES (326, 'role.export.name', '角色名称 ', 'Role Name'); +REPLACE INTO "sys_i18n" VALUES (327, 'role.export.key', '角色键值', 'Role Key'); +REPLACE INTO "sys_i18n" VALUES (328, 'role.export.sort', '角色顺序', 'Role Sort'); +REPLACE INTO "sys_i18n" VALUES (329, 'role.export.dataScope', '角色数据范围', 'Role Data Range'); +REPLACE INTO "sys_i18n" VALUES (330, 'role.export.status', '角色状态', 'Role Status'); +REPLACE INTO "sys_i18n" VALUES (331, 'role.noData', '没有可访问角色数据!', 'There is no accessible role data!'); +REPLACE INTO "sys_i18n" VALUES (332, 'role.statusEq', '变更状态与旧值相等!', 'The change status is equal to the old value!'); +REPLACE INTO "sys_i18n" VALUES (333, 'role.errNameExists', '操作角色【{name}】失败,角色名称已存在', 'Manipulating role [{name}] failed, role name already exists!'); +REPLACE INTO "sys_i18n" VALUES (334, 'role.errKeyExists', '操作角色【{name}】失败,角色键值已存在', 'Failed to manipulate role [{name}], role key already exists!'); +REPLACE INTO "sys_i18n" VALUES (335, 'post.admin', '系统', 'Systems'); +REPLACE INTO "sys_i18n" VALUES (336, 'post.operator', '管理', 'Management'); +REPLACE INTO "sys_i18n" VALUES (337, 'post.monitor', '运维', 'Operation & Maintenance'); +REPLACE INTO "sys_i18n" VALUES (338, 'post.visitor', '监控', 'Monitoring'); +REPLACE INTO "sys_i18n" VALUES (339, 'post.export.id', '岗位编号 ', 'Position Number'); +REPLACE INTO "sys_i18n" VALUES (340, 'post.export.code', '岗位编码', 'Position Code'); +REPLACE INTO "sys_i18n" VALUES (341, 'post.export.name', '岗位名称', 'Position Name'); +REPLACE INTO "sys_i18n" VALUES (342, 'post.export.sort', '岗位排序', 'Position Sort'); +REPLACE INTO "sys_i18n" VALUES (343, 'post.export.status', '岗位状态', 'Position Status'); +REPLACE INTO "sys_i18n" VALUES (344, 'post.noData', '没有可访问岗位数据!', 'There is no accessible post data!'); +REPLACE INTO "sys_i18n" VALUES (345, 'post.errNameExists', '操作岗位【{name}】失败,岗位名称已存在已存在', 'Failed to manipulate post [{name}], post name already exists already exists'); +REPLACE INTO "sys_i18n" VALUES (346, 'post.errCodeExists', '操作角色【{name}】失败,角色键值已存在', 'Failed to manipulate role [{name}], role key already exists.'); +REPLACE INTO "sys_i18n" VALUES (347, 'user.export.id', '用户编号', 'User Number'); +REPLACE INTO "sys_i18n" VALUES (348, 'user.export.name', '登录账号', 'Account'); +REPLACE INTO "sys_i18n" VALUES (349, 'user.export.nick', '用户昵称', 'Nick Name'); +REPLACE INTO "sys_i18n" VALUES (350, 'user.export.email', '电子邮箱', 'E-Mail'); +REPLACE INTO "sys_i18n" VALUES (351, 'user.export.phone', '手机号码', 'Cell phone number'); +REPLACE INTO "sys_i18n" VALUES (352, 'user.export.sex', '用户性别', 'Gender'); +REPLACE INTO "sys_i18n" VALUES (353, 'user.export.status', '用户状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (354, 'user.export.deptID', '部门编号', 'Department number'); +REPLACE INTO "sys_i18n" VALUES (355, 'user.export.deptName', '部门名称', 'Department'); +REPLACE INTO "sys_i18n" VALUES (356, 'user.export.deptLeader', '部门负责人', 'Department Head'); +REPLACE INTO "sys_i18n" VALUES (357, 'user.export.loginIP', '用户登录IP', 'Login Address'); +REPLACE INTO "sys_i18n" VALUES (358, 'user.export.loginDate', '用户登录时间', 'Login Time'); +REPLACE INTO "sys_i18n" VALUES (359, 'user.noData', '没有可访问用户数据!', 'No accessible user data!'); +REPLACE INTO "sys_i18n" VALUES (360, 'user.statusEq', '变更状态与旧值相等!', 'The change status is equal to the old value!'); +REPLACE INTO "sys_i18n" VALUES (361, 'user.errPasswdOld', '修改密码失败,旧密码错误', 'Change password failed, old password is wrong'); +REPLACE INTO "sys_i18n" VALUES (362, 'user.errPasswdEqOld', '新密码不能与旧密码相同', 'New password cannot be the same as the old one'); +REPLACE INTO "sys_i18n" VALUES (363, 'config.sys.user.passwordPolicyError', '密码至少{minLength}位,至少包含{specialChars}个特殊字符和至少{uppercase}个大写字母和至少{lowercase}个小写字母', 'Passwords are at least {minLength} digits long and contain at least {specialChars} special characters and at least {uppercase} uppercase letter and at least {lowercase} lowercase letter.'); +REPLACE INTO "sys_i18n" VALUES (364, 'user.errEmailFormat', '操作用户【{name}】失败,邮箱格式错误', 'Failed to operate user [{name}], mailbox format error'); +REPLACE INTO "sys_i18n" VALUES (365, 'user.errEmailExists', '操作用户【{name}】失败,邮箱已存在', 'Failed to operate user [{name}], mailbox already exists.'); +REPLACE INTO "sys_i18n" VALUES (366, 'user.errPhoneFormat', '操作用户【{name}】失败,手机号码格式错误', 'Failed to operate user [{name}], cell phone number format is wrong.'); +REPLACE INTO "sys_i18n" VALUES (367, 'user.errPhoneExists', '操作用户【{name}】失败,手机号码已存在', 'Failed to operate user [{name}], cell phone number already exists.'); +REPLACE INTO "sys_i18n" VALUES (368, 'user.errNameExists', '操作用户【{name}】失败,登录账号已存在', 'Failed to operate user [{name}], login account already exists.'); +REPLACE INTO "sys_i18n" VALUES (369, 'user.import.mustItem', '表格中必填列表项,{text}', 'Required list item in form, {text}'); +REPLACE INTO "sys_i18n" VALUES (370, 'user.import.phoneExist', '用户编号:{id} 手机号码 {phone} 已存在', 'User ID: {id} cell phone number {phone} Existing'); +REPLACE INTO "sys_i18n" VALUES (371, 'user.import.phoneFormat', '用户编号:{id} 手机号码 {phone} 格式错误', 'User ID: {id} cell phone number {phone} Wrong format'); +REPLACE INTO "sys_i18n" VALUES (372, 'user.import.emailExist', '用户编号:{id} 用户邮箱:{email} 已存在', 'User ID: {id} User Email: {email} Existing'); +REPLACE INTO "sys_i18n" VALUES (373, 'user.import.emailFormat', '用户编号:{id} 用户邮箱:{email} 格式错误', 'User ID: {id} Email: {email} Wrong Format'); +REPLACE INTO "sys_i18n" VALUES (374, 'user.import.success', '用户编号:{id} 登录名称:{name} 导入成功', 'User ID:{id} Login name:{name} Imported successfully!'); +REPLACE INTO "sys_i18n" VALUES (375, 'user.import.fail', '用户编号:{id} 登录名称:{name} 导入失败', 'User ID: {id} Login name: {name} Import failed'); +REPLACE INTO "sys_i18n" VALUES (376, 'user.import.successUpdate', '用户编号:{id} 登录名称:{name} 更新成功', 'User ID: {id} Login name: {name} Update success'); +REPLACE INTO "sys_i18n" VALUES (377, 'user.import.failUpdate', '用户编号:{id} 登录名称:{name} 更新失败', 'User ID: {id} Login Name: {name} Update Failed'); +REPLACE INTO "sys_i18n" VALUES (378, 'user.import.failTip', '很抱歉,导入失败!共 {num} 条数据格式不正确,错误如下:', 'Sorry, the import failed! A total of {num} entries were not formatted correctly, the error is below:'); +REPLACE INTO "sys_i18n" VALUES (379, 'user.import.successTip', '恭喜您,数据已全部导入成功!共 {num} 条,数据如下:', 'Congratulations, the data has been imported successfully! There are {num} entries with the following data:'); +REPLACE INTO "sys_i18n" VALUES (380, 'app.common.err403', '无权访问 {method} {requestURI}', 'Unauthorized access {method} {requestURI}'); +REPLACE INTO "sys_i18n" VALUES (381, 'app.common.err401', '无效身份授权', 'Invalid authorization'); +REPLACE INTO "sys_i18n" VALUES (382, 'app.common.err400', '参数错误', 'Parameter error'); +REPLACE INTO "sys_i18n" VALUES (383, 'app.common.exportEmpty', '导出数据记录为空', 'Export data record is empty'); +REPLACE INTO "sys_i18n" VALUES (384, 'app.common.errOperateAdmin', '不允许操作内置用户', 'Built-in users are not allowed to operate'); +REPLACE INTO "sys_i18n" VALUES (385, 'app.common.errOperateRole', '不允许操作内置角色', 'Built-in roles are not allowed to be operated'); +REPLACE INTO "sys_i18n" VALUES (386, 'app.common.deleteSuccess', '删除成功:{num}', 'Deleted successfully: {num}'); +REPLACE INTO "sys_i18n" VALUES (387, 'app.common.loginSuccess', '登录成功', 'Login Success'); +REPLACE INTO "sys_i18n" VALUES (388, 'app.common.logoutSuccess', '注销成功', 'Logout Successful'); +REPLACE INTO "sys_i18n" VALUES (389, 'app.common.errUnlock', '该用户未被锁定', 'The user is not locked'); +REPLACE INTO "sys_i18n" VALUES (390, 'app.common.noLoginUser', '登录用户信息无效', 'Invalid login user information'); +REPLACE INTO "sys_i18n" VALUES (391, 'app.common.rateLimitTip', '访问过于频繁,请稍候再试', 'Access too often, please try again later'); +REPLACE INTO "sys_i18n" VALUES (392, 'log.operate.export.id', '操作编号', 'Log ID'); +REPLACE INTO "sys_i18n" VALUES (393, 'log.operate.export.title', '模块名称', 'Module Name'); +REPLACE INTO "sys_i18n" VALUES (394, 'log.operate.export.businessType', '业务类型', 'Business Type'); +REPLACE INTO "sys_i18n" VALUES (395, 'log.operate.export.method', '操作方法', 'Operation Method'); +REPLACE INTO "sys_i18n" VALUES (396, 'log.operate.export.requestMethod', '请求方式 ', 'Request Method'); +REPLACE INTO "sys_i18n" VALUES (397, 'log.operate.export.operatorType', '操作类型', 'Operation Type'); +REPLACE INTO "sys_i18n" VALUES (398, 'log.operate.export.operName', '操作人员', 'Operator'); +REPLACE INTO "sys_i18n" VALUES (399, 'log.operate.export.deptName', '操作人员部门名称', 'Operator Department Name'); +REPLACE INTO "sys_i18n" VALUES (400, 'log.operate.export.url', '请求链接地址', 'Request URL'); +REPLACE INTO "sys_i18n" VALUES (401, 'log.operate.export.ip', '请求主机 ', 'Request Host'); +REPLACE INTO "sys_i18n" VALUES (402, 'log.operate.export.location', '请求地址', 'Request Address'); +REPLACE INTO "sys_i18n" VALUES (403, 'log.operate.export.param', '请求参数', 'Request Parameters'); +REPLACE INTO "sys_i18n" VALUES (404, 'log.operate.export.msg', '操作信息', 'Operation Information'); +REPLACE INTO "sys_i18n" VALUES (405, 'log.operate.export.status', '操作状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (406, 'log.operate.export.costTime', '消耗时间(毫秒)', 'Time Consumption (ms)'); +REPLACE INTO "sys_i18n" VALUES (407, 'log.operate.export.operTime', '操作时间', 'Time'); +REPLACE INTO "sys_i18n" VALUES (408, 'log.login.export.id', '记录编号', 'Log ID'); +REPLACE INTO "sys_i18n" VALUES (409, 'log.login.export.userName', '登录账号', 'Login Account'); +REPLACE INTO "sys_i18n" VALUES (410, 'log.login.export.status', '登录状态', 'Status'); +REPLACE INTO "sys_i18n" VALUES (411, 'log.login.export.ip', '登录地址', 'Login Address'); +REPLACE INTO "sys_i18n" VALUES (412, 'log.login.export.location', '登录地点', 'Login Location'); +REPLACE INTO "sys_i18n" VALUES (413, 'log.login.export.browser', '浏览器', 'Browser'); +REPLACE INTO "sys_i18n" VALUES (414, 'log.login.export.os', '操作系统', 'Operating System'); +REPLACE INTO "sys_i18n" VALUES (415, 'log.login.export.msg', '登录信息', 'Login Information'); +REPLACE INTO "sys_i18n" VALUES (416, 'log.login.export.time', '登录时间', 'Login Time'); +REPLACE INTO "sys_i18n" VALUES (417, 'trace.tcpdump.noData', '找不到 {type} {id} 对应网元信息', 'Can it find {type} {id} information of the corresponding network element.'); +REPLACE INTO "sys_i18n" VALUES (418, 'register.errUsername', '账号不能以数字开头,可包含大写小写字母,数字,且不少于5位', 'The account number cannot start with a number, but can contain upper and lower case letters, numbers, and not less than 5 digits.'); +REPLACE INTO "sys_i18n" VALUES (419, 'login.errPasswdExpire', '登录密码已过期', 'Login password has expired'); +REPLACE INTO "sys_i18n" VALUES (420, 'register.errPasswdNotEq', '用户确认输入密码不一致', 'User confirms password inconsistency'); +REPLACE INTO "sys_i18n" VALUES (421, 'register.success', '注册成功', 'Successful registration'); +REPLACE INTO "sys_i18n" VALUES (422, 'register.successMsg', '{name} 注册成功 {id}', '{name} Register Successful {id}'); +REPLACE INTO "sys_i18n" VALUES (423, 'log.operate.title.sysJobLog', '调度任务日志', 'Scheduling Task Logs'); +REPLACE INTO "sys_i18n" VALUES (424, 'log.operate.title.sysJob', '调度任务', 'Scheduling Tasks'); +REPLACE INTO "sys_i18n" VALUES (425, 'log.operate.title.tcpdump', '信令抓包', 'Signaling Capture'); +REPLACE INTO "sys_i18n" VALUES (426, 'log.operate.title.sysConfig', '参数配置', 'Parameter Configuration'); +REPLACE INTO "sys_i18n" VALUES (427, 'log.operate.title.sysDept', '部门', 'Sector'); +REPLACE INTO "sys_i18n" VALUES (428, 'log.operate.title.sysDictData', '字典数据', 'Dictionary Data'); +REPLACE INTO "sys_i18n" VALUES (429, 'log.operate.title.sysDictType', '字典类型', 'Dictionary type'); +REPLACE INTO "sys_i18n" VALUES (430, 'log.operate.title.sysMenu', '菜单', 'Menu'); +REPLACE INTO "sys_i18n" VALUES (431, 'log.operate.title.sysPost', '岗位', 'Positions'); +REPLACE INTO "sys_i18n" VALUES (432, 'log.operate.title.sysProfile', '个人信息', 'Personal Information'); +REPLACE INTO "sys_i18n" VALUES (433, 'log.operate.title.sysProfileAvatar', '个人头像', 'Personal avatar'); +REPLACE INTO "sys_i18n" VALUES (434, 'log.operate.title.sysRole', '角色', 'Roles'); +REPLACE INTO "sys_i18n" VALUES (435, 'log.operate.title.sysUser', '用户', 'User'); +REPLACE INTO "sys_i18n" VALUES (436, 'log.operate.title.sysLogOper', '操作日志记录', 'Operation Logging'); +REPLACE INTO "sys_i18n" VALUES (437, 'log.operate.title.sysLogLogin', '登录日志记录', 'Operation Logging'); +REPLACE INTO "sys_i18n" VALUES (438, 'login.errNameOrPasswd', '用户不存在或密码错误', 'User does not exist or password is wrong'); +REPLACE INTO "sys_i18n" VALUES (439, 'login.errDelFlag', '对不起,您的账号已被删除', 'Sorry, your account has been deleted'); +REPLACE INTO "sys_i18n" VALUES (440, 'login.errStatus', '对不起,您的帐户已被禁用', 'Sorry, your account has been disabled'); +REPLACE INTO "sys_i18n" VALUES (441, 'login.errRetryPasswd', '密码输入错误多次,帐户已被锁定', 'Password was entered incorrectly several times, account has been locked'); +REPLACE INTO "sys_i18n" VALUES (442, 'captcha.err', '验证码错误', 'Captcha Error'); +REPLACE INTO "sys_i18n" VALUES (443, 'captcha.errValid', '验证码已失效', 'Captcha is invalid'); +REPLACE INTO "sys_i18n" VALUES (444, 'app.common.noUaOsBrowser', '未知 未知', 'Unknown Unknown'); +REPLACE INTO "sys_i18n" VALUES (445, 'app.common.noIPregion', '内网', 'Intranet'); +REPLACE INTO "sys_i18n" VALUES (446, 'app.common.unknown', '未知', 'Unknown'); +REPLACE INTO "sys_i18n" VALUES (447, 'app.common.noNEInfo', '未找到匹配网元信息', 'No matching network element information found'); +REPLACE INTO "sys_i18n" VALUES (448, 'ne.udm.errImportUserAuthFileFormat', '请上传.csv或.txt的格式文件。英文逗号分割txt格式:imsi, ki, algo, amf, opc', 'Please upload a file in the format of. csv or. txt. English comma separated txt format: imsi, ki, algo, amf, opc'); +REPLACE INTO "sys_i18n" VALUES (449, 'ne.udm.errExportType', '导出文件类型支持CSV和txt', 'Export file types support CSV and txt'); +REPLACE INTO "sys_i18n" VALUES (450, 'ne.udm.errImportUserSubFileFormat', '请上传.csv或.txt的格式文件。英文逗号分割txt格式:imsi, msisdn, ambr, nssai, arfb, sar, rat, cn, smf_sel, sm_dat, eps_dat', 'Please upload files in .csv or .txt format. English comma-separated txt format: imsi, msisdn, ambr, nssai, arfb, sar, rat, cn, smf_sel, sm_dat, eps_dat'); +REPLACE INTO "sys_i18n" VALUES (451, 'log.operate.title.udmAuth', 'UDM鉴权用户', 'UDM Authentication'); +REPLACE INTO "sys_i18n" VALUES (452, 'log.operate.title.udmSub', 'UDM签约用户', 'UDM Subscriber'); +REPLACE INTO "sys_i18n" VALUES (453, 'dictType.active_alarm_type', '活动告警类型', 'Event Alarm Types'); +REPLACE INTO "sys_i18n" VALUES (454, 'dictType.active_alarm_type_remark', '活动告警类型列表', 'List of Active Alarm Types'); +REPLACE INTO "sys_i18n" VALUES (455, 'dictData.active_alarm_type.communication', '通信告警', 'Communication Alarm'); +REPLACE INTO "sys_i18n" VALUES (456, 'dictData.active_alarm_type.equipment', '设备告警', 'Equipment Alarm'); +REPLACE INTO "sys_i18n" VALUES (457, 'dictData.active_alarm_type.processing', '处理错误', 'Processing Failure Alarm'); +REPLACE INTO "sys_i18n" VALUES (458, 'dictData.active_alarm_type.environmental', '环境告警', 'Environmental Alarm'); +REPLACE INTO "sys_i18n" VALUES (459, 'dictData.active_alarm_type.qualityOfService', '服务质量', 'Quality of Service Alarm'); +REPLACE INTO "sys_i18n" VALUES (460, 'dictType.active_clear_type', '告警清除类型', 'Alarm Clearing Types'); +REPLACE INTO "sys_i18n" VALUES (461, 'dictType.active_clear_type_remark', '告警清除类型列表', 'List of Alarm Clearing Types'); +REPLACE INTO "sys_i18n" VALUES (462, 'dictData.active_clear_type.notCleared', '告警未清除', 'Not cleared'); +REPLACE INTO "sys_i18n" VALUES (463, 'dictData.active_clear_type.hand', '手动清除', 'Manually cleared'); +REPLACE INTO "sys_i18n" VALUES (464, 'dictData.active_clear_type.auto', '自动清除', 'Automatically cleared'); +REPLACE INTO "sys_i18n" VALUES (465, 'dictType.active_ack_state', '告警确认类型', 'Alarm Acknowledgement Types'); +REPLACE INTO "sys_i18n" VALUES (466, 'dictType.active_ack_state_remark', '告警确认类型列表', 'Alarm Acknowledgement Type List'); +REPLACE INTO "sys_i18n" VALUES (467, 'dictData.active_ack_state.unconfirmed', '未确认', 'Not Confirm'); +REPLACE INTO "sys_i18n" VALUES (468, 'dictData.active_ack_state.confirmed', '已确认', 'Confirm'); +REPLACE INTO "sys_i18n" VALUES (469, 'dictType.active_alarm_severity', '严重程度', 'Severity'); +REPLACE INTO "sys_i18n" VALUES (470, 'dictType.active_alarm_severity_remark', '严重程度列表', 'Severity List'); +REPLACE INTO "sys_i18n" VALUES (471, 'dictData.active_alarm_severity.critical', '严重告警', 'Critical'); +REPLACE INTO "sys_i18n" VALUES (472, 'dictData.active_alarm_severity.major', '主要告警', 'Major'); +REPLACE INTO "sys_i18n" VALUES (473, 'dictData.active_alarm_severity.minor', '次要告警', 'Minor'); +REPLACE INTO "sys_i18n" VALUES (474, 'dictData.active_alarm_severity.warning', '警告告警', 'Warning'); +REPLACE INTO "sys_i18n" VALUES (475, 'dictData.active_alarm_severity.event', '事件告警', 'Event'); +REPLACE INTO "sys_i18n" VALUES (476, 'config.sys.officialUrl', '系统设置-官网链接', 'System Settings - Official Website Links'); +REPLACE INTO "sys_i18n" VALUES (477, 'config.sys.helpDoc', '系统设置-系统使用文档', 'System Settings-System Documentation'); +REPLACE INTO "sys_i18n" VALUES (478, 'config.sys.officialUrlRemark', '默认无地址用#号', 'Default no address with # sign'); +REPLACE INTO "sys_i18n" VALUES (479, 'config.sys.helpDocRemark', '静态文件目录地址,使用{language}区分语言文件', 'Static file directory address, use {language} to distinguish language files'); +REPLACE INTO "sys_i18n" VALUES (480, 'log.operate.title.neAction', '网元处理', 'Network Element Processing'); +REPLACE INTO "sys_i18n" VALUES (481, 'log.operate.title.helpDoc', '系统使用文档', 'System Usage Documentation'); +REPLACE INTO "sys_i18n" VALUES (482, 'menu.ueUser.n3iwf', 'N3IWF在线用户', 'N3IWF Online User'); +REPLACE INTO "sys_i18n" VALUES (483, 'menu.neData.pcfSub', '用户策略控制信息', 'User PCC Information'); +REPLACE INTO "sys_i18n" VALUES (484, 'menu.system.user.editRole', '修改用户角色', 'Modifying User Role'); +REPLACE INTO "sys_i18n" VALUES (485, 'config.sys.i18nOpen', '国际化切换', 'Internationalization Switching'); +REPLACE INTO "sys_i18n" VALUES (486, 'config.sys.i18nDefault', '国际化默认语言', 'Internationalization Default Language'); +REPLACE INTO "sys_i18n" VALUES (487, 'user.export.role', '用户角色', 'Role'); +REPLACE INTO "sys_i18n" VALUES (488, 'menu.system.setting.i18n', '国际化切换', 'Internationalization Switch'); +REPLACE INTO "sys_i18n" VALUES (489, 'menu.system.setting.i18nRemark', '国际化多语言的切换选择', 'Internationalized multilingual switching options'); +REPLACE INTO "sys_i18n" VALUES (490, 'dictType.index_status', '首页状态', 'Home Status'); +REPLACE INTO "sys_i18n" VALUES (491, 'dictType.index_status_remark', '首页的网元状态颜色', 'Network element status colors on the home page'); +REPLACE INTO "sys_i18n" VALUES (492, 'dictType.index_status.normal', '正常', 'Normal'); +REPLACE INTO "sys_i18n" VALUES (493, 'dictType.index_status.abnormal', '异常', 'Abnormal'); +REPLACE INTO "sys_i18n" VALUES (494, 'menu.log.neFile', '网元日志文件', 'NE Log File'); +REPLACE INTO "sys_i18n" VALUES (495, 'menu.dashboard.overview.smfUeNum', '展示数据会话数', 'Display data session number'); +REPLACE INTO "sys_i18n" VALUES (496, 'menu.dashboard.overview.imsUeNum', '展示语音会话数', 'Display the number of voice sessions'); +REPLACE INTO "sys_i18n" VALUES (497, 'menu.dashboard.overview.gnbBase', '展示5G基站在线信息', 'Display 5G base station online information'); +REPLACE INTO "sys_i18n" VALUES (498, 'menu.dashboard.overview.enbBase', '展示4G基站在线信息', 'Display 4G base station online information'); +REPLACE INTO "sys_i18n" VALUES (499, 'job.ne_alarm_state_check', '网元告警-状态检查', 'NE Alarm-Health State Check'); +REPLACE INTO "sys_i18n" VALUES (500, 'job.ne_alarm_state_check_remark', '检查网元的健康状况,在出现异常时发出警报。 Alarm type: CommunicationAlarm=1 @@ -566,297 +566,297 @@ Critical=1 Major=2 Minor=3 Warning=4'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (501, 'menu.neUser.nssf', 'NSSF在线订阅数', 'NSSF Subscription Info'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (502, 'menu.neUser.nssfAmf', 'NSSF可用的注册AMF', 'NSSF Available AMFs'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (503, 'menu.monitor.topology', '拓扑信息', 'Topology Info'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (504, 'menu.monitor.topologyBuild', '拓扑图组编辑', 'Topological Graph Build'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (505, 'log.operate.title.chartGraph', '拓扑图组', 'Topological Graph'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (506, 'menu.monitor.topologyArchitecture', '网元拓扑组网', 'NE System Topology'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (507, 'menu.alarm', '告警', 'Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (508, 'menu.topology', '拓扑', 'Topology'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (509, 'config.sys.lockTime', '系统设置-锁屏超时时长', 'System Settings - Screen Lock Timeout Duration'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (510, 'config.sys.lockTimeRemark', '无操作时锁屏超时时长,单位(秒)。0表示无锁屏超时', 'Timeout of lock screen when no operation, unit (sec), 0 means no timeout of lock screen'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (511, 'sys.account.captchaType', '账号自助-验证码类型', 'Account Self Service - Captcha Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (512, 'sys.account.captchaTypeRemark', '使用验证码类型(math数值计算,char字符验证)', 'Using CAPTCHA types (math numeric calculation, char character validation)'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (513, 'menu.dashboard', '仪表盘', 'Dashboard'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (514, 'menu.dashboard.overview', '总览', 'Overview'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (515, 'menu.dashboard.imsCDR', '语音话单', 'Voice CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (516, 'dictType.cdr_sip_code', 'IMS-Voice-SIP响应代码类别类型', 'IMS-Voice-SIP Response Code Category Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (517, 'dictType.cdr_call_type', 'IMS-呼叫类型', 'IMS-Call Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (518, 'dictType.ue_auth_code', 'UE 事件认证代码类型', 'UE Event Authentication Code Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (519, 'dictType.ue_event_type', 'UE 事件类型', 'UE Event Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (520, 'dictData.cdr_sip_code.200', '200 正常通话', '200 OK'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (521, 'dictData.cdr_sip_code.403', '403 禁止访问', '403 Forbidden'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (522, 'dictData.cdr_sip_code.408', '408 请求超时', '408 Request Timeout'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (523, 'dictData.cdr_sip_code.500', '500 内部服务器错误', '500 Internal Server Error'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (524, 'dictData.cdr_call_type.audio', '语音', 'Voice'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (525, 'dictData.cdr_call_type.video', '视频', 'Video'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (526, 'dictData.ue_auth_code.200', '成功', 'Success'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (527, 'dictData.ue_auth_code.001', '网络失败', 'Network Failure'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (528, 'dictData.ue_auth_code.002', '接口失败', 'Interface Failure'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (529, 'dictData.ue_auth_code.003', 'MAC失败', 'MAC Failure'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (530, 'dictData.ue_auth_code.004', '同步失败', 'Synchronization failure'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (531, 'dictData.ue_auth_code.005', '不接受非5G认证', 'Non-5G Authentication Not Accepted'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (532, 'dictData.ue_auth_code.006', '响应失败', 'Response Failure'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (533, 'dictData.ue_auth_code.007', '未知', 'Unknown'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (534, 'dictData.ue_event_type.auth', '认证', 'Authentication'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (535, 'dictData.ue_event_type.detach', '注销', 'Detach'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (536, 'dictData.ue_event_type.state', 'CM状态', 'CM Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (537, 'dictType.ue_event_cm_state', 'UE 事件CM状态', 'UE Event CM Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (538, 'dictData.ue_event_cm_state.connected', '连接', 'Connected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (539, 'dictData.ue_event_cm_state.idle', '空闲', 'Idle'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (540, 'dictData.ue_event_cm_state.inactive', '不活动', 'Inactive'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (541, 'dictData.cdr_sip_code.404', '404 找不到', '404 Not Found'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (542, 'dictData.cdr_sip_code.487', '487 请求已终止', '487 Request Terminated'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (543, 'dictData.cdr_sip_code.503', '503 服务不可用', '503 Service Unavailable'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (544, 'dictData.cdr_sip_code.504', '504 服务器超时', '504 Server Timeout'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (545, 'dictData.cdr_sip_code.603', '603 拒绝', '603 Decline'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (546, 'dictData.cdr_sip_code.606', '606 不可接受', '606 Not Acceptable'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (547, 'cache.name.token', '用户令牌', 'User Token'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (548, 'cache.name.sys_config', '参数管理', 'Parameters Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (549, 'cache.name.sys_dict', '字典管理', 'Dictionary Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (550, 'cache.name.captcha_codes', '验证码', 'Captcha'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (551, 'cache.name.repeat_submit', '防重提交', 'Resubmit'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (552, 'cache.name.rate_limit', '限流', 'Limit Traffic'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (553, 'cache.name.pwd_err_cnt', '登录账户密码错误次数', 'Number of Password Errors'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (554, 'cache.name.ne_info', '网元信息管理', 'NE Info Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (555, 'cache.name.ne_data', '网元数据管理', 'NE Data Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (556, 'dictData.cdr_call_type.sms', '短信', 'SMS'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (557, 'dictData.cdr_sip_code.202', '202 已接受', '202 Accepted'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (558, 'dictData.cdr_sip_code.488', '488 这里不接受', '488 Not Acceptable Here'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (559, 'dictData.cdr_sip_code.0', '0 原因不明', '0 Unknown Reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (560, 'log.operate.title.ws', 'WS会话', 'WS Sessions'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (561, 'log.operate.title.neHost', '网元主机', 'NE Host'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (562, 'neHost.noData', '没有可访问主机信息数据!', 'There is no accessible host information data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (563, 'neHost.errKeyExists', '主机信息操作【{name}】失败,同组内名称已存在', 'Host information operation [{name}] failed, name already exists in the same group'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (564, 'neHost.errByHostInfo', '连接失败,请检查连接参数后重试', 'Connection Failed, Please check connection parameters and retry'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (565, 'dictType.ne_host_type', '网元主机连接类型', 'Network element host connection type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (566, 'dictType.ne_host_groupId', '网元主机分组', 'Network element host grouping'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (567, 'dictType.ne_host_authMode', '网元主机认证模式', 'Network element host authentication mode'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (568, 'dictData.ne_host_type.ssh', 'SSH', 'SSH'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (569, 'dictData.ne_host_type.telnet', 'Telnet', 'Telnet'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (570, 'dictData.ne_host_groupId.0', '其他', 'Other'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (571, 'dictData.ne_host_groupId.1', '网元', 'Network Elements'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (572, 'dictData.ne_host_groupId.2', '系统', 'System'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (573, 'dictData.ne_host_authMode.0', '密码认证', 'Password Authentication'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (574, 'dictData.ne_host_authMode.1', '私钥认证', 'Private key authentication'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (575, 'menu.tools.terminal', '主机终端', 'Host Terminal'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (576, 'menu.ne.neHost', '网元主机', 'NE Host'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (577, 'menu.ne.neHostCommand', '网元主机命令', 'NE Host CMD'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (578, 'log.operate.title.neHostCmd', '网元主机命令', 'NE Host CMD'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (579, 'neHostCmd.noData', '没有可访问主机命令数据!', 'No accessible host command data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (580, 'neHostCmd.errKeyExists', '主机命令操作【{name}】失败,同组内名称已存在', 'Host command operation [{name}] failed, name already exists in the same group'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (581, 'dictType.ne_host_cmd_groupId', '网元主机命令分组', 'Network element host command grouping'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (582, 'dictData.ne_host_cmd_groupId.0', '默认', 'Default'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (583, 'dictData.ne_host_cmd_groupId.1', '快速命令', 'Quick Commands'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (584, 'menu.ne.neInfo', '网元信息', 'NE Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (585, 'log.operate.title.neInfo', '网元信息', 'NE Information'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (586, 'neInfo.noData', '没有可访问网元信息数据!', 'There is no accessible network element information data!'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (587, 'neInfo.errKeyExists', '网元信息操作【{key}】失败,同类型下标识已存在', 'NE info operation [{key}] failed, identifier already exists under the same type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (588, 'log.operate.title.imsCDR', '通话话单', 'Voice CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (589, 'menu.dashboard.amfUE', '5G 终端事件', '5G UE Events'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (590, 'log.operate.title.amfUE', '5G 终端事件', '5G UE Events'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (591, 'dictData.ne_info_status.0', '离线', 'Offline'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (592, 'dictData.ne_info_status.1', '在线', 'Active'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (593, 'dictData.ne_info_status.2', '等待同步', 'Wait Sync'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (594, 'dictData.ne_info_status.3', '待机', 'Standby'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (595, 'dictType.ne_info_status', '网元信息状态', 'NE Info State'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (596, 'menu.ne.neQuickSetup', '网元快速安装', 'NE Quick Setup'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (597, 'log.operate.title.neConfig', '网元参数配置', 'NE Parameter Configuration'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (598, 'menu.ne.neLicense', '网元许可', 'NE License'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (599, 'log.operate.title.neLicense', '网元许可', 'NE License'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (600, 'menu.ne.neSoftware', '网元软件包', 'NE Software'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (601, 'log.operate.title.neSoftware', '网元软件包', 'NE Software'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (602, 'log.operate.title.neVersion', '网元版本', 'NE Version'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (603, 'menu.ne.neVersion', '网元版本', 'Ne Version'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (604, 'dictType.ne_license_status', '网元许可状态', 'NE License Status'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (605, 'dictData.ne_license_status.0', '无效', 'Invalid'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (606, 'dictData.ne_license_status.1', '有效', 'Valid'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (607, 'menu.dashboard.mocn', 'MOCN', 'MOCN'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (608, 'menu.monitor.cdr', '话单', 'CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (609, 'menu.monitor.event', '事件', 'Events'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (610, 'post.export.time', '创建时间', 'Creation Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (611, 'role.export.time', '创建时间', 'Creation Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (612, 'dictData.ne_host_authMode.2', '免密认证', 'Confidentiality Auth Mode'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (613, 'menu.ne.neConfig', '网元配置', 'NE Config'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (614, 'dictData.ne_version_status.0', '无', 'Nothing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (615, 'dictData.ne_version_status.1', '已是最新', 'Updated'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (616, 'dictData.ne_version_status.2', '上一版本', 'Previous'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (617, 'dictData.ne_version_status.3', '有新版本', 'Has New'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (618, 'menu.fault.event', '事件通知', 'Event Notification'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (619, 'menu.dashboard.smfCDR', '数据话单', 'Data CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (620, 'log.operate.title.smfCDR', '数据话单', 'Data CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (621, 'config.sys.i18nDefaultRemark', '国际化默认语言可选择 en_US、zh_CN', 'Internationalization default language selectable en_US、zh_CN'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (622, 'config.sys.i18nOpenRemark', '是否显示切换的控件 true/false', 'Whether to display switched controls true/false'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (623, 'menu.dashboard.mmeUE', '4G 终端事件', '4G UE Events'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (624, 'log.operate.title.mmeUE', '4G 终端事件', '4G UE Events'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (625, 'menu.system.user.editPost', '修改用户岗位', 'Modify User Post'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (626, 'menu.dashboard.smscCDR', '短信话单', 'SMS CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (627, 'log.operate.title.smscCDR', '短信话单', 'SMS CDR'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (628, 'menu.trace.pcapFile', '信令抓包文件', 'Signaling Capture File'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (629, 'menu.trace.taskAnalyze', '网元跟踪任务分析', 'NE Trace Task Analysis'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (630, 'job.ne_data_udm', '网元数据-UDM用户数据同步', 'NE Data-Sync UDM Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (631, 'menu.system.setting.doc', '系统使用文档', 'System User Documentation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (632, 'menu.system.setting.official', '官网链接', 'Official Website'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (633, 'menu.system.setting.lock', '锁屏操作', 'Lockscreen Operation'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (634, 'menu.ne.neConfigBackup', '网元配置备份', 'NE Config Backups'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (635, 'job.ne_config_backup', '网元-配置文件定期备份', 'NE-Config Backup Regularly'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (636, 'job.ne_config_backup_remark', '网元配置文件定期备份到网管服务器 +REPLACE INTO "sys_i18n" VALUES (501, 'menu.neUser.nssf', 'NSSF在线订阅数', 'NSSF Subscription Info'); +REPLACE INTO "sys_i18n" VALUES (502, 'menu.neUser.nssfAmf', 'NSSF可用的注册AMF', 'NSSF Available AMFs'); +REPLACE INTO "sys_i18n" VALUES (503, 'menu.monitor.topology', '拓扑信息', 'Topology Info'); +REPLACE INTO "sys_i18n" VALUES (504, 'menu.monitor.topologyBuild', '拓扑图组编辑', 'Topological Graph Build'); +REPLACE INTO "sys_i18n" VALUES (505, 'log.operate.title.chartGraph', '拓扑图组', 'Topological Graph'); +REPLACE INTO "sys_i18n" VALUES (506, 'menu.monitor.topologyArchitecture', '网元拓扑组网', 'NE System Topology'); +REPLACE INTO "sys_i18n" VALUES (507, 'menu.alarm', '告警', 'Alarm'); +REPLACE INTO "sys_i18n" VALUES (508, 'menu.topology', '拓扑', 'Topology'); +REPLACE INTO "sys_i18n" VALUES (509, 'config.sys.lockTime', '系统设置-锁屏超时时长', 'System Settings - Screen Lock Timeout Duration'); +REPLACE INTO "sys_i18n" VALUES (510, 'config.sys.lockTimeRemark', '无操作时锁屏超时时长,单位(秒)。0表示无锁屏超时', 'Timeout of lock screen when no operation, unit (sec), 0 means no timeout of lock screen'); +REPLACE INTO "sys_i18n" VALUES (511, 'sys.account.captchaType', '账号自助-验证码类型', 'Account Self Service - Captcha Type'); +REPLACE INTO "sys_i18n" VALUES (512, 'sys.account.captchaTypeRemark', '使用验证码类型(math数值计算,char字符验证)', 'Using CAPTCHA types (math numeric calculation, char character validation)'); +REPLACE INTO "sys_i18n" VALUES (513, 'menu.dashboard', '仪表盘', 'Dashboard'); +REPLACE INTO "sys_i18n" VALUES (514, 'menu.dashboard.overview', '总览', 'Overview'); +REPLACE INTO "sys_i18n" VALUES (515, 'menu.dashboard.imsCDR', '语音话单', 'Voice CDR'); +REPLACE INTO "sys_i18n" VALUES (516, 'dictType.cdr_sip_code', 'IMS-Voice-SIP响应代码类别类型', 'IMS-Voice-SIP Response Code Category Type'); +REPLACE INTO "sys_i18n" VALUES (517, 'dictType.cdr_call_type', 'IMS-呼叫类型', 'IMS-Call Type'); +REPLACE INTO "sys_i18n" VALUES (518, 'dictType.ue_auth_code', 'UE 事件认证代码类型', 'UE Event Authentication Code Type'); +REPLACE INTO "sys_i18n" VALUES (519, 'dictType.ue_event_type', 'UE 事件类型', 'UE Event Type'); +REPLACE INTO "sys_i18n" VALUES (520, 'dictData.cdr_sip_code.200', '200 正常通话', '200 OK'); +REPLACE INTO "sys_i18n" VALUES (521, 'dictData.cdr_sip_code.403', '403 禁止访问', '403 Forbidden'); +REPLACE INTO "sys_i18n" VALUES (522, 'dictData.cdr_sip_code.408', '408 请求超时', '408 Request Timeout'); +REPLACE INTO "sys_i18n" VALUES (523, 'dictData.cdr_sip_code.500', '500 内部服务器错误', '500 Internal Server Error'); +REPLACE INTO "sys_i18n" VALUES (524, 'dictData.cdr_call_type.audio', '语音', 'Voice'); +REPLACE INTO "sys_i18n" VALUES (525, 'dictData.cdr_call_type.video', '视频', 'Video'); +REPLACE INTO "sys_i18n" VALUES (526, 'dictData.ue_auth_code.200', '成功', 'Success'); +REPLACE INTO "sys_i18n" VALUES (527, 'dictData.ue_auth_code.001', '网络失败', 'Network Failure'); +REPLACE INTO "sys_i18n" VALUES (528, 'dictData.ue_auth_code.002', '接口失败', 'Interface Failure'); +REPLACE INTO "sys_i18n" VALUES (529, 'dictData.ue_auth_code.003', 'MAC失败', 'MAC Failure'); +REPLACE INTO "sys_i18n" VALUES (530, 'dictData.ue_auth_code.004', '同步失败', 'Synchronization failure'); +REPLACE INTO "sys_i18n" VALUES (531, 'dictData.ue_auth_code.005', '不接受非5G认证', 'Non-5G Authentication Not Accepted'); +REPLACE INTO "sys_i18n" VALUES (532, 'dictData.ue_auth_code.006', '响应失败', 'Response Failure'); +REPLACE INTO "sys_i18n" VALUES (533, 'dictData.ue_auth_code.007', '未知', 'Unknown'); +REPLACE INTO "sys_i18n" VALUES (534, 'dictData.ue_event_type.auth', '认证', 'Authentication'); +REPLACE INTO "sys_i18n" VALUES (535, 'dictData.ue_event_type.detach', '注销', 'Detach'); +REPLACE INTO "sys_i18n" VALUES (536, 'dictData.ue_event_type.state', 'CM状态', 'CM Status'); +REPLACE INTO "sys_i18n" VALUES (537, 'dictType.ue_event_cm_state', 'UE 事件CM状态', 'UE Event CM Status'); +REPLACE INTO "sys_i18n" VALUES (538, 'dictData.ue_event_cm_state.connected', '连接', 'Connected'); +REPLACE INTO "sys_i18n" VALUES (539, 'dictData.ue_event_cm_state.idle', '空闲', 'Idle'); +REPLACE INTO "sys_i18n" VALUES (540, 'dictData.ue_event_cm_state.inactive', '不活动', 'Inactive'); +REPLACE INTO "sys_i18n" VALUES (541, 'dictData.cdr_sip_code.404', '404 找不到', '404 Not Found'); +REPLACE INTO "sys_i18n" VALUES (542, 'dictData.cdr_sip_code.487', '487 请求已终止', '487 Request Terminated'); +REPLACE INTO "sys_i18n" VALUES (543, 'dictData.cdr_sip_code.503', '503 服务不可用', '503 Service Unavailable'); +REPLACE INTO "sys_i18n" VALUES (544, 'dictData.cdr_sip_code.504', '504 服务器超时', '504 Server Timeout'); +REPLACE INTO "sys_i18n" VALUES (545, 'dictData.cdr_sip_code.603', '603 拒绝', '603 Decline'); +REPLACE INTO "sys_i18n" VALUES (546, 'dictData.cdr_sip_code.606', '606 不可接受', '606 Not Acceptable'); +REPLACE INTO "sys_i18n" VALUES (547, 'cache.name.token', '用户令牌', 'User Token'); +REPLACE INTO "sys_i18n" VALUES (548, 'cache.name.sys_config', '参数管理', 'Parameters Management'); +REPLACE INTO "sys_i18n" VALUES (549, 'cache.name.sys_dict', '字典管理', 'Dictionary Management'); +REPLACE INTO "sys_i18n" VALUES (550, 'cache.name.captcha_codes', '验证码', 'Captcha'); +REPLACE INTO "sys_i18n" VALUES (551, 'cache.name.repeat_submit', '防重提交', 'Resubmit'); +REPLACE INTO "sys_i18n" VALUES (552, 'cache.name.rate_limit', '限流', 'Limit Traffic'); +REPLACE INTO "sys_i18n" VALUES (553, 'cache.name.pwd_err_cnt', '登录账户密码错误次数', 'Number of Password Errors'); +REPLACE INTO "sys_i18n" VALUES (554, 'cache.name.ne_info', '网元信息管理', 'NE Info Management'); +REPLACE INTO "sys_i18n" VALUES (555, 'cache.name.ne_data', '网元数据管理', 'NE Data Management'); +REPLACE INTO "sys_i18n" VALUES (556, 'dictData.cdr_call_type.sms', '短信', 'SMS'); +REPLACE INTO "sys_i18n" VALUES (557, 'dictData.cdr_sip_code.202', '202 已接受', '202 Accepted'); +REPLACE INTO "sys_i18n" VALUES (558, 'dictData.cdr_sip_code.488', '488 这里不接受', '488 Not Acceptable Here'); +REPLACE INTO "sys_i18n" VALUES (559, 'dictData.cdr_sip_code.0', '0 原因不明', '0 Unknown Reason'); +REPLACE INTO "sys_i18n" VALUES (560, 'log.operate.title.ws', 'WS会话', 'WS Sessions'); +REPLACE INTO "sys_i18n" VALUES (561, 'log.operate.title.neHost', '网元主机', 'NE Host'); +REPLACE INTO "sys_i18n" VALUES (562, 'neHost.noData', '没有可访问主机信息数据!', 'There is no accessible host information data!'); +REPLACE INTO "sys_i18n" VALUES (563, 'neHost.errKeyExists', '主机信息操作【{name}】失败,同组内名称已存在', 'Host information operation [{name}] failed, name already exists in the same group'); +REPLACE INTO "sys_i18n" VALUES (564, 'neHost.errByHostInfo', '连接失败,请检查连接参数后重试', 'Connection Failed, Please check connection parameters and retry'); +REPLACE INTO "sys_i18n" VALUES (565, 'dictType.ne_host_type', '网元主机连接类型', 'Network element host connection type'); +REPLACE INTO "sys_i18n" VALUES (566, 'dictType.ne_host_groupId', '网元主机分组', 'Network element host grouping'); +REPLACE INTO "sys_i18n" VALUES (567, 'dictType.ne_host_authMode', '网元主机认证模式', 'Network element host authentication mode'); +REPLACE INTO "sys_i18n" VALUES (568, 'dictData.ne_host_type.ssh', 'SSH', 'SSH'); +REPLACE INTO "sys_i18n" VALUES (569, 'dictData.ne_host_type.telnet', 'Telnet', 'Telnet'); +REPLACE INTO "sys_i18n" VALUES (570, 'dictData.ne_host_groupId.0', '其他', 'Other'); +REPLACE INTO "sys_i18n" VALUES (571, 'dictData.ne_host_groupId.1', '网元', 'Network Elements'); +REPLACE INTO "sys_i18n" VALUES (572, 'dictData.ne_host_groupId.2', '系统', 'System'); +REPLACE INTO "sys_i18n" VALUES (573, 'dictData.ne_host_authMode.0', '密码认证', 'Password Authentication'); +REPLACE INTO "sys_i18n" VALUES (574, 'dictData.ne_host_authMode.1', '私钥认证', 'Private key authentication'); +REPLACE INTO "sys_i18n" VALUES (575, 'menu.tools.terminal', '主机终端', 'Host Terminal'); +REPLACE INTO "sys_i18n" VALUES (576, 'menu.ne.neHost', '网元主机', 'NE Host'); +REPLACE INTO "sys_i18n" VALUES (577, 'menu.ne.neHostCommand', '网元主机命令', 'NE Host CMD'); +REPLACE INTO "sys_i18n" VALUES (578, 'log.operate.title.neHostCmd', '网元主机命令', 'NE Host CMD'); +REPLACE INTO "sys_i18n" VALUES (579, 'neHostCmd.noData', '没有可访问主机命令数据!', 'No accessible host command data!'); +REPLACE INTO "sys_i18n" VALUES (580, 'neHostCmd.errKeyExists', '主机命令操作【{name}】失败,同组内名称已存在', 'Host command operation [{name}] failed, name already exists in the same group'); +REPLACE INTO "sys_i18n" VALUES (581, 'dictType.ne_host_cmd_groupId', '网元主机命令分组', 'Network element host command grouping'); +REPLACE INTO "sys_i18n" VALUES (582, 'dictData.ne_host_cmd_groupId.0', '默认', 'Default'); +REPLACE INTO "sys_i18n" VALUES (583, 'dictData.ne_host_cmd_groupId.1', '快速命令', 'Quick Commands'); +REPLACE INTO "sys_i18n" VALUES (584, 'menu.ne.neInfo', '网元信息', 'NE Information'); +REPLACE INTO "sys_i18n" VALUES (585, 'log.operate.title.neInfo', '网元信息', 'NE Information'); +REPLACE INTO "sys_i18n" VALUES (586, 'neInfo.noData', '没有可访问网元信息数据!', 'There is no accessible network element information data!'); +REPLACE INTO "sys_i18n" VALUES (587, 'neInfo.errKeyExists', '网元信息操作【{key}】失败,同类型下标识已存在', 'NE info operation [{key}] failed, identifier already exists under the same type'); +REPLACE INTO "sys_i18n" VALUES (588, 'log.operate.title.imsCDR', '通话话单', 'Voice CDR'); +REPLACE INTO "sys_i18n" VALUES (589, 'menu.dashboard.amfUE', '5G 终端事件', '5G UE Events'); +REPLACE INTO "sys_i18n" VALUES (590, 'log.operate.title.amfUE', '5G 终端事件', '5G UE Events'); +REPLACE INTO "sys_i18n" VALUES (591, 'dictData.ne_info_status.0', '离线', 'Offline'); +REPLACE INTO "sys_i18n" VALUES (592, 'dictData.ne_info_status.1', '在线', 'Active'); +REPLACE INTO "sys_i18n" VALUES (593, 'dictData.ne_info_status.2', '等待同步', 'Wait Sync'); +REPLACE INTO "sys_i18n" VALUES (594, 'dictData.ne_info_status.3', '待机', 'Standby'); +REPLACE INTO "sys_i18n" VALUES (595, 'dictType.ne_info_status', '网元信息状态', 'NE Info State'); +REPLACE INTO "sys_i18n" VALUES (596, 'menu.ne.neQuickSetup', '网元快速安装', 'NE Quick Setup'); +REPLACE INTO "sys_i18n" VALUES (597, 'log.operate.title.neConfig', '网元参数配置', 'NE Parameter Configuration'); +REPLACE INTO "sys_i18n" VALUES (598, 'menu.ne.neLicense', '网元许可', 'NE License'); +REPLACE INTO "sys_i18n" VALUES (599, 'log.operate.title.neLicense', '网元许可', 'NE License'); +REPLACE INTO "sys_i18n" VALUES (600, 'menu.ne.neSoftware', '网元软件包', 'NE Software'); +REPLACE INTO "sys_i18n" VALUES (601, 'log.operate.title.neSoftware', '网元软件包', 'NE Software'); +REPLACE INTO "sys_i18n" VALUES (602, 'log.operate.title.neVersion', '网元版本', 'NE Version'); +REPLACE INTO "sys_i18n" VALUES (603, 'menu.ne.neVersion', '网元版本', 'Ne Version'); +REPLACE INTO "sys_i18n" VALUES (604, 'dictType.ne_license_status', '网元许可状态', 'NE License Status'); +REPLACE INTO "sys_i18n" VALUES (605, 'dictData.ne_license_status.0', '无效', 'Invalid'); +REPLACE INTO "sys_i18n" VALUES (606, 'dictData.ne_license_status.1', '有效', 'Valid'); +REPLACE INTO "sys_i18n" VALUES (607, 'menu.dashboard.mocn', 'MOCN', 'MOCN'); +REPLACE INTO "sys_i18n" VALUES (608, 'menu.monitor.cdr', '话单', 'CDR'); +REPLACE INTO "sys_i18n" VALUES (609, 'menu.monitor.event', '事件', 'Events'); +REPLACE INTO "sys_i18n" VALUES (610, 'post.export.time', '创建时间', 'Creation Time'); +REPLACE INTO "sys_i18n" VALUES (611, 'role.export.time', '创建时间', 'Creation Time'); +REPLACE INTO "sys_i18n" VALUES (612, 'dictData.ne_host_authMode.2', '免密认证', 'Confidentiality Auth Mode'); +REPLACE INTO "sys_i18n" VALUES (613, 'menu.ne.neConfig', '网元配置', 'NE Config'); +REPLACE INTO "sys_i18n" VALUES (614, 'dictData.ne_version_status.0', '无', 'Nothing'); +REPLACE INTO "sys_i18n" VALUES (615, 'dictData.ne_version_status.1', '已是最新', 'Updated'); +REPLACE INTO "sys_i18n" VALUES (616, 'dictData.ne_version_status.2', '上一版本', 'Previous'); +REPLACE INTO "sys_i18n" VALUES (617, 'dictData.ne_version_status.3', '有新版本', 'Has New'); +REPLACE INTO "sys_i18n" VALUES (618, 'menu.fault.event', '事件通知', 'Event Notification'); +REPLACE INTO "sys_i18n" VALUES (619, 'menu.dashboard.smfCDR', '数据话单', 'Data CDR'); +REPLACE INTO "sys_i18n" VALUES (620, 'log.operate.title.smfCDR', '数据话单', 'Data CDR'); +REPLACE INTO "sys_i18n" VALUES (621, 'config.sys.i18nDefaultRemark', '国际化默认语言可选择 en_US、zh_CN', 'Internationalization default language selectable en_US、zh_CN'); +REPLACE INTO "sys_i18n" VALUES (622, 'config.sys.i18nOpenRemark', '是否显示切换的控件 true/false', 'Whether to display switched controls true/false'); +REPLACE INTO "sys_i18n" VALUES (623, 'menu.dashboard.mmeUE', '4G 终端事件', '4G UE Events'); +REPLACE INTO "sys_i18n" VALUES (624, 'log.operate.title.mmeUE', '4G 终端事件', '4G UE Events'); +REPLACE INTO "sys_i18n" VALUES (625, 'menu.system.user.editPost', '修改用户岗位', 'Modify User Post'); +REPLACE INTO "sys_i18n" VALUES (626, 'menu.dashboard.smscCDR', '短信话单', 'SMS CDR'); +REPLACE INTO "sys_i18n" VALUES (627, 'log.operate.title.smscCDR', '短信话单', 'SMS CDR'); +REPLACE INTO "sys_i18n" VALUES (628, 'menu.trace.pcapFile', '信令抓包文件', 'Signaling Capture File'); +REPLACE INTO "sys_i18n" VALUES (629, 'menu.trace.taskAnalyze', '网元跟踪任务分析', 'NE Trace Task Analysis'); +REPLACE INTO "sys_i18n" VALUES (630, 'job.ne_data_udm', '网元数据-UDM用户数据同步', 'NE Data-Sync UDM Data'); +REPLACE INTO "sys_i18n" VALUES (631, 'menu.system.setting.doc', '系统使用文档', 'System User Documentation'); +REPLACE INTO "sys_i18n" VALUES (632, 'menu.system.setting.official', '官网链接', 'Official Website'); +REPLACE INTO "sys_i18n" VALUES (633, 'menu.system.setting.lock', '锁屏操作', 'Lockscreen Operation'); +REPLACE INTO "sys_i18n" VALUES (634, 'menu.ne.neConfigBackup', '网元配置备份', 'NE Config Backups'); +REPLACE INTO "sys_i18n" VALUES (635, 'job.ne_config_backup', '网元-配置文件定期备份', 'NE-Config Backup Regularly'); +REPLACE INTO "sys_i18n" VALUES (636, 'job.ne_config_backup_remark', '网元配置文件定期备份到网管服务器 可查看网元配置备份记录进行下载或通过网元信息操作导入配置', 'Network Element Configuration files are regularly backed up to the OMC View network element configuration backup records for downloading or importing configurations through network element information operations.'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (637, 'job.backup_export_table_sys_log_operate', '备份-操作日志表定期导出', 'Backup-Operation Log Table Periodic Export'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (638, 'job.backup_export_table_cdr_event_ims', '备份-语音话单表定期导出', 'Backup-Regular Export of voice bill forms'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (639, 'job.backup_export_table_cdr_event_smf', '备份-数据话单表定期导出', 'Backup-Regular Export of data sheet tables'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (640, 'cache.name.oauth2_codes', '客户端授权码', 'Oauth2 Client Code'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (641, 'cache.name.oauth2_devices', '客户端令牌', 'Oauth2 Token'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (642, 'job.backup_export_cdr', '备份-CDR数据定期导出', 'Backup-Periodic export of CDR Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (643, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc +REPLACE INTO "sys_i18n" VALUES (637, 'job.backup_export_table_sys_log_operate', '备份-操作日志表定期导出', 'Backup-Operation Log Table Periodic Export'); +REPLACE INTO "sys_i18n" VALUES (638, 'job.backup_export_table_cdr_event_ims', '备份-语音话单表定期导出', 'Backup-Regular Export of voice bill forms'); +REPLACE INTO "sys_i18n" VALUES (639, 'job.backup_export_table_cdr_event_smf', '备份-数据话单表定期导出', 'Backup-Regular Export of data sheet tables'); +REPLACE INTO "sys_i18n" VALUES (640, 'cache.name.oauth2_codes', '客户端授权码', 'Oauth2 Client Code'); +REPLACE INTO "sys_i18n" VALUES (641, 'cache.name.oauth2_devices', '客户端令牌', 'Oauth2 Token'); +REPLACE INTO "sys_i18n" VALUES (642, 'job.backup_export_cdr', '备份-CDR数据定期导出', 'Backup-Periodic export of CDR Data'); +REPLACE INTO "sys_i18n" VALUES (643, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc fileType: 文件类型 csv/xlsx hour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support ims/smf/sgwc/smsc fileType: file type csv/xlsx hour: data time from the hour before the task execution time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (644, 'menu.log.exportFile', '导出文件', 'Exported File'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (645, 'menu.perf.kpiCReport', '自定义指标数据', 'Custom Indicator Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (646, 'menu.trace.taskHLR', 'HLR 跟踪任务', 'HLR Trace Task'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (647, 'dictType.cdr_cause_code', 'CDR 响应原因代码类别类型', 'CDR Response Reason Code Category Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (648, 'dictData.cdr_cause_code.0', '未知错误', 'Unknown Error'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (649, 'dictData.cdr_cause_code.8', '运营者确定的禁止', 'Operator determined barring'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (650, 'dictData.cdr_cause_code.10', '禁止呼叫', 'Call Barred'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (651, 'dictData.cdr_cause_code.21', '呼叫被拒', 'Call rejected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (652, 'dictData.cdr_cause_code.22', '数量已更改', 'Number changed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (653, 'dictData.cdr_cause_code.27', '目的地出错', 'Destination out of order'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (654, 'dictData.cdr_cause_code.28', '数字格式无效(数字不完整)', 'Invalid number format (incomplete number)'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (655, 'dictData.cdr_cause_code.29', '设施被拒', 'Facility rejected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (656, 'dictData.cdr_cause_code.30', '回复状态查询', 'Response to STATUS ENQUIRY'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (657, 'dictData.cdr_cause_code.38', '网络故障', 'Network out of order'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (658, 'dictData.cdr_cause_code.41', '临时故障', 'Temporary failure'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (659, 'dictData.cdr_cause_code.42', '交换设备拥塞', 'Switching equipment congestion'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (660, 'dictData.cdr_cause_code.47', '资源不可用', 'Resource unavailable, unspecified'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (661, 'dictData.cdr_cause_code.50', '请求的设施未订阅', 'Requested facility not subscribed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (662, 'job.backup_export_table_cdr_event_smsc', '备份-短信话单表定期导出', 'Backup-Regular Export of SMS call list'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (663, 'job.backup_remove_file', '备份-定期删除备份目录下文件', 'Backup-Periodically Delete Directory Files'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (664, 'config.sys.homePage', '自定义主页', 'Custom Home Page'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (665, 'config.sys.homePageRemark', '选择列表中的任一页面作为主页路径', 'Select any page in the list as the homepage'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (666, 'menu.ne.neOverview', '网元概览', 'NE Overview'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (667, 'menu.ne.neOverviewRemark', '显示所有网元状态配置和license等概览信息', 'Displays overview information such as status, configuration and license of all network elements'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (668, 'job.backup_export_table_cdr_event_sgwc', '备份-漫游数据话单表定期导出', 'Backup-Regular Export of Roaming Data table'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (669, 'cache.name.i18n', '国际化语言管理', 'Internationalized Language Management'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (670, 'config.sys.user.passwordPolicy', '用户管理-默认密码策略强度', 'User Management-Default Password Policy Strength'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (671, 'config.sys.user.passwordPolicyRemark', 'minLength:密码至少8个字符 +REPLACE INTO "sys_i18n" VALUES (644, 'menu.log.exportFile', '导出文件', 'Exported File'); +REPLACE INTO "sys_i18n" VALUES (645, 'menu.perf.kpiCReport', '自定义指标数据', 'Custom Indicator Data'); +REPLACE INTO "sys_i18n" VALUES (646, 'menu.trace.taskHLR', 'HLR 跟踪任务', 'HLR Trace Task'); +REPLACE INTO "sys_i18n" VALUES (647, 'dictType.cdr_cause_code', 'CDR 响应原因代码类别类型', 'CDR Response Reason Code Category Type'); +REPLACE INTO "sys_i18n" VALUES (648, 'dictData.cdr_cause_code.0', '未知错误', 'Unknown Error'); +REPLACE INTO "sys_i18n" VALUES (649, 'dictData.cdr_cause_code.8', '运营者确定的禁止', 'Operator determined barring'); +REPLACE INTO "sys_i18n" VALUES (650, 'dictData.cdr_cause_code.10', '禁止呼叫', 'Call Barred'); +REPLACE INTO "sys_i18n" VALUES (651, 'dictData.cdr_cause_code.21', '呼叫被拒', 'Call rejected'); +REPLACE INTO "sys_i18n" VALUES (652, 'dictData.cdr_cause_code.22', '数量已更改', 'Number changed'); +REPLACE INTO "sys_i18n" VALUES (653, 'dictData.cdr_cause_code.27', '目的地出错', 'Destination out of order'); +REPLACE INTO "sys_i18n" VALUES (654, 'dictData.cdr_cause_code.28', '数字格式无效(数字不完整)', 'Invalid number format (incomplete number)'); +REPLACE INTO "sys_i18n" VALUES (655, 'dictData.cdr_cause_code.29', '设施被拒', 'Facility rejected'); +REPLACE INTO "sys_i18n" VALUES (656, 'dictData.cdr_cause_code.30', '回复状态查询', 'Response to STATUS ENQUIRY'); +REPLACE INTO "sys_i18n" VALUES (657, 'dictData.cdr_cause_code.38', '网络故障', 'Network out of order'); +REPLACE INTO "sys_i18n" VALUES (658, 'dictData.cdr_cause_code.41', '临时故障', 'Temporary failure'); +REPLACE INTO "sys_i18n" VALUES (659, 'dictData.cdr_cause_code.42', '交换设备拥塞', 'Switching equipment congestion'); +REPLACE INTO "sys_i18n" VALUES (660, 'dictData.cdr_cause_code.47', '资源不可用', 'Resource unavailable, unspecified'); +REPLACE INTO "sys_i18n" VALUES (661, 'dictData.cdr_cause_code.50', '请求的设施未订阅', 'Requested facility not subscribed'); +REPLACE INTO "sys_i18n" VALUES (662, 'job.backup_export_table_cdr_event_smsc', '备份-短信话单表定期导出', 'Backup-Regular Export of SMS call list'); +REPLACE INTO "sys_i18n" VALUES (663, 'job.backup_remove_file', '备份-定期删除备份目录下文件', 'Backup-Periodically Delete Directory Files'); +REPLACE INTO "sys_i18n" VALUES (664, 'config.sys.homePage', '自定义主页', 'Custom Home Page'); +REPLACE INTO "sys_i18n" VALUES (665, 'config.sys.homePageRemark', '选择列表中的任一页面作为主页路径', 'Select any page in the list as the homepage'); +REPLACE INTO "sys_i18n" VALUES (666, 'menu.ne.neOverview', '网元概览', 'NE Overview'); +REPLACE INTO "sys_i18n" VALUES (667, 'menu.ne.neOverviewRemark', '显示所有网元状态配置和license等概览信息', 'Displays overview information such as status, configuration and license of all network elements'); +REPLACE INTO "sys_i18n" VALUES (668, 'job.backup_export_table_cdr_event_sgwc', '备份-漫游数据话单表定期导出', 'Backup-Regular Export of Roaming Data table'); +REPLACE INTO "sys_i18n" VALUES (669, 'cache.name.i18n', '国际化语言管理', 'Internationalized Language Management'); +REPLACE INTO "sys_i18n" VALUES (670, 'config.sys.user.passwordPolicy', '用户管理-默认密码策略强度', 'User Management-Default Password Policy Strength'); +REPLACE INTO "sys_i18n" VALUES (671, 'config.sys.user.passwordPolicyRemark', 'minLength:密码至少8个字符 specialChars:至少包含2个特殊字符(例如:!@#$%^&*()) uppercase:至少包含一个大写字母 lowercase:至少包含一个小写字母', 'minLength: password should be at least 8 characters long specialChars: at least 2 special characters (e.g. ! @#$%^&*()) uppercase: contain at least one uppercase letter lowercase: contains at least one lowercase letter'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (672, 'config.sys.user.passwdExpire', '用户管理-密码有效期', 'User Management-Password Expiration Date'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (673, 'config.sys.user.passwdExpireRemark', '数值单位(小时) +REPLACE INTO "sys_i18n" VALUES (672, 'config.sys.user.passwdExpire', '用户管理-密码有效期', 'User Management-Password Expiration Date'); +REPLACE INTO "sys_i18n" VALUES (673, 'config.sys.user.passwdExpireRemark', '数值单位(小时) expHours为过期时间,0表示不启用 alertHours即将到期提醒时间', 'Numerical unit (hours) expHours for the expiration time, 0 means not enabled alertHours upcoming expiration reminder time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (674, 'config.sys.user.passwdNotAllowedHistory', '用户管理-不允许使用最近密码次数', 'User Management-Not Allowed Recent Passwords'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (675, 'config.sys.user.passwdNotAllowedHistoryRemark', '创建新密码不等于之前使用的x次中的密码', 'Creating a new password that is not equal to the previously used password in x times'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (676, 'login.errPasswdHistory', '不允许使用最近密码', 'Recent passwords not allowed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (677, 'log.operate.title.oauth2client', 'Oauth2客户端授权', 'Oauth2 Client Authorization'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (678, 'log.operate.title.pcfRule', '终端策略规则', 'UE PCC Rule'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (679, 'dictType.trace_msg_type', '跟踪消息类型', 'Trace Message Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (680, 'dictData.trace_msg_type.0', '请求', 'Request'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (681, 'dictData.trace_msg_type.1', '响应', 'Response'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (682, 'dictType.trace_msg_direct', '跟踪消息方向', 'Track Message Direction'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (683, 'dictData.trace_msg_direct.0', '接收', 'Receive'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (684, 'dictData.trace_msg_direct.1', '发送', 'Send'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (685, 'dictData.trace_interfaces.1', 'N1', 'N1'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (686, 'dictData.trace_interfaces.2', 'N2', 'N2'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (687, 'dictData.trace_interfaces.3', 'N1/N2', 'N1/N2'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (688, 'dictData.trace_interfaces.4', 'N4', 'N4'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (689, 'dictData.trace_interfaces.8', 'N8', 'N8'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (690, 'dictData.trace_interfaces.10', 'N10', 'N10'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (691, 'dictData.trace_interfaces.11', 'N11', 'N11'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (692, 'dictData.trace_interfaces.12', 'N12', 'N12'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (693, 'dictData.trace_interfaces.13', 'N13', 'N13'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (694, 'dictData.trace_interfaces.7', 'N7', 'N7'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (695, 'dictData.trace_interfaces.15', 'N15', 'N15'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (696, 'dictData.trace_interfaces.17', 'N17', 'N17'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (697, 'dictData.trace_interfaces.20', 'N20', 'N20'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (698, 'dictData.trace_interfaces.22', 'N22', 'N22'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (699, 'dictData.trace_interfaces.40', 'N40', 'N40'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (700, 'dictData.cdr_sip_code.302', '302 原因不明', '302 Unknown Reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (701, 'dictData.cdr_sip_code.402', '402 原因不明', '402 Unknown Reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (702, 'dictData.cdr_sip_code.480', '480 被叫挂断/拒接', '480 Temporarily Unavailable'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (703, 'dictData.cdr_sip_code.481', '481 原因不明', '481 Unknown Reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (704, 'dictData.cdr_sip_code.482', '482 发现环路', '482 Loop Detected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (705, 'dictData.cdr_sip_code.486', '486 这里很忙', '486 Busy Here'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (706, 'dictData.cdr_sip_code.489', '489 原因不明', '489 Unknown Reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (707, 'dictData.cdr_sip_code.580', '580 原因不明', '580 Unknown Reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (708, 'alarm.export.alarmType', '告警类型', 'Alarm Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (709, 'alarm.export.origSeverity', '告警级别', 'Severity'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (710, 'alarm.export.alarmTitle', '告警标题', 'Alarm Title'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (711, 'alarm.export.eventTime', '告警产生时间', 'Event Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (712, 'alarm.export.alarmId', '告警唯一标识', 'Alarm ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (713, 'alarm.export.clearUser', '告警清除用户', 'Clear User'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (714, 'alarm.export.clearType', '告警清除类型', 'Clear Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (715, 'alarm.export.clearTime', '告警清除时间', 'Clear Time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (716, 'log.operate.title.alarm', '告警', 'Alarm'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (717, 'ne.common.neType', '网元类型', 'NE Type'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (718, 'ne.common.neName', '网元名称', 'NE Name'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (719, 'ne.common.neId', '网元标识', 'NE ID'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (720, 'log.operate.title.udmVOIP', 'VOIP用户', 'UDM VOIP'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (721, 'log.operate.title.udmVolteIMS', 'VolteIMS用户', 'UDM VolteIMS'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (722, 'log.operate.title.backup', '备份', 'Backup'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (723, 'job.backup_export_table_cdr_event_smsc_remark', 'hour: 数据时间从任务执行时间前的小时数 +REPLACE INTO "sys_i18n" VALUES (674, 'config.sys.user.passwdNotAllowedHistory', '用户管理-不允许使用最近密码次数', 'User Management-Not Allowed Recent Passwords'); +REPLACE INTO "sys_i18n" VALUES (675, 'config.sys.user.passwdNotAllowedHistoryRemark', '创建新密码不等于之前使用的x次中的密码', 'Creating a new password that is not equal to the previously used password in x times'); +REPLACE INTO "sys_i18n" VALUES (676, 'login.errPasswdHistory', '不允许使用最近密码', 'Recent passwords not allowed'); +REPLACE INTO "sys_i18n" VALUES (677, 'log.operate.title.oauth2client', 'Oauth2客户端授权', 'Oauth2 Client Authorization'); +REPLACE INTO "sys_i18n" VALUES (678, 'log.operate.title.pcfRule', '终端策略规则', 'UE PCC Rule'); +REPLACE INTO "sys_i18n" VALUES (679, 'dictType.trace_msg_type', '跟踪消息类型', 'Trace Message Type'); +REPLACE INTO "sys_i18n" VALUES (680, 'dictData.trace_msg_type.0', '请求', 'Request'); +REPLACE INTO "sys_i18n" VALUES (681, 'dictData.trace_msg_type.1', '响应', 'Response'); +REPLACE INTO "sys_i18n" VALUES (682, 'dictType.trace_msg_direct', '跟踪消息方向', 'Track Message Direction'); +REPLACE INTO "sys_i18n" VALUES (683, 'dictData.trace_msg_direct.0', '接收', 'Receive'); +REPLACE INTO "sys_i18n" VALUES (684, 'dictData.trace_msg_direct.1', '发送', 'Send'); +REPLACE INTO "sys_i18n" VALUES (685, 'dictData.trace_interfaces.1', 'N1', 'N1'); +REPLACE INTO "sys_i18n" VALUES (686, 'dictData.trace_interfaces.2', 'N2', 'N2'); +REPLACE INTO "sys_i18n" VALUES (687, 'dictData.trace_interfaces.3', 'N1/N2', 'N1/N2'); +REPLACE INTO "sys_i18n" VALUES (688, 'dictData.trace_interfaces.4', 'N4', 'N4'); +REPLACE INTO "sys_i18n" VALUES (689, 'dictData.trace_interfaces.8', 'N8', 'N8'); +REPLACE INTO "sys_i18n" VALUES (690, 'dictData.trace_interfaces.10', 'N10', 'N10'); +REPLACE INTO "sys_i18n" VALUES (691, 'dictData.trace_interfaces.11', 'N11', 'N11'); +REPLACE INTO "sys_i18n" VALUES (692, 'dictData.trace_interfaces.12', 'N12', 'N12'); +REPLACE INTO "sys_i18n" VALUES (693, 'dictData.trace_interfaces.13', 'N13', 'N13'); +REPLACE INTO "sys_i18n" VALUES (694, 'dictData.trace_interfaces.7', 'N7', 'N7'); +REPLACE INTO "sys_i18n" VALUES (695, 'dictData.trace_interfaces.15', 'N15', 'N15'); +REPLACE INTO "sys_i18n" VALUES (696, 'dictData.trace_interfaces.17', 'N17', 'N17'); +REPLACE INTO "sys_i18n" VALUES (697, 'dictData.trace_interfaces.20', 'N20', 'N20'); +REPLACE INTO "sys_i18n" VALUES (698, 'dictData.trace_interfaces.22', 'N22', 'N22'); +REPLACE INTO "sys_i18n" VALUES (699, 'dictData.trace_interfaces.40', 'N40', 'N40'); +REPLACE INTO "sys_i18n" VALUES (700, 'dictData.cdr_sip_code.302', '302 原因不明', '302 Unknown Reason'); +REPLACE INTO "sys_i18n" VALUES (701, 'dictData.cdr_sip_code.402', '402 原因不明', '402 Unknown Reason'); +REPLACE INTO "sys_i18n" VALUES (702, 'dictData.cdr_sip_code.480', '480 被叫挂断/拒接', '480 Temporarily Unavailable'); +REPLACE INTO "sys_i18n" VALUES (703, 'dictData.cdr_sip_code.481', '481 原因不明', '481 Unknown Reason'); +REPLACE INTO "sys_i18n" VALUES (704, 'dictData.cdr_sip_code.482', '482 发现环路', '482 Loop Detected'); +REPLACE INTO "sys_i18n" VALUES (705, 'dictData.cdr_sip_code.486', '486 这里很忙', '486 Busy Here'); +REPLACE INTO "sys_i18n" VALUES (706, 'dictData.cdr_sip_code.489', '489 原因不明', '489 Unknown Reason'); +REPLACE INTO "sys_i18n" VALUES (707, 'dictData.cdr_sip_code.580', '580 原因不明', '580 Unknown Reason'); +REPLACE INTO "sys_i18n" VALUES (708, 'alarm.export.alarmType', '告警类型', 'Alarm Type'); +REPLACE INTO "sys_i18n" VALUES (709, 'alarm.export.origSeverity', '告警级别', 'Severity'); +REPLACE INTO "sys_i18n" VALUES (710, 'alarm.export.alarmTitle', '告警标题', 'Alarm Title'); +REPLACE INTO "sys_i18n" VALUES (711, 'alarm.export.eventTime', '告警产生时间', 'Event Time'); +REPLACE INTO "sys_i18n" VALUES (712, 'alarm.export.alarmId', '告警唯一标识', 'Alarm ID'); +REPLACE INTO "sys_i18n" VALUES (713, 'alarm.export.clearUser', '告警清除用户', 'Clear User'); +REPLACE INTO "sys_i18n" VALUES (714, 'alarm.export.clearType', '告警清除类型', 'Clear Type'); +REPLACE INTO "sys_i18n" VALUES (715, 'alarm.export.clearTime', '告警清除时间', 'Clear Time'); +REPLACE INTO "sys_i18n" VALUES (716, 'log.operate.title.alarm', '告警', 'Alarm'); +REPLACE INTO "sys_i18n" VALUES (717, 'ne.common.neType', '网元类型', 'NE Type'); +REPLACE INTO "sys_i18n" VALUES (718, 'ne.common.neName', '网元名称', 'NE Name'); +REPLACE INTO "sys_i18n" VALUES (719, 'ne.common.neId', '网元标识', 'NE ID'); +REPLACE INTO "sys_i18n" VALUES (720, 'log.operate.title.udmVOIP', 'VOIP用户', 'UDM VOIP'); +REPLACE INTO "sys_i18n" VALUES (721, 'log.operate.title.udmVolteIMS', 'VolteIMS用户', 'UDM VolteIMS'); +REPLACE INTO "sys_i18n" VALUES (722, 'log.operate.title.backup', '备份', 'Backup'); +REPLACE INTO "sys_i18n" VALUES (723, 'job.backup_export_table_cdr_event_smsc_remark', 'hour: 数据时间从任务执行时间前的小时数 tableName: 数据表名 columns: 支持字段 backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time tableName: data table name columns: support fields backupPath: backup output path /usr/local/omc/backup/{backupPath}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (724, 'job.backup_export_table_cdr_event_sgwc_remark', 'hour: 数据时间从任务执行时间前的小时数 +REPLACE INTO "sys_i18n" VALUES (724, 'job.backup_export_table_cdr_event_sgwc_remark', 'hour: 数据时间从任务执行时间前的小时数 tableName: 数据表名 columns: 支持字段 backupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time tableName: data table name columns: support fields backupPath: backup output path /usr/local/omc/backup/{backupPath}'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (725, 'job.backup_remove_file_remark', 'backupPath: 备份路径 /usr/local/omc/backup/{backupPath} +REPLACE INTO "sys_i18n" VALUES (725, 'job.backup_remove_file_remark', 'backupPath: 备份路径 /usr/local/omc/backup/{backupPath} storeDays: 保留天数 storeNum: 保留数量,默认保留7', 'backupPath: backup path /usr/local/omc/backup/{backupPath} storeDays: retention days storeNum: retention number, default retention 7'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (726, 'job.backup_export_udm', '备份-UDM数据定期导出', 'Backup-Periodic export of UDM Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (727, 'job.backup_export_udm_remark', 'dataType: 类型支持 auth/sub/voip/volte +REPLACE INTO "sys_i18n" VALUES (726, 'job.backup_export_udm', '备份-UDM数据定期导出', 'Backup-Periodic export of UDM Data'); +REPLACE INTO "sys_i18n" VALUES (727, 'job.backup_export_udm_remark', 'dataType: 类型支持 auth/sub/voip/volte fileType: 文件类型 csv/txt', 'Backup-Periodic export of dataType: type support auth/sub/voip/volte fileType: file type csv/txt'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (728, 'dictData.cdr_sip_code_cause.0', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常通话清除', 'Normal Call Clearing'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务器本身出了问题', 'Something went wrong inside the server itself'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (751, 'job.backup_export_log_remark', 'dataType: 类型支持 operate/login +REPLACE INTO "sys_i18n" VALUES (728, 'dictData.cdr_sip_code_cause.0', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常通话清除', 'Normal Call Clearing'); +REPLACE INTO "sys_i18n" VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); +REPLACE INTO "sys_i18n" VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); +REPLACE INTO "sys_i18n" VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); +REPLACE INTO "sys_i18n" VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); +REPLACE INTO "sys_i18n" VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); +REPLACE INTO "sys_i18n" VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); +REPLACE INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); +REPLACE INTO "sys_i18n" VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); +REPLACE INTO "sys_i18n" VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); +REPLACE INTO "sys_i18n" VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务器本身出了问题', 'Something went wrong inside the server itself'); +REPLACE INTO "sys_i18n" VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); +REPLACE INTO "sys_i18n" VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); +REPLACE INTO "sys_i18n" VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); +REPLACE INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); +REPLACE INTO "sys_i18n" VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); +REPLACE INTO "sys_i18n" VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); +REPLACE INTO "sys_i18n" VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); +REPLACE INTO "sys_i18n" VALUES (751, 'job.backup_export_log_remark', 'dataType: 类型支持 operate/login fileType: 文件类型 csv/xlsx hour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support operate/login fileType: file type csv/xlsx hour: data time from the hour before the task execution time'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (752, 'job.ne_alarm_state_check_cmd', '网元告警-内存/CPU/磁盘检查', 'NE Alarm-Memory/CPU/Disk Checks'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (753, 'job.ne_alarm_state_check_cmd_remark', '检查网元的内存/CPU/磁盘检查健康状况,在出现过阈值时发出警报。 +REPLACE INTO "sys_i18n" VALUES (752, 'job.ne_alarm_state_check_cmd', '网元告警-内存/CPU/磁盘检查', 'NE Alarm-Memory/CPU/Disk Checks'); +REPLACE INTO "sys_i18n" VALUES (753, 'job.ne_alarm_state_check_cmd_remark', '检查网元的内存/CPU/磁盘检查健康状况,在出现过阈值时发出警报。 Alarm type: CommunicationAlarm=1 @@ -893,8 +893,8 @@ AddInfo: Additional information on alarms cpuUseGt: CPU utilization is greater than, range 0~100*number of CPU cores memUseGt: Memory utilization greater than, range 0 to 100% diskUseGt: Disk utilization greater than, range 0 to 100%'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (754, 'job.ne_alarm_state_check_license', '网元告警-License到期检查', 'NE Alarm-License Expire Check'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。 +REPLACE INTO "sys_i18n" VALUES (754, 'job.ne_alarm_state_check_license', '网元告警-License到期检查', 'NE Alarm-License Expire Check'); +REPLACE INTO "sys_i18n" VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。 Alarm type: CommunicationAlarm=1 @@ -927,5 +927,6 @@ Warning=4 AddInfo: Additional information on alarms dayLt: Days less than, default 30 days'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (756, 'dictData.trace_interfaces.14', 'N14', 'N14'); -REPLACE INTO "sys_i18n" ("id", "key_lable", "value_zh", "value_en") VALUES (757, 'dictData.trace_interfaces.5', 'N5', 'N5'); +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"); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 3078cb13..79d290fe 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -772,5 +772,6 @@ INSERT INTO `sys_i18n` VALUES (754, 'job.ne_alarm_state_check_license', '网元 INSERT INTO `sys_i18n` VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。\r\n\r\nAlarm type:\r\nCommunicationAlarm=1\r\nEquipmentAlarm=2\r\nProcessingFailure=3\r\nEnvironmentalAlarm=4\r\nQualityOfServiceAlarm=5\r\n\r\nSeverity:\r\nCritical=1\r\nMajor=2\r\nMinor=3\r\nWarning=4\r\n\r\nAddInfo: 告警补充信息\r\ndayLt: 天数小于,默认30天', 'Checks if the network element is License is about to expire and sends an alert if a threshold is crossed.\n\nAlarm type:\nCommunicationAlarm=1\nEquipmentAlarm=2\nProcessingFailure=3\nEnvironmentalAlarm=4\nQualityOfServiceAlarm=5\n\nSeverity:\nCritical=1\nMajor=2\nMinor=3\nWarning=4\r\n\r\nAddInfo: Additional information on alarms\r\ndayLt: Days less than, default 30 days'); 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"); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index f5558c26..048c044b 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -769,5 +769,6 @@ REPLACE INTO `sys_i18n` VALUES (754, 'job.ne_alarm_state_check_license', '网元 REPLACE INTO `sys_i18n` VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。\r\n\r\nAlarm type:\r\nCommunicationAlarm=1\r\nEquipmentAlarm=2\r\nProcessingFailure=3\r\nEnvironmentalAlarm=4\r\nQualityOfServiceAlarm=5\r\n\r\nSeverity:\r\nCritical=1\r\nMajor=2\r\nMinor=3\r\nWarning=4\r\n\r\nAddInfo: 告警补充信息\r\ndayLt: 天数小于,默认30天', 'Checks if the network element is License is about to expire and sends an alert if a threshold is crossed.\n\nAlarm type:\nCommunicationAlarm=1\nEquipmentAlarm=2\nProcessingFailure=3\nEnvironmentalAlarm=4\nQualityOfServiceAlarm=5\n\nSeverity:\nCritical=1\nMajor=2\nMinor=3\nWarning=4\r\n\r\nAddInfo: Additional information on alarms\r\ndayLt: Days less than, default 30 days'); 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"); -- Dump completed on 2025-02-14 15:26:56 From c9b9408f1d739bd88ffc890953a31bd1c338c236 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 23 Jul 2025 14:05:07 +0800 Subject: [PATCH 42/80] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0IMS-CDR=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E7=A0=81=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 10 +++++----- build/database/lite/upgrade/upg_sys_i18n.sql | 10 +++++----- build/database/std/install/sys_i18n.sql | 10 +++++----- build/database/std/upgrade/upg_sys_i18n.sql | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index 53186caa..538f12ff 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -833,13 +833,13 @@ INSERT INTO "sys_i18n" VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常 INSERT INTO "sys_i18n" VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); INSERT INTO "sys_i18n" VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); INSERT INTO "sys_i18n" VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); -INSERT INTO "sys_i18n" VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); -INSERT INTO "sys_i18n" VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); +INSERT INTO "sys_i18n" VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒接主叫用户', 'MO User Rejected'); +INSERT INTO "sys_i18n" VALUES (734, 'dictData.cdr_sip_code_cause.404', '被叫用户离线', 'MT User Offline'); INSERT INTO "sys_i18n" VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); INSERT INTO "sys_i18n" VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); INSERT INTO "sys_i18n" VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); -INSERT INTO "sys_i18n" VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -INSERT INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); +INSERT INTO "sys_i18n" VALUES (738, 'dictData.cdr_sip_code_cause.486', '被叫用户忙', 'MT User Busy'); +INSERT INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', '主叫挂断', 'MO User Disconnected'); INSERT INTO "sys_i18n" VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); INSERT INTO "sys_i18n" VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); INSERT INTO "sys_i18n" VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -847,7 +847,7 @@ INSERT INTO "sys_i18n" VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 INSERT INTO "sys_i18n" VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); INSERT INTO "sys_i18n" VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); INSERT INTO "sys_i18n" VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -INSERT INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); +INSERT INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', '被叫拒接', 'MT explicitly rejected the call'); INSERT INTO "sys_i18n" VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); INSERT INTO "sys_i18n" VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); INSERT INTO "sys_i18n" VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index 5bddf13d..e11b4272 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -832,13 +832,13 @@ REPLACE INTO "sys_i18n" VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常 REPLACE INTO "sys_i18n" VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); REPLACE INTO "sys_i18n" VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); REPLACE INTO "sys_i18n" VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); -REPLACE INTO "sys_i18n" VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); +REPLACE INTO "sys_i18n" VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒接主叫用户', 'MO User Rejected'); +REPLACE INTO "sys_i18n" VALUES (734, 'dictData.cdr_sip_code_cause.404', '被叫用户离线', 'MT User Offline'); REPLACE INTO "sys_i18n" VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); REPLACE INTO "sys_i18n" VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); REPLACE INTO "sys_i18n" VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); -REPLACE INTO "sys_i18n" VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -REPLACE INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); +REPLACE INTO "sys_i18n" VALUES (738, 'dictData.cdr_sip_code_cause.486', '被叫用户忙', 'MT User Busy'); +REPLACE INTO "sys_i18n" VALUES (739, 'dictData.cdr_sip_code_cause.487', '主叫挂断', 'MO User Disconnected'); REPLACE INTO "sys_i18n" VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); REPLACE INTO "sys_i18n" VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); REPLACE INTO "sys_i18n" VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -846,7 +846,7 @@ REPLACE INTO "sys_i18n" VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 REPLACE INTO "sys_i18n" VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); REPLACE INTO "sys_i18n" VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); REPLACE INTO "sys_i18n" VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); +REPLACE INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', '被叫拒接', 'MT explicitly rejected the call'); REPLACE INTO "sys_i18n" VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); REPLACE INTO "sys_i18n" VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); REPLACE INTO "sys_i18n" VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 79d290fe..4e84a680 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -747,13 +747,13 @@ INSERT INTO `sys_i18n` VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常 INSERT INTO `sys_i18n` VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); INSERT INTO `sys_i18n` VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); INSERT INTO `sys_i18n` VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); -INSERT INTO `sys_i18n` VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); -INSERT INTO `sys_i18n` VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); +INSERT INTO `sys_i18n` VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒接主叫用户', 'MO User Rejected'); +INSERT INTO `sys_i18n` VALUES (734, 'dictData.cdr_sip_code_cause.404', '被叫用户离线', 'MT User Offline'); INSERT INTO `sys_i18n` VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); INSERT INTO `sys_i18n` VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); INSERT INTO `sys_i18n` VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); -INSERT INTO `sys_i18n` VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -INSERT INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); +INSERT INTO `sys_i18n` VALUES (738, 'dictData.cdr_sip_code_cause.486', '被叫用户忙', 'MT User Busy'); +INSERT INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', '主叫挂断', 'MO User Disconnected'); INSERT INTO `sys_i18n` VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); INSERT INTO `sys_i18n` VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); INSERT INTO `sys_i18n` VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -761,7 +761,7 @@ INSERT INTO `sys_i18n` VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 INSERT INTO `sys_i18n` VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); INSERT INTO `sys_i18n` VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); INSERT INTO `sys_i18n` VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -INSERT INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); +INSERT INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', '被叫拒接', 'MT explicitly rejected the call'); INSERT INTO `sys_i18n` VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); INSERT INTO `sys_i18n` VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); INSERT INTO `sys_i18n` VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index 048c044b..f89bccb3 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -744,13 +744,13 @@ REPLACE INTO `sys_i18n` VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常 REPLACE INTO `sys_i18n` VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); REPLACE INTO `sys_i18n` VALUES (731, 'dictData.cdr_sip_code_cause.302', '因其他原因呼叫失败', 'Call failure for other reason'); REPLACE INTO `sys_i18n` VALUES (732, 'dictData.cdr_sip_code_cause.402', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO `sys_i18n` VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒绝 MO 用户', 'MO User Rejected'); -REPLACE INTO `sys_i18n` VALUES (734, 'dictData.cdr_sip_code_cause.404', 'MT 用户离线', 'MT User Offline'); +REPLACE INTO `sys_i18n` VALUES (733, 'dictData.cdr_sip_code_cause.403', '拒接主叫用户', 'MO User Rejected'); +REPLACE INTO `sys_i18n` VALUES (734, 'dictData.cdr_sip_code_cause.404', '被叫用户离线', 'MT User Offline'); REPLACE INTO `sys_i18n` VALUES (735, 'dictData.cdr_sip_code_cause.480', '因其他原因呼叫失败', 'Call failure for other reason'); REPLACE INTO `sys_i18n` VALUES (736, 'dictData.cdr_sip_code_cause.481', '电话无法拨出', 'Call cannot be dialed'); REPLACE INTO `sys_i18n` VALUES (737, 'dictData.cdr_sip_code_cause.482', '闪断', 'Flashback'); -REPLACE INTO `sys_i18n` VALUES (738, 'dictData.cdr_sip_code_cause.486', 'MT 用户忙', 'MT User Busy'); -REPLACE INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', 'MO 主叫挂断', 'MO User Disconnected'); +REPLACE INTO `sys_i18n` VALUES (738, 'dictData.cdr_sip_code_cause.486', '被叫用户忙', 'MT User Busy'); +REPLACE INTO `sys_i18n` VALUES (739, 'dictData.cdr_sip_code_cause.487', '主叫挂断', 'MO User Disconnected'); REPLACE INTO `sys_i18n` VALUES (740, 'dictData.cdr_sip_code_cause.408', '服务器等待响应的时间过长', 'The server waits too long for a response'); REPLACE INTO `sys_i18n` VALUES (741, 'dictData.cdr_sip_code_cause.488', '媒体详细信息与服务器支持的内容不匹配', 'Media details didn’t match what the server supports'); REPLACE INTO `sys_i18n` VALUES (742, 'dictData.cdr_sip_code_cause.489', '因其他原因呼叫失败', 'Call failure for other reason'); @@ -758,7 +758,7 @@ REPLACE INTO `sys_i18n` VALUES (743, 'dictData.cdr_sip_code_cause.500', '服务 REPLACE INTO `sys_i18n` VALUES (744, 'dictData.cdr_sip_code_cause.503', '服务器超载或因维护而停机,无法处理呼叫', 'The server is overloaded or down for maintenance and can it process the call'); REPLACE INTO `sys_i18n` VALUES (745, 'dictData.cdr_sip_code_cause.504', '服务器尝试以您的名义与另一台服务器通信,但未及时收到回复,并超时了', 'The server tried to talk to another server on your behalf, didn’t get a reply in time, and timed out'); REPLACE INTO `sys_i18n` VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其他原因呼叫失败', 'Call failure for other reason'); -REPLACE INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 被叫拒绝', 'MT explicitly rejected the call'); +REPLACE INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', '被叫拒接', 'MT explicitly rejected the call'); REPLACE INTO `sys_i18n` VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); REPLACE INTO `sys_i18n` VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); REPLACE INTO `sys_i18n` VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); From 6f30d998f383c099c94c49c27aaf17efa4e40cf7 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 24 Jul 2025 14:20:32 +0800 Subject: [PATCH 43/80] =?UTF-8?q?fix:=20=E8=87=AA=E6=A3=80=E4=BA=A7?= =?UTF-8?q?=E7=94=9F=E7=9A=84=E5=91=8A=E8=AD=A6=E8=BE=85=E5=8A=A9=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E5=AD=97=E7=AC=A6=E9=87=8D=E5=A4=8D=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go | 9 +++++---- .../ne_alarm_state_check_license.go | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go b/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go index 2d7fc89e..12dc40ae 100644 --- a/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go +++ b/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go @@ -142,10 +142,11 @@ func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) { if err == nil { continue } - if params.AddInfo != "" { - params.AddInfo = params.AddInfo + ", " + err.Error() + addInfo := params.AddInfo + if addInfo != "" { + addInfo = addInfo + ", " + err.Error() } else { - params.AddInfo = err.Error() + addInfo = err.Error() } // 事件产生时间 @@ -164,7 +165,7 @@ func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) { AlarmStatus: oam.ALARM_STATUS_ACTIVE, // 告警状态 SpecificProblem: params.SpecificProblem, // 告警问题原因 SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID - AddInfo: params.AddInfo, // 告警辅助信息 + AddInfo: addInfo, // 告警辅助信息 LocationInfo: "NE CPU/Menory/Disk: Heartbeat", // 告警定位信息 } if err = oamService.NewAlarm.Resolve(alarm); err == nil { diff --git a/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go b/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go index a5ae5411..8e866a05 100644 --- a/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go +++ b/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go @@ -80,10 +80,11 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) { if err == nil { continue } - if params.AddInfo != "" { - params.AddInfo = params.AddInfo + ", " + err.Error() + addInfo := params.AddInfo + if addInfo != "" { + addInfo = addInfo + ", " + err.Error() } else { - params.AddInfo = err.Error() + addInfo = err.Error() } // 告警ID @@ -100,7 +101,7 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) { AlarmStatus: oam.ALARM_STATUS_ACTIVE, // 告警状态 SpecificProblem: params.SpecificProblem, // 告警问题原因 SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID - AddInfo: params.AddInfo, // 告警辅助信息 + AddInfo: addInfo, // 告警辅助信息 LocationInfo: "NE License: Heartbeat", // 告警定位信息 } if err = oamService.NewAlarm.Resolve(alarm); err == nil { From 77f6693fcf977234ee8e877749754d6e7d23a0c9 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 25 Jul 2025 15:13:50 +0800 Subject: [PATCH 44/80] =?UTF-8?q?style:=20=E5=87=8F=E5=B0=91=E4=B8=8A?= =?UTF-8?q?=E6=8A=A5=E6=95=B0=E6=8D=AE=E4=B8=8D=E8=BF=9B=E8=A1=8C=E8=AD=A6?= =?UTF-8?q?=E5=91=8A=E7=B1=BB=E5=9E=8B=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/service/alarm.go | 9 --------- src/modules/oam/service/cdr.go | 2 -- src/modules/oam/service/kpi.go | 4 ---- src/modules/oam/service/nb_state.go | 2 -- src/modules/oam/service/ue_nb.go | 2 -- 5 files changed, 19 deletions(-) diff --git a/src/modules/oam/service/alarm.go b/src/modules/oam/service/alarm.go index bea08860..33d8cbe9 100644 --- a/src/modules/oam/service/alarm.go +++ b/src/modules/oam/service/alarm.go @@ -5,7 +5,6 @@ import ( "be.ems/src/framework/config" "be.ems/src/framework/constants" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/parse" "github.com/tsmask/go-oam" @@ -44,7 +43,6 @@ func (s *Alarm) Resolve(a oam.Alarm) error { // 是否存在网元 neInfo := s.neInfoService.FindByRmuid(a.NeUid) if neInfo.NeType == "" || neInfo.RmUID != a.NeUid { - logger.Warnf("resolve alarm network element does not exist %s", a.NeUid) return fmt.Errorf("resolve alarm network element does not exist %s", a.NeUid) } @@ -80,12 +78,10 @@ func (s *Alarm) Resolve(a oam.Alarm) error { if a.AlarmStatus == oam.ALARM_STATUS_CLEAR { if a.PerceivedSeverity == oam.ALARM_SEVERITY_EVENT { if err := s.clearEvent(); err != nil { - logger.Warnf("resolve alarm clear event failed: %s", err.Error()) return err } } else { if err := s.clear(); err != nil { - logger.Warnf("resolve alarm clear failed: %s", err.Error()) return err } } @@ -95,12 +91,10 @@ func (s *Alarm) Resolve(a oam.Alarm) error { if a.AlarmStatus == oam.ALARM_STATUS_ACTIVE { if a.PerceivedSeverity == oam.ALARM_SEVERITY_EVENT { if err := s.addEvent(); err != nil { - logger.Warnf("resolve alarm add event failed: %s", err.Error()) return err } } else { if err := s.add(); err != nil { - logger.Warnf("resolve alarm add failed: %s", err.Error()) return err } } @@ -108,7 +102,6 @@ func (s *Alarm) Resolve(a oam.Alarm) error { // 记录日志 if err := s.saveLog(); err != nil { - logger.Warnf("resolve alarm save log failed: %s", err.Error()) return err } // 推送 @@ -265,7 +258,6 @@ func (s *Alarm) notify(neIp string) { emailErr := notificationService.EmailAlarm(s.alarm, neIp) if emailErr != nil { emailResult = emailErr.Error() - logger.Warnf("alarm notify email failed: %s", emailErr.Error()) } s.notifyLog("EMAIL", emailList, emailResult) } @@ -278,7 +270,6 @@ func (s *Alarm) notify(neIp string) { smscErr := notificationService.SMSCAlarm(s.alarm, neIp) if smscErr != nil { smscResult = smscErr.Error() - logger.Warnf("alarm notify email failed: %s", smscErr.Error()) } s.notifyLog("SMSC", mobileList, smscResult) } diff --git a/src/modules/oam/service/cdr.go b/src/modules/oam/service/cdr.go index 7173087d..8b1e2427 100644 --- a/src/modules/oam/service/cdr.go +++ b/src/modules/oam/service/cdr.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" - "be.ems/src/framework/logger" "github.com/tsmask/go-oam" neDataModel "be.ems/src/modules/network_data/model" @@ -35,7 +34,6 @@ func (s *CDR) Resolve(c oam.CDR) error { // 是否存在网元 neInfo := s.neInfoService.FindByRmuid(c.NeUid) if neInfo.NeType == "" || neInfo.RmUID != c.NeUid { - logger.Warnf("resolve cdr network element does not exist %s", c.NeUid) return fmt.Errorf("resolve cdr network element does not exist %s", c.NeUid) } diff --git a/src/modules/oam/service/kpi.go b/src/modules/oam/service/kpi.go index 832f4c7d..3a3766bf 100644 --- a/src/modules/oam/service/kpi.go +++ b/src/modules/oam/service/kpi.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/expr" "be.ems/src/framework/utils/parse" @@ -43,7 +42,6 @@ func (s *KPI) Resolve(k oam.KPI) error { // 是否存在网元 s.neInfo = s.neInfoService.FindByRmuid(k.NeUid) if s.neInfo.NeType == "" || s.neInfo.RmUID != k.NeUid { - logger.Warnf("resolve kpi network element does not exist %s", k.NeUid) return fmt.Errorf("resolve kpi network element does not exist %s", k.NeUid) } @@ -53,11 +51,9 @@ func (s *KPI) Resolve(k oam.KPI) error { index := int64(curSeconds) / k.Granularity if err := s.saveKPIData(k, index); err != nil { - logger.Warnf("resolve kpi data fail %s", k.NeUid) return err } if err := s.saveKPIDataC(k, index); err != nil { - logger.Warnf("resolve kpic data fail %s", k.NeUid) return err } return nil diff --git a/src/modules/oam/service/nb_state.go b/src/modules/oam/service/nb_state.go index bc283a54..3f85a49f 100644 --- a/src/modules/oam/service/nb_state.go +++ b/src/modules/oam/service/nb_state.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/date" "github.com/tsmask/go-oam" @@ -33,7 +32,6 @@ func (s *NBState) Resolve(n oam.NBState) error { // 是否存在网元 neInfo := s.neInfoService.FindByRmuid(n.NeUid) if neInfo.NeType == "" || neInfo.RmUID != n.NeUid { - logger.Warnf("resolve nb_state network element does not exist %s", n.NeUid) return fmt.Errorf("resolve nb_state network element does not exist %s", n.NeUid) } diff --git a/src/modules/oam/service/ue_nb.go b/src/modules/oam/service/ue_nb.go index 5a419049..55904013 100644 --- a/src/modules/oam/service/ue_nb.go +++ b/src/modules/oam/service/ue_nb.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" - "be.ems/src/framework/logger" "github.com/tsmask/go-oam" neDataModel "be.ems/src/modules/network_data/model" @@ -32,7 +31,6 @@ func (s *UENB) Resolve(u oam.UENB) error { // 是否存在网元 neInfo := s.neInfoService.FindByRmuid(u.NeUid) if neInfo.NeType == "" || neInfo.RmUID != u.NeUid { - logger.Warnf("resolve ue_nb network element does not exist %s", u.NeUid) return fmt.Errorf("resolve ue_nb network element does not exist %s", u.NeUid) } From 47855304950742dc26cae9b63fde70ec046bd8fe Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 25 Jul 2025 20:39:36 +0800 Subject: [PATCH 45/80] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2507.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c7c8bba..bc089bce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # 版本发布日志 +## 2.2507.3-20250725 + +- 优化 减少上报数据不进行警告类型日志记录 +- 优化 自检产生的告警辅助信息字符重复追加 +- 修复 告警同步返回状态为正常,过程错误信息返回到响应 +- 更新 IMS-CDR结果码说明,告警导出表格标题编码翻译补充 +- 修复 自定义指标数据统计不处理小数,计算小于0就强制为0 +- 修复 告警级别判断成类型导致事件存储到告警中 +- 修复 网管状态信息返回nil字符修改,信息返回版本号 + ## 2.2507.2-20250718 - 移除 iperf安装包,features、lib和sshsvc目录 From 2c1e55bd0cf20310f16a31fb871d0a092d820ae8 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 28 Jul 2025 17:16:48 +0800 Subject: [PATCH 46/80] =?UTF-8?q?fix:=20=E5=AF=86=E7=A0=81=E5=BC=BA?= =?UTF-8?q?=E5=88=B6=E4=BF=AE=E6=94=B9=E9=9D=9E=E9=A6=96=E6=AC=A1=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=A0=A1=E9=AA=8C=E5=8E=BB=E9=99=A4=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E5=88=A4=E6=96=AD=EF=BC=8C=E8=A1=A5=E5=85=85=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E8=AF=B4=E6=98=8E=E7=BF=BB=E8=AF=91=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 1 + build/database/lite/upgrade/upg_sys_i18n.sql | 1 + build/database/std/install/sys_i18n.sql | 1 + build/database/std/upgrade/upg_sys_i18n.sql | 1 + src/modules/system/controller/sys_profile.go | 22 ++++++++++---------- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index 538f12ff..c2207969 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -931,3 +931,4 @@ dayLt: Days less than, default 30 days'); 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."); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index e11b4272..126a3ffc 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -930,3 +930,4 @@ dayLt: Days less than, default 30 days'); 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."); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 4e84a680..83045948 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -773,5 +773,6 @@ INSERT INTO `sys_i18n` VALUES (755, 'job.ne_alarm_state_check_license_remark', ' 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."); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index f89bccb3..ef55f345 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -770,5 +770,6 @@ REPLACE INTO `sys_i18n` VALUES (755, 'job.ne_alarm_state_check_license_remark', 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."); -- Dump completed on 2025-02-14 15:26:56 diff --git a/src/modules/system/controller/sys_profile.go b/src/modules/system/controller/sys_profile.go index 659fcf08..6dfbd9b2 100644 --- a/src/modules/system/controller/sys_profile.go +++ b/src/modules/system/controller/sys_profile.go @@ -290,17 +290,17 @@ func (s *SysProfileController) PasswordForce(c *gin.Context) { return } - // 首次登录 - forcePasswdChange := userInfo.LoginCount <= 2 - // 非首次登录,判断密码是否过期 - if !forcePasswdChange { - alert, _ := s.sysUserService.ValidatePasswordExpireTime(userInfo.PasswordUpdateTime) - forcePasswdChange = alert - } - if !forcePasswdChange { - c.JSON(403, resp.ErrMsg("not matching the amendment")) - return - } + // // 首次登录 + // forcePasswdChange := userInfo.LoginCount <= 2 + // // 非首次登录,判断密码是否过期 + // if !forcePasswdChange { + // alert, _ := s.sysUserService.ValidatePasswordExpireTime(userInfo.PasswordUpdateTime) + // forcePasswdChange = alert + // } + // if !forcePasswdChange { + // c.JSON(403, resp.ErrMsg("not matching the amendment")) + // return + // } // 检查密码是否与历史密码一致 err = s.sysUserService.ValidatePasswordNotAllowedHistory(userInfo.UserId, body.Password) From 1b4cb6399e68d6e34fd0f69cd0847632e472b485 Mon Sep 17 00:00:00 2001 From: zhangsz Date: Fri, 1 Aug 2025 14:50:55 +0800 Subject: [PATCH 47/80] feat: support CBC broadcast --- build/database/std/install/cbc_message.sql | 38 ++ build/database/std/install/sys_i18n.sql | 19 + build/database/std/install/sys_menu.sql | 2 + build/database/std/install/sys_role_menu.sql | 2 + .../database/std/upgrade/upg_cbc_message.sql | 37 ++ build/database/std/upgrade/upg_sys_i18n.sql | 19 + build/database/std/upgrade/upg_sys_menu.sql | 2 + .../std/upgrade/upg_sys_role_menu.sql | 2 + src/modules/network_data/controller/cbc.go | 316 ++++++++++++ src/modules/network_data/model/cbc_message.go | 112 +++++ src/modules/network_data/network_data.go | 38 ++ .../network_data/repository/cbc_message.go | 254 ++++++++++ .../network_data/service/cbc_message.go | 453 ++++++++++++++++++ src/modules/oam/controller/api_rest.go | 24 + src/modules/oam/oam.go | 1 + src/modules/oam/service/cbs_state.go | 29 ++ 16 files changed, 1348 insertions(+) create mode 100755 build/database/std/install/cbc_message.sql create mode 100755 build/database/std/upgrade/upg_cbc_message.sql create mode 100644 src/modules/network_data/controller/cbc.go create mode 100644 src/modules/network_data/model/cbc_message.go create mode 100644 src/modules/network_data/repository/cbc_message.go create mode 100644 src/modules/network_data/service/cbc_message.go create mode 100644 src/modules/oam/service/cbs_state.go diff --git a/build/database/std/install/cbc_message.sql b/build/database/std/install/cbc_message.sql new file mode 100755 index 00000000..59910b5a --- /dev/null +++ b/build/database/std/install/cbc_message.sql @@ -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; diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 83045948..04c356ff 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -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 diff --git a/build/database/std/install/sys_menu.sql b/build/database/std/install/sys_menu.sql index c5025ce0..f6d8f08b 100644 --- a/build/database/std/install/sys_menu.sql +++ b/build/database/std/install/sys_menu.sql @@ -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 diff --git a/build/database/std/install/sys_role_menu.sql b/build/database/std/install/sys_role_menu.sql index 62a310de..099ecc5f 100644 --- a/build/database/std/install/sys_role_menu.sql +++ b/build/database/std/install/sys_role_menu.sql @@ -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); diff --git a/build/database/std/upgrade/upg_cbc_message.sql b/build/database/std/upgrade/upg_cbc_message.sql new file mode 100755 index 00000000..281c7bcb --- /dev/null +++ b/build/database/std/upgrade/upg_cbc_message.sql @@ -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; diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index ef55f345..105bd632 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -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 diff --git a/build/database/std/upgrade/upg_sys_menu.sql b/build/database/std/upgrade/upg_sys_menu.sql index 555014cc..352bccca 100644 --- a/build/database/std/upgrade/upg_sys_menu.sql +++ b/build/database/std/upgrade/upg_sys_menu.sql @@ -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 diff --git a/build/database/std/upgrade/upg_sys_role_menu.sql b/build/database/std/upgrade/upg_sys_role_menu.sql index d8e3385b..87e16b35 100644 --- a/build/database/std/upgrade/upg_sys_role_menu.sql +++ b/build/database/std/upgrade/upg_sys_role_menu.sql @@ -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); diff --git a/src/modules/network_data/controller/cbc.go b/src/modules/network_data/controller/cbc.go new file mode 100644 index 00000000..a5935875 --- /dev/null +++ b/src/modules/network_data/controller/cbc.go @@ -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) +} diff --git a/src/modules/network_data/model/cbc_message.go b/src/modules/network_data/model/cbc_message.go new file mode 100644 index 00000000..fb7f75a3 --- /dev/null +++ b/src/modules/network_data/model/cbc_message.go @@ -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 +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 0cbb2fe3..e41d1683 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -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 初始参数 diff --git a/src/modules/network_data/repository/cbc_message.go b/src/modules/network_data/repository/cbc_message.go new file mode 100644 index 00000000..b9d140d3 --- /dev/null +++ b/src/modules/network_data/repository/cbc_message.go @@ -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 +} diff --git a/src/modules/network_data/service/cbc_message.go b/src/modules/network_data/service/cbc_message.go new file mode 100644 index 00000000..8062e256 --- /dev/null +++ b/src/modules/network_data/service/cbc_message.go @@ -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) +} diff --git a/src/modules/oam/controller/api_rest.go b/src/modules/oam/controller/api_rest.go index 955ad745..cfcd2822 100644 --- a/src/modules/oam/controller/api_rest.go +++ b/src/modules/oam/controller/api_rest.go @@ -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)) +} diff --git a/src/modules/oam/oam.go b/src/modules/oam/oam.go index fa4cac0b..54dd3a68 100644 --- a/src/modules/oam/oam.go +++ b/src/modules/oam/oam.go @@ -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) diff --git a/src/modules/oam/service/cbs_state.go b/src/modules/oam/service/cbs_state.go new file mode 100644 index 00000000..3b898621 --- /dev/null +++ b/src/modules/oam/service/cbs_state.go @@ -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) +} From 0ee3af118776619e6692dfcec9ab7c597e7c4ec9 Mon Sep 17 00:00:00 2001 From: zhangsz Date: Fri, 1 Aug 2025 15:11:38 +0800 Subject: [PATCH 48/80] feat: sql list support cbc broadcast --- build/database/lite/install/cbc_message.sql | 21 +++++++++++++++++++ build/database/lite/install/sys_i18n.sql | 19 +++++++++++++++++ build/database/lite/install/sys_menu.sql | 2 ++ build/database/lite/install/sys_role_menu.sql | 2 ++ .../database/lite/upgrade/upg_cbc_message.sql | 17 +++++++++++++++ build/database/lite/upgrade/upg_sys_i18n.sql | 19 +++++++++++++++++ build/database/lite/upgrade/upg_sys_menu.sql | 2 ++ .../lite/upgrade/upg_sys_role_menu.sql | 2 ++ 8 files changed, 84 insertions(+) create mode 100755 build/database/lite/install/cbc_message.sql create mode 100755 build/database/lite/upgrade/upg_cbc_message.sql diff --git a/build/database/lite/install/cbc_message.sql b/build/database/lite/install/cbc_message.sql new file mode 100755 index 00000000..ed4627d9 --- /dev/null +++ b/build/database/lite/install/cbc_message.sql @@ -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`); diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index c2207969..dd3cfd40 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -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'); diff --git a/build/database/lite/install/sys_menu.sql b/build/database/lite/install/sys_menu.sql index 1bf7da58..8e2edf52 100644 --- a/build/database/lite/install/sys_menu.sql +++ b/build/database/lite/install/sys_menu.sql @@ -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, ''); diff --git a/build/database/lite/install/sys_role_menu.sql b/build/database/lite/install/sys_role_menu.sql index a73b884f..e07988e4 100644 --- a/build/database/lite/install/sys_role_menu.sql +++ b/build/database/lite/install/sys_role_menu.sql @@ -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); diff --git a/build/database/lite/upgrade/upg_cbc_message.sql b/build/database/lite/upgrade/upg_cbc_message.sql new file mode 100755 index 00000000..1c24d946 --- /dev/null +++ b/build/database/lite/upgrade/upg_cbc_message.sql @@ -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`); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index 126a3ffc..c2162aaf 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -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'); diff --git a/build/database/lite/upgrade/upg_sys_menu.sql b/build/database/lite/upgrade/upg_sys_menu.sql index d5c28e75..85959b21 100644 --- a/build/database/lite/upgrade/upg_sys_menu.sql +++ b/build/database/lite/upgrade/upg_sys_menu.sql @@ -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, ''); diff --git a/build/database/lite/upgrade/upg_sys_role_menu.sql b/build/database/lite/upgrade/upg_sys_role_menu.sql index 20cc5770..29090ef4 100644 --- a/build/database/lite/upgrade/upg_sys_role_menu.sql +++ b/build/database/lite/upgrade/upg_sys_role_menu.sql @@ -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); From e4f52c949eb5ab69b3fa7cf0a050e5052acd62cc Mon Sep 17 00:00:00 2001 From: zhangsz Date: Fri, 1 Aug 2025 15:12:37 +0800 Subject: [PATCH 49/80] fix: project change --- .gitignore | 4 ++++ go.sum | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/.gitignore b/.gitignore index 77a77087..c38e16c7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,10 @@ *.bak *.bak* *.exe +__debug_bin* +debug/ +*.log.* +main # Build Output local/omc_db.sqlite diff --git a/go.sum b/go.sum index 4c3e693e..9fb14a58 100644 --- a/go.sum +++ b/go.sum @@ -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= From de0b81ee01f735d0a79103ee53c79b3790a2dce2 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 1 Aug 2025 16:29:28 +0800 Subject: [PATCH 50/80] =?UTF-8?q?fix:=20cbc=E6=97=B6=E9=97=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=BB=9F=E4=B8=80=E6=AF=AB=E7=A7=92=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/cbc_message.sql | 2 +- build/database/std/install/cbc_message.sql | 2 +- go.mod | 11 ++--- go.sum | 43 ++++--------------- src/modules/network_data/controller/cbc.go | 5 ++- src/modules/network_data/model/cbc_message.go | 16 +++---- .../network_data/repository/cbc_message.go | 11 ++--- .../network_data/service/cbc_message.go | 4 +- 8 files changed, 35 insertions(+), 59 deletions(-) diff --git a/build/database/lite/install/cbc_message.sql b/build/database/lite/install/cbc_message.sql index ed4627d9..4f6d38c6 100755 --- a/build/database/lite/install/cbc_message.sql +++ b/build/database/lite/install/cbc_message.sql @@ -12,7 +12,7 @@ CREATE TABLE `cbc_message` ( `message_json` TEXT, `status` TEXT DEFAULT 'INACTIVE' CHECK(`status` IN ('ACTIVE', 'INACTIVE')), `detail` TEXT, - `created_at` INTEGER DEFAULT (strftime('%s', 'now') * 1000000), + `created_at` INTEGER, `updated_at` INTEGER ); diff --git a/build/database/std/install/cbc_message.sql b/build/database/std/install/cbc_message.sql index 59910b5a..8eae21f5 100755 --- a/build/database/std/install/cbc_message.sql +++ b/build/database/std/install/cbc_message.sql @@ -28,7 +28,7 @@ CREATE TABLE `cbc_message` ( `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(), + `created_at` bigint(20) NULL DEFAULT NULL, `updated_at` bigint(20) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `id`(`id`) USING BTREE, diff --git a/go.mod b/go.mod index 6433b78d..000c9eb6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module be.ems -go 1.24.0 +go 1.24 require ( github.com/creack/pty v1.1.24 @@ -9,7 +9,7 @@ require ( github.com/gin-gonic/gin v1.10.1 github.com/glebarez/sqlite v1.11.0 github.com/godoes/ginprom v0.3.7 - github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/golang-jwt/jwt/v5 v5.3.0 github.com/gopacket/gopacket v1.3.1 github.com/gorilla/websocket v1.5.3 github.com/linxGnu/gosmpp v0.3.1 @@ -22,12 +22,12 @@ require ( github.com/redis/go-redis/v9 v9.11.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil/v4 v4.25.6 - github.com/spf13/pflag v1.0.6 + github.com/spf13/pflag v1.0.7 github.com/spf13/viper v1.20.1 github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 - github.com/swaggo/swag v1.16.4 - github.com/tsmask/go-oam v1.0.4 + github.com/swaggo/swag v1.16.6 + github.com/tsmask/go-oam v1.0.7 github.com/wneessen/go-mail v0.6.2 github.com/xuri/excelize/v2 v2.9.0 golang.org/x/crypto v0.40.0 @@ -108,6 +108,7 @@ require ( golang.org/x/arch v0.16.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/image v0.26.0 // indirect + golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect diff --git a/go.sum b/go.sum index 9fb14a58..09da69e9 100644 --- a/go.sum +++ b/go.sum @@ -2,11 +2,6 @@ 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= @@ -22,11 +17,9 @@ 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= @@ -85,11 +78,10 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godoes/ginprom v0.3.7 h1:HlKZhp2qS23YPpBWrP1K1+XZQFVruC6leUqkm/1ImFE= github.com/godoes/ginprom v0.3.7/go.mod h1:U6qRPc3I1sFtgbMDrnea4sDNYcc47b5e/ZHtCW3KFtY= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= 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= @@ -108,11 +100,8 @@ 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= @@ -139,7 +128,6 @@ 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= @@ -153,7 +141,6 @@ 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= @@ -193,20 +180,18 @@ 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= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -225,26 +210,24 @@ github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= -github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= -github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= +github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= +github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= -github.com/tsmask/go-oam v1.0.4 h1:Q3sV8paXweQweLUJ4uDyO9Pn9TjElWjeWd6cfVOFgNw= -github.com/tsmask/go-oam v1.0.4/go.mod h1:HqFtN0LA9BiR1HWyHO++DY0fyYTl2sKVnRrZzuWy9n4= +github.com/tsmask/go-oam v1.0.7 h1:muMa7oL3QKljCYf4aXbaIM9Qydn59TFSeswi4LqT24o= +github.com/tsmask/go-oam v1.0.7/go.mod h1:HqFtN0LA9BiR1HWyHO++DY0fyYTl2sKVnRrZzuWy9n4= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 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= @@ -254,7 +237,6 @@ 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= @@ -291,7 +273,6 @@ 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= @@ -321,7 +302,6 @@ 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= @@ -354,13 +334,11 @@ 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= @@ -368,11 +346,8 @@ 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= @@ -396,5 +371,3 @@ 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= diff --git a/src/modules/network_data/controller/cbc.go b/src/modules/network_data/controller/cbc.go index a5935875..52093c77 100644 --- a/src/modules/network_data/controller/cbc.go +++ b/src/modules/network_data/controller/cbc.go @@ -93,8 +93,9 @@ func (m *CBCController) Insert(c *gin.Context) { c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - msg.CreatedAt = time.Now().Local().UnixMicro() - msg.UpdatedAt = nil // 新增时更新时间为nil + now := time.Now().UnixMilli() + msg.CreatedAt = now + msg.UpdatedAt = now // 使用 ShouldBindBodyWithJSON 读取请求体 var jsonData interface{} diff --git a/src/modules/network_data/model/cbc_message.go b/src/modules/network_data/model/cbc_message.go index fb7f75a3..37470209 100644 --- a/src/modules/network_data/model/cbc_message.go +++ b/src/modules/network_data/model/cbc_message.go @@ -71,14 +71,14 @@ type CBCMessageQuery struct { // @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"` // 更新时间 + 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"` // 更新时间 } // TableName 表名称 diff --git a/src/modules/network_data/repository/cbc_message.go b/src/modules/network_data/repository/cbc_message.go index b9d140d3..f7d246a4 100644 --- a/src/modules/network_data/repository/cbc_message.go +++ b/src/modules/network_data/repository/cbc_message.go @@ -109,6 +109,7 @@ func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessa // @example // CBCMessage.InsertCBCMessage(msg) func (s *CBCMessage) Insert(msg model.CBCMessage) error { + msg.CreatedAt = time.Now().UnixMilli() // 这里可以使用ORM或其他方式将ticket插入到数据库中 if err := db.DB("").Table("cbc_message").Create(&msg).Error; err != nil { return fmt.Errorf("failed to insert CBC message: %w", err) @@ -157,10 +158,10 @@ func (s *CBCMessage) SelectByEventName(eventName string) (*model.CBCMessage, err // @example // mfCBCMessageService.UpdateCBCMessage(msg) func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error { - now := time.Now().UnixMicro() + now := time.Now().UnixMilli() if err := db.DB("").Table("cbc_message"). Where("id = ?", id). - Updates(map[string]interface{}{ + Updates(map[string]any{ "message_json": messageJson, "updated_at": now, }).Error; err != nil { @@ -177,7 +178,7 @@ func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error { // @example // UpdateCBCMessageDetail(msg) func (s *CBCMessage) UpdateDetail(eventName, detail string) error { - now := time.Now().UnixMicro() + now := time.Now().UnixMilli() if err := db.DB("").Table("cbc_message"). Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName). Updates(map[string]any{ @@ -212,7 +213,7 @@ func (s *CBCMessage) Delete(id int64) error { // @return error 错误信息 func (s *CBCMessage) UpdateStatus(id int64, status model.CBCEventStatus) error { // 更新数据库状态 - now := time.Now().UnixMicro() + now := time.Now().UnixMilli() if err := db.DB("").Table("cbc_message"). Where("id = ?", id). Updates(map[string]interface{}{ @@ -250,5 +251,5 @@ func parseTimeToMicro(ts string) (int64, error) { if err != nil { return 0, err } - return t.UnixMicro(), nil + return t.UnixMilli(), nil } diff --git a/src/modules/network_data/service/cbc_message.go b/src/modules/network_data/service/cbc_message.go index 8062e256..378b0da5 100644 --- a/src/modules/network_data/service/cbc_message.go +++ b/src/modules/network_data/service/cbc_message.go @@ -291,8 +291,8 @@ func (r CBCMessage) ExportXlsx(rows []model.CBCMessage, fileName, language strin "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), + "F" + idx: time.UnixMilli(row.CreatedAt).Format(time.RFC3339), + "G" + idx: time.UnixMilli(row.UpdatedAt).Format(time.RFC3339), } dataCells = append(dataCells, cells) From e0fa00bc052a5ce2807ec6729a2d160e2cc1c5ce Mon Sep 17 00:00:00 2001 From: zhangsz Date: Fri, 1 Aug 2025 16:52:31 +0800 Subject: [PATCH 51/80] fix: upgrade cbc message --- .../database/lite/upgrade/upg_cbc_message.sql | 2 +- .../database/std/upgrade/upg_cbc_message.sql | 2 +- go.sum | 27 +++++++++++++++++++ .../network_data/repository/cbc_message.go | 6 ++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/build/database/lite/upgrade/upg_cbc_message.sql b/build/database/lite/upgrade/upg_cbc_message.sql index 1c24d946..251d96d5 100755 --- a/build/database/lite/upgrade/upg_cbc_message.sql +++ b/build/database/lite/upgrade/upg_cbc_message.sql @@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS `cbc_message` ( `message_json` TEXT, `status` TEXT DEFAULT 'INACTIVE' CHECK(`status` IN ('ACTIVE', 'INACTIVE')), `detail` TEXT, - `created_at` INTEGER DEFAULT (strftime('%s', 'now') * 1000000), + `created_at` INTEGER, `updated_at` INTEGER ); diff --git a/build/database/std/upgrade/upg_cbc_message.sql b/build/database/std/upgrade/upg_cbc_message.sql index 281c7bcb..88a75dca 100755 --- a/build/database/std/upgrade/upg_cbc_message.sql +++ b/build/database/std/upgrade/upg_cbc_message.sql @@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS `cbc_message` ( `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(), + `created_at` bigint(20) NULL DEFAULT NULL, `updated_at` bigint(20) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `id`(`id`) USING BTREE, diff --git a/go.sum b/go.sum index 09da69e9..816253b8 100644 --- a/go.sum +++ b/go.sum @@ -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.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9v github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= 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= diff --git a/src/modules/network_data/repository/cbc_message.go b/src/modules/network_data/repository/cbc_message.go index f7d246a4..d7c09198 100644 --- a/src/modules/network_data/repository/cbc_message.go +++ b/src/modules/network_data/repository/cbc_message.go @@ -39,13 +39,13 @@ func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessa var startMicro, endMicro int64 var err error if query.StartTime != "" { - startMicro, err = parseTimeToMicro(query.StartTime) + startMicro, err = parseTimeToMilli(query.StartTime) if err != nil { return nil, 0, fmt.Errorf("invalid start time: %w", err) } } if query.EndTime != "" { - endMicro, err = parseTimeToMicro(query.EndTime) + endMicro, err = parseTimeToMilli(query.EndTime) if err != nil { return nil, 0, fmt.Errorf("invalid end time: %w", err) } @@ -243,7 +243,7 @@ func (s *CBCMessage) SelectByNeId(neId string, msgs *[]model.CBCMessage) error { } // 假设 query.StartTime 和 query.EndTime 是 "2006-01-02 15:04:05" 格式字符串 -func parseTimeToMicro(ts string) (int64, error) { +func parseTimeToMilli(ts string) (int64, error) { if ts == "" { return 0, nil } From 37e0f0828e6817518c68fd184235ee5b82432f84 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 1 Aug 2025 17:45:18 +0800 Subject: [PATCH 52/80] =?UTF-8?q?sql:=20=E6=9B=B4=E6=96=B0=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=8F=9C=E5=8D=95=EF=BC=8C=E5=88=86=E9=85=8D=E8=AF=AD?= =?UTF-8?q?=E9=9F=B3=E6=95=B0=E6=8D=AE=E8=8F=9C=E5=8D=95=E7=BB=99admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 1 + build/database/lite/install/sys_menu.sql | 6 +++--- build/database/lite/install/sys_role_menu.sql | 1 + build/database/lite/upgrade/upg_cbc_message.sql | 2 +- build/database/lite/upgrade/upg_sys_i18n.sql | 1 + build/database/lite/upgrade/upg_sys_menu.sql | 6 +++--- build/database/lite/upgrade/upg_sys_role_menu.sql | 1 + build/database/std/install/sys_i18n.sql | 1 + build/database/std/install/sys_menu.sql | 6 +++--- build/database/std/install/sys_role_menu.sql | 1 + build/database/std/upgrade/upg_cbc_message.sql | 2 +- build/database/std/upgrade/upg_sys_i18n.sql | 1 + build/database/std/upgrade/upg_sys_menu.sql | 6 +++--- build/database/std/upgrade/upg_sys_role_menu.sql | 1 + 14 files changed, 22 insertions(+), 14 deletions(-) diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index dd3cfd40..4fd1c2d8 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -932,6 +932,7 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); INSERT INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent'); INSERT INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information'); diff --git a/build/database/lite/install/sys_menu.sql b/build/database/lite/install/sys_menu.sql index 8e2edf52..3e7e61d2 100644 --- a/build/database/lite/install/sys_menu.sql +++ b/build/database/lite/install/sys_menu.sql @@ -156,7 +156,7 @@ INSERT INTO "sys_menu" VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, INSERT INTO "sys_menu" VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2120, 'DashboardV1', 2131, 8, 'dashboardV1', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.setting.i18nRemark'); INSERT INTO "sys_menu" VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -166,13 +166,13 @@ INSERT INTO "sys_menu" VALUES (2128, 'menu.monitor.topologyArchitecture', 2130, INSERT INTO "sys_menu" VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', '0', 'D', '1', '1', '', 'icon-jinggao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2139, 'menu.perf.kpiIMSOverview', 2099, 14, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'ims#perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/lite/install/sys_role_menu.sql b/build/database/lite/install/sys_role_menu.sql index e07988e4..15dc94cf 100644 --- a/build/database/lite/install/sys_role_menu.sql +++ b/build/database/lite/install/sys_role_menu.sql @@ -129,6 +129,7 @@ INSERT INTO "sys_role_menu" VALUES (2, 2132); INSERT INTO "sys_role_menu" VALUES (2, 2133); INSERT INTO "sys_role_menu" VALUES (2, 2137); INSERT INTO "sys_role_menu" VALUES (2, 2138); +INSERT INTO "sys_role_menu" VALUES (2, 2139); INSERT INTO "sys_role_menu" VALUES (2, 2140); INSERT INTO "sys_role_menu" VALUES (2, 2141); INSERT INTO "sys_role_menu" VALUES (2, 2142); diff --git a/build/database/lite/upgrade/upg_cbc_message.sql b/build/database/lite/upgrade/upg_cbc_message.sql index 1c24d946..251d96d5 100755 --- a/build/database/lite/upgrade/upg_cbc_message.sql +++ b/build/database/lite/upgrade/upg_cbc_message.sql @@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS `cbc_message` ( `message_json` TEXT, `status` TEXT DEFAULT 'INACTIVE' CHECK(`status` IN ('ACTIVE', 'INACTIVE')), `detail` TEXT, - `created_at` INTEGER DEFAULT (strftime('%s', 'now') * 1000000), + `created_at` INTEGER, `updated_at` INTEGER ); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index c2162aaf..d3b15c6a 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -931,6 +931,7 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); REPLACE INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent'); REPLACE INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information'); diff --git a/build/database/lite/upgrade/upg_sys_menu.sql b/build/database/lite/upgrade/upg_sys_menu.sql index 85959b21..316e40dc 100644 --- a/build/database/lite/upgrade/upg_sys_menu.sql +++ b/build/database/lite/upgrade/upg_sys_menu.sql @@ -155,7 +155,7 @@ REPLACE INTO "sys_menu" VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, REPLACE INTO "sys_menu" VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -REPLACE INTO "sys_menu" VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2120, 'DashboardV1', 2131, 8, 'dashboardV1', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.setting.i18nRemark'); REPLACE INTO "sys_menu" VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -165,13 +165,13 @@ REPLACE INTO "sys_menu" VALUES (2128, 'menu.monitor.topologyArchitecture', 2130, REPLACE INTO "sys_menu" VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', '0', 'D', '1', '1', '', 'icon-jinggao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -REPLACE INTO "sys_menu" VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -REPLACE INTO "sys_menu" VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (2139, 'menu.perf.kpiIMSOverview', 2099, 14, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'ims#perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/lite/upgrade/upg_sys_role_menu.sql b/build/database/lite/upgrade/upg_sys_role_menu.sql index 29090ef4..995e7c22 100644 --- a/build/database/lite/upgrade/upg_sys_role_menu.sql +++ b/build/database/lite/upgrade/upg_sys_role_menu.sql @@ -128,6 +128,7 @@ REPLACE INTO "sys_role_menu" VALUES (2, 2132); REPLACE INTO "sys_role_menu" VALUES (2, 2133); REPLACE INTO "sys_role_menu" VALUES (2, 2137); REPLACE INTO "sys_role_menu" VALUES (2, 2138); +REPLACE INTO "sys_role_menu" VALUES (2, 2139); REPLACE INTO "sys_role_menu" VALUES (2, 2140); REPLACE INTO "sys_role_menu" VALUES (2, 2141); REPLACE INTO "sys_role_menu" VALUES (2, 2142); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 04c356ff..2000c020 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -774,6 +774,7 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); INSERT INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent'); INSERT INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information'); diff --git a/build/database/std/install/sys_menu.sql b/build/database/std/install/sys_menu.sql index f6d8f08b..869ffb04 100644 --- a/build/database/std/install/sys_menu.sql +++ b/build/database/std/install/sys_menu.sql @@ -159,7 +159,7 @@ INSERT INTO `sys_menu` VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, INSERT INTO `sys_menu` VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2120, 'DashboardV1', 2131, 8, 'dashboardV1', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.setting.i18nRemark'); INSERT INTO `sys_menu` VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -171,13 +171,13 @@ INSERT INTO `sys_menu` VALUES (2128, 'menu.monitor.topologyArchitecture', 2130, INSERT INTO `sys_menu` VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', '0', 'D', '1', '1', '', 'icon-jinggao', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2139, 'menu.perf.kpiIMSOverview', 2099, 14, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'ims#perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, ''); diff --git a/build/database/std/install/sys_role_menu.sql b/build/database/std/install/sys_role_menu.sql index 099ecc5f..c8e6b38e 100644 --- a/build/database/std/install/sys_role_menu.sql +++ b/build/database/std/install/sys_role_menu.sql @@ -135,6 +135,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2132); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2133); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2137); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2138); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2139); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2140); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2141); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2142); diff --git a/build/database/std/upgrade/upg_cbc_message.sql b/build/database/std/upgrade/upg_cbc_message.sql index 281c7bcb..88a75dca 100755 --- a/build/database/std/upgrade/upg_cbc_message.sql +++ b/build/database/std/upgrade/upg_cbc_message.sql @@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS `cbc_message` ( `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(), + `created_at` bigint(20) NULL DEFAULT NULL, `updated_at` bigint(20) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `id`(`id`) USING BTREE, diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index 105bd632..dd33ea15 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -771,6 +771,7 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); REPLACE INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent'); REPLACE INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information'); diff --git a/build/database/std/upgrade/upg_sys_menu.sql b/build/database/std/upgrade/upg_sys_menu.sql index 352bccca..10e5e0de 100644 --- a/build/database/std/upgrade/upg_sys_menu.sql +++ b/build/database/std/upgrade/upg_sys_menu.sql @@ -181,7 +181,7 @@ REPLACE INTO `sys_menu` VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, REPLACE INTO `sys_menu` VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2119, 'Alarm Overview', 2129, 6, 'alarm-overview', 'faultManage/alarm-overview/index', '1', '1', 'M', '1', '1', 'faultManage:active-overview:index', 'icon-wenjian', '0', 'system', 1728641403588,'system', 1728641403588, ''); -REPLACE INTO `sys_menu` VALUES (2120, 'Dashboard2', 2131, 8, 'dashboard2', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview2:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (2120, 'DashboardV1', 2131, 8, 'dashboardV1', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.setting.i18nRemark'); REPLACE INTO `sys_menu` VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -193,13 +193,13 @@ REPLACE INTO `sys_menu` VALUES (2128, 'menu.monitor.topologyArchitecture', 2130, REPLACE INTO `sys_menu` VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', '0', 'D', '1', '1', '', 'icon-jinggao', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588,'system', 1728641403588, ''); -REPLACE INTO `sys_menu` VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview2/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -REPLACE INTO `sys_menu` VALUES (2139, 'Key Performance Dashboard', 2099, 8, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (2139, 'menu.perf.kpiIMSOverview', 2099, 14, 'dashboard', 'perfManage/overview/index', '1', '0', 'M', '1', '1', 'ims#perfManage:dashboard:index', 'icon-fuzhichenggong', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, ''); diff --git a/build/database/std/upgrade/upg_sys_role_menu.sql b/build/database/std/upgrade/upg_sys_role_menu.sql index 87e16b35..2c9c27ac 100644 --- a/build/database/std/upgrade/upg_sys_role_menu.sql +++ b/build/database/std/upgrade/upg_sys_role_menu.sql @@ -134,6 +134,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2132); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2133); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2137); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2138); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2139); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2140); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2141); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2142); From 825988ca8ebc5786d26af889960a319a594e7a6d Mon Sep 17 00:00:00 2001 From: zhangsz Date: Fri, 1 Aug 2025 17:56:11 +0800 Subject: [PATCH 53/80] feat: support cbc message --- build/database/lite/install/sys_i18n.sql | 4 ++-- build/database/lite/upgrade/upg_sys_i18n.sql | 4 ++-- build/database/std/install/sys_i18n.sql | 4 ++-- build/database/std/upgrade/upg_sys_i18n.sql | 4 ++-- src/modules/network_data/service/cbc_message.go | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index 4fd1c2d8..95ce5ffb 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -950,5 +950,5 @@ 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'); +INSERT INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '预警广播', 'Early Warning Broadcast'); +INSERT INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index d3b15c6a..a393a9c9 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -949,5 +949,5 @@ 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'); +REPLACE INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '预警广播', 'Early Warning Broadcast'); +REPLACE INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 2000c020..e8675d6b 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -792,7 +792,7 @@ 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'); +INSERT INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '预警广播', 'Early Warning Broadcast'); +INSERT INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index dd33ea15..e1855bf5 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -789,7 +789,7 @@ 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'); +REPLACE INTO `sys_i18n` VALUES (2016, 'menu.ue.cbc.cbe', '预警广播', 'Early Warning Broadcast'); +REPLACE INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); -- Dump completed on 2025-02-14 15:26:56 diff --git a/src/modules/network_data/service/cbc_message.go b/src/modules/network_data/service/cbc_message.go index 378b0da5..1772faa7 100644 --- a/src/modules/network_data/service/cbc_message.go +++ b/src/modules/network_data/service/cbc_message.go @@ -404,7 +404,7 @@ func (s *CBCMessage) sendActivateRequest(msg model.CBCMessage) error { if err != nil { return err } - + // 直接使用 MessageJson 发送POST请求 return client.PostMessage(msg.MessageJson) } @@ -414,8 +414,8 @@ func (s *CBCMessage) sendUpdateRequest(msg model.CBCMessage) error { if err != nil { return err } - - return client.PutMessage(msg.MessageJson) + // 直接使用 MessageJson 发送POST请求 + return client.PostMessage(msg.MessageJson) } // 重构后的停用请求 From 3248591ba6e67a4a653a127e80e465400a97f67a Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 1 Aug 2025 18:19:59 +0800 Subject: [PATCH 54/80] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2507.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc089bce..daaf8d90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 版本发布日志 +## 2.2507.4-20250801 + +- 修复 密码强制修改非首次登录校验去除日期判断,补充参数说明翻译信息 +- 新增 CBC预警广播功能 +- 新增 仪表盘总览替换,语音数据概览 + ## 2.2507.3-20250725 - 优化 减少上报数据不进行警告类型日志记录 From b2652b6198d507d2a038ce9aa89c794ae74ba0c0 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 4 Aug 2025 16:13:07 +0800 Subject: [PATCH 55/80] =?UTF-8?q?sql:=20MML=E7=B1=BB=E5=9E=8Bobject=5Ftype?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=80=BCmml=E6=9B=B4=E6=96=B0General?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/common/mml_system.sql | 122 ++++++++++----------- build/database/std/common/mml_system.sql | 124 +++++++++++----------- 2 files changed, 123 insertions(+), 123 deletions(-) diff --git a/build/database/lite/common/mml_system.sql b/build/database/lite/common/mml_system.sql index 6aaf1aec..78d77ead 100644 --- a/build/database/lite/common/mml_system.sql +++ b/build/database/lite/common/mml_system.sql @@ -19,64 +19,64 @@ CREATE TABLE "mml_system" ( -- ---------------------------- -- Records of mml_system -- ---------------------------- -INSERT INTO "mml_system" VALUES (833, 'UPF', 'upfManagement', 'UPF Management', 'help', '', 'List UPF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (834, 'UPF', 'systemManagement', 'System Management', 'set', 'n3 driver', 'Set N3 Driver', 'mml', '[{"comment":"","display":"Type","filter":"","name":"type","optional":"false","type":"int"},{"comment":"","display":"IP address","filter":"","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Mask","filter":"","name":"mask","optional":"false","type":"string"},{"comment":"","display":"Mac address","filter":"","name":"mac","optional":"false","type":"string"},{"comment":"","display":"PCI address","filter":"","name":"pci","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (835, 'UPF', 'systemManagement', 'System Management', 'set', 'n4 ip', 'Set N4 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (836, 'UPF', 'systemManagement', 'System Management', 'set', 'n6 driver', 'Set N6 Driver', 'mml', '[{"comment":"","display":"Type","filter":"","name":"type","optional":"false","type":"int"},{"comment":"","display":"IP address","filter":"","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Mask","filter":"","name":"mask","optional":"false","type":"string"},{"comment":"","display":"Mac address","filter":"","name":"mac","optional":"false","type":"string"},{"comment":"","display":"PCI address","filter":"","name":"pci","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (837, 'UPF', 'systemManagement', 'System Management', 'set', 'n9 driver', 'Set N9 Driver', 'mml', '[{"comment":"","display":"Type","filter":"","name":"type","optional":"false","type":"int"},{"comment":"","display":"IP address","filter":"","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Mask","filter":"","name":"mask","optional":"false","type":"string"},{"comment":"","display":"Mac address","filter":"","name":"mac","optional":"false","type":"string"},{"comment":"","display":"PCI address","filter":"","name":"pci","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (838, 'UPF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'mml', '[{"comment":"","display":"DNN","filter":"","name":"dnn","optional":"false","type":"string"},{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (839, 'UPF', 'systemManagement', 'System Management', 'set', 'pfcp', 'Set PFCP', 'mml', '[{"comment":"","display":"Path","filter":"","name":"path","optional":"false","type":"string"},{"comment":"","display":"Local IP Address","filter":"","name":"local","optional":"false","type":"string"},{"comment":"","display":"Remote IP Address","filter":"","name":"remote","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (840, 'UPF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'mml', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"comment":"","display":"5qi","filter":"","name":"5qi","optional":"false","type":"string"},{"comment":"","display":"Priority Level","filter":"","name":"priority","optional":"false","type":"int"},{"comment":"","display":"MBR","filter":"","name":"mbr","optional":"false","type":"string"},{"comment":"","display":"GBR","filter":"","name":"gbr","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (841, 'UPF', 'systemManagement', 'System Management', 'set', 'pccrule', 'Set PCC Rule', 'mml', '[{"comment":"","display":"Index","filter":"0~65535","name":"index","optional":"false","type":"int"},{"comment":"","display":"Precedence","filter":"","name":"precedence","optional":"false","type":"int"},{"comment":"","display":"QOS Index","filter":"","name":"qosindex","optional":"false","type":"int"},{"comment":"","display":"Filter Direction","filter":"{\"0\":\"NA\", \"1\":\"Uplink\", \"2\":\"Downlink\", \"3\":\"Bidirectionallink\"}","name":"direction","optional":"true","type":"int"},{"comment":"","display":"Filter","filter":"","name":"filter","optional":"true","type":"string"},{"comment":"","display":"Application ID","filter":"","name":"appid","optional":"true","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (842, 'UPF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (843, 'UPF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO "mml_system" VALUES (853, 'SMF', 'smfManagement', 'SMF Management', 'help', '', 'List SMF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (854, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 server', 'Set N7 Server', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (855, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 client', 'Set N7 Client', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (856, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 server', 'Set N10 Server', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (857, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 client', 'Set N10 Client', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (858, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 server', 'Set N11 Server', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (859, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 client', 'Set N11 Client', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (860, 'SMF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'mml', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"int"},{"comment":"","display":"DNN","filter":"","name":"DNN","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (862, 'SMF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'mml', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"comment":"","display":"SD","filter":"","name":"5qi","optional":"false","type":"string"},{"comment":"","display":"5qipl","filter":"","name":"5qipl","optional":"false","type":"string"},{"comment":"","display":"arppl","filter":"","name":"arppl","optional":"false","type":"string"},{"comment":"","display":"arppci","filter":"","name":"arppci","optional":"false","type":"string"},{"comment":"","display":"arppvi","filter":"","name":"arppvi","optional":"false","type":"string"},{"comment":"","display":"mfbrul","filter":"","name":"mfbrul","optional":"false","type":"string"},{"comment":"","display":"mfbrdl","filter":"","name":"mfbrdl","optional":"false","type":"string"},{"comment":"","display":"gfbrul","filter":"","name":"gfbrul","optional":"false","type":"string"},{"comment":"","display":"gfbrdl","filter":"","name":"gfbrdl","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (863, 'SMF', 'systemManagement', 'System Management', 'set', 'snssai', 'Set Snssai', 'mml', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"display":"sst-sd","filter":"","name":"sst-sd","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (864, 'SMF', 'systemManagement', 'System Management', 'release', 'imsi', 'Release IMSI', 'mml', '[{"comment":"","display":"IMSI","filter":"","name":"imsi","optional":"false","type":"string"},{"display":"PDU Session Id","filter":"","name":"pduSessId","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (865, 'SMF', 'systemManagement', 'System Management', 'set', 'urr', 'Set URR', 'mml', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"comment":"","display":"Quota Volume Tatol","filter":"","name":"quotavolumetatol","optional":"false","type":"string"},{"comment":"","display":"Quota Volume UL","filter":"","name":"quotavolumeul","optional":"false","type":"string"},{"comment":"","display":"Quota Volume DL","filter":"","name":"quotavolumedl","optional":"false","type":"string"},{"comment":"","display":"Quota Time","filter":"","name":"quotatime","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (866, 'SMF', 'systemManagement', 'System Management', 'set', 'dpi', 'Set DPI', 'mml', '[{"comment":"","display":"Flag","filter":"{\"0\":\"disable\", \"1\":\"enable\"}","name":"flag","optional":"false","type":"enum"},{"comment":"","display":"Max Detect Packet Number","filter":"","name":"max","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (867, 'SMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (868, 'SMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO "mml_system" VALUES (870, 'IMS', 'imsManagement', 'IMS Management', 'help', '', 'List IMS MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (871, 'N3IWF', 'n3iwfManagement', 'N3IWF Management', 'help', '', 'List N3IWF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (872, 'NSSF', 'nssfManagement', 'NSSF Management', 'help', '', 'List NSSF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (873, 'NRF', 'nrfManagement', 'NRF Management', 'help', '', 'List NRF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (874, 'PCF', 'pcfManagement', 'PCF Management', 'help', '', 'List PCF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (875, 'AMF', 'subsManagement', 'Subscriber Management', 'list', 'imsi', 'List Online IMSI', 'mml', '[{"comment":"","display":"IMSI","filter":"32","name":"imsi","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (876, 'AMF', 'amfManagement', 'AMF Management', 'help', '', 'List AMF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (877, 'AMF', 'systemManagement', 'System Management', 'set', 'n8_ip', 'Set N8 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (878, 'AMF', 'systemManagement', 'System Management', 'set', 'n11_ip', 'Set N11 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (879, 'AMF', 'systemManagement', 'System Management', 'set', 'n12_ip', 'Set N12 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (880, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_ip', 'Set N2 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (881, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_port', 'Set N2 Port', 'mml', '[{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (882, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpversion', 'Set NTP Version', 'mml', '[{"comment":"","display":"Version","filter":"","name":"version","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (883, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpmaxdiff', 'Set NTP Max Diff', 'mml', '[{"comment":"","display":"Max Value(ms)","filter":"100~2000","name":"value","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (884, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpsynctimer', 'Set NTP Sync Timer', 'mml', '[{"comment":"","display":"Periods(second)","filter":"","name":"periods","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (885, 'AMF', 'systemManagement', 'System Management', 'add', 'slice', 'Add Slice', 'mml', '[{"comment":"","display":"SST","filter":"","name":"sst","optional":"false","type":"string"},{"comment":"","display":"SD","filter":"","name":"sd","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (886, 'AMF', 'systemManagement', 'System Management', 'deregister', 'imsi', 'Deregister IMSI', 'mml', '[{"comment":"","display":"IMSI","filter":"","name":"IMSI","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (887, 'AMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (888, 'AMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO "mml_system" VALUES (889, 'UDM', 'udmManagement', 'UDM Management', 'help', '', 'List UDM MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (890, 'UDM', 'systemManagement', 'System Management', 'set', 'n8ip', 'Set N8 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"ipv4"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (891, 'UDM', 'systemManagement', 'System Management', 'set', 'n8port', 'Set N8 Port', 'mml', '[{"comment":"","display":"Port","filter":"1~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (892, 'UDM', 'systemManagement', 'System Management', 'set', 'n8scheme', 'Set N8 Scheme', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (893, 'UDM', 'systemManagement', 'System Management', 'set', 'n10ip', 'Set N10 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (894, 'UDM', 'systemManagement', 'System Management', 'set', 'n10port', 'Set N10 Port', 'mml', '[{"comment":"","display":"Port","filter":"1~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (895, 'UDM', 'systemManagement', 'System Management', 'set', 'n10scheme', 'Set N10 Scheme', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (896, 'UDM', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (897, 'UDM', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO "mml_system" VALUES (898, 'AUSF', 'ausfManagement', 'AUSF Management', 'help', '', 'List AUSF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO "mml_system" VALUES (899, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12ip', 'Set N12 IP Address', 'mml', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (900, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12port', 'Set N12 Port', 'mml', '[{"comment":"","display":"Port","filter":"1~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (901, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12scheme', 'Set N12 Scheme', 'mml', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (902, 'AUSF', 'systemManagement', 'System Management', 'set', 'supirange', 'Set SUPI Range', 'mml', '[{"comment":"","display":"SUPI Range","filter":"","name":"supirange","optional":"false","type":"string"}]', 'Inactive'); -INSERT INTO "mml_system" VALUES (903, 'AUSF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO "mml_system" VALUES (904, 'MME', 'mmeManagement', 'MME Management', 'help', '', 'List MME MML CMD', 'mml', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (833, 'UPF', 'upfManagement', 'UPF Management', 'help', '', 'List UPF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (834, 'UPF', 'systemManagement', 'System Management', 'set', 'n3 driver', 'Set N3 Driver', 'General', '[{"comment":"","display":"Type","filter":"","name":"type","optional":"false","type":"int"},{"comment":"","display":"IP address","filter":"","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Mask","filter":"","name":"mask","optional":"false","type":"string"},{"comment":"","display":"Mac address","filter":"","name":"mac","optional":"false","type":"string"},{"comment":"","display":"PCI address","filter":"","name":"pci","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (835, 'UPF', 'systemManagement', 'System Management', 'set', 'n4 ip', 'Set N4 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (836, 'UPF', 'systemManagement', 'System Management', 'set', 'n6 driver', 'Set N6 Driver', 'General', '[{"comment":"","display":"Type","filter":"","name":"type","optional":"false","type":"int"},{"comment":"","display":"IP address","filter":"","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Mask","filter":"","name":"mask","optional":"false","type":"string"},{"comment":"","display":"Mac address","filter":"","name":"mac","optional":"false","type":"string"},{"comment":"","display":"PCI address","filter":"","name":"pci","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (837, 'UPF', 'systemManagement', 'System Management', 'set', 'n9 driver', 'Set N9 Driver', 'General', '[{"comment":"","display":"Type","filter":"","name":"type","optional":"false","type":"int"},{"comment":"","display":"IP address","filter":"","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Mask","filter":"","name":"mask","optional":"false","type":"string"},{"comment":"","display":"Mac address","filter":"","name":"mac","optional":"false","type":"string"},{"comment":"","display":"PCI address","filter":"","name":"pci","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (838, 'UPF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'General', '[{"comment":"","display":"DNN","filter":"","name":"dnn","optional":"false","type":"string"},{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (839, 'UPF', 'systemManagement', 'System Management', 'set', 'pfcp', 'Set PFCP', 'General', '[{"comment":"","display":"Path","filter":"","name":"path","optional":"false","type":"string"},{"comment":"","display":"Local IP Address","filter":"","name":"local","optional":"false","type":"string"},{"comment":"","display":"Remote IP Address","filter":"","name":"remote","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (840, 'UPF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'General', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"comment":"","display":"5qi","filter":"","name":"5qi","optional":"false","type":"string"},{"comment":"","display":"Priority Level","filter":"","name":"priority","optional":"false","type":"int"},{"comment":"","display":"MBR","filter":"","name":"mbr","optional":"false","type":"string"},{"comment":"","display":"GBR","filter":"","name":"gbr","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (841, 'UPF', 'systemManagement', 'System Management', 'set', 'pccrule', 'Set PCC Rule', 'General', '[{"comment":"","display":"Index","filter":"0~65535","name":"index","optional":"false","type":"int"},{"comment":"","display":"Precedence","filter":"","name":"precedence","optional":"false","type":"int"},{"comment":"","display":"QOS Index","filter":"","name":"qosindex","optional":"false","type":"int"},{"comment":"","display":"Filter Direction","filter":"{\"0\":\"NA\", \"1\":\"Uplink\", \"2\":\"Downlink\", \"3\":\"Bidirectionallink\"}","name":"direction","optional":"true","type":"int"},{"comment":"","display":"Filter","filter":"","name":"filter","optional":"true","type":"string"},{"comment":"","display":"Application ID","filter":"","name":"appid","optional":"true","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (842, 'UPF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (843, 'UPF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO "mml_system" VALUES (853, 'SMF', 'smfManagement', 'SMF Management', 'help', '', 'List SMF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (854, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 server', 'Set N7 Server', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (855, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 client', 'Set N7 Client', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (856, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 server', 'Set N10 Server', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (857, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 client', 'Set N10 Client', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (858, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 server', 'Set N11 Server', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"},{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (859, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 client', 'Set N11 Client', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"},{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (860, 'SMF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'General', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"int"},{"comment":"","display":"DNN","filter":"","name":"DNN","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (862, 'SMF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'General', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"comment":"","display":"SD","filter":"","name":"5qi","optional":"false","type":"string"},{"comment":"","display":"5qipl","filter":"","name":"5qipl","optional":"false","type":"string"},{"comment":"","display":"arppl","filter":"","name":"arppl","optional":"false","type":"string"},{"comment":"","display":"arppci","filter":"","name":"arppci","optional":"false","type":"string"},{"comment":"","display":"arppvi","filter":"","name":"arppvi","optional":"false","type":"string"},{"comment":"","display":"mfbrul","filter":"","name":"mfbrul","optional":"false","type":"string"},{"comment":"","display":"mfbrdl","filter":"","name":"mfbrdl","optional":"false","type":"string"},{"comment":"","display":"gfbrul","filter":"","name":"gfbrul","optional":"false","type":"string"},{"comment":"","display":"gfbrdl","filter":"","name":"gfbrdl","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (863, 'SMF', 'systemManagement', 'System Management', 'set', 'snssai', 'Set Snssai', 'General', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"display":"sst-sd","filter":"","name":"sst-sd","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (864, 'SMF', 'systemManagement', 'System Management', 'release', 'imsi', 'Release IMSI', 'General', '[{"comment":"","display":"IMSI","filter":"","name":"imsi","optional":"false","type":"string"},{"display":"PDU Session Id","filter":"","name":"pduSessId","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (865, 'SMF', 'systemManagement', 'System Management', 'set', 'urr', 'Set URR', 'General', '[{"comment":"","display":"Index","filter":"","name":"index","optional":"false","type":"string"},{"comment":"","display":"Quota Volume Tatol","filter":"","name":"quotavolumetatol","optional":"false","type":"string"},{"comment":"","display":"Quota Volume UL","filter":"","name":"quotavolumeul","optional":"false","type":"string"},{"comment":"","display":"Quota Volume DL","filter":"","name":"quotavolumedl","optional":"false","type":"string"},{"comment":"","display":"Quota Time","filter":"","name":"quotatime","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (866, 'SMF', 'systemManagement', 'System Management', 'set', 'dpi', 'Set DPI', 'General', '[{"comment":"","display":"Flag","filter":"{\"0\":\"disable\", \"1\":\"enable\"}","name":"flag","optional":"false","type":"enum"},{"comment":"","display":"Max Detect Packet Number","filter":"","name":"max","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (867, 'SMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (868, 'SMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO "mml_system" VALUES (870, 'IMS', 'imsManagement', 'IMS Management', 'help', '', 'List IMS MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (871, 'N3IWF', 'n3iwfManagement', 'N3IWF Management', 'help', '', 'List N3IWF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (872, 'NSSF', 'nssfManagement', 'NSSF Management', 'help', '', 'List NSSF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (873, 'NRF', 'nrfManagement', 'NRF Management', 'help', '', 'List NRF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (874, 'PCF', 'pcfManagement', 'PCF Management', 'help', '', 'List PCF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (875, 'AMF', 'subsManagement', 'Subscriber Management', 'list', 'imsi', 'List Online IMSI', 'General', '[{"comment":"","display":"IMSI","filter":"32","name":"imsi","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (876, 'AMF', 'amfManagement', 'AMF Management', 'help', '', 'List AMF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (877, 'AMF', 'systemManagement', 'System Management', 'set', 'n8_ip', 'Set N8 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (878, 'AMF', 'systemManagement', 'System Management', 'set', 'n11_ip', 'Set N11 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (879, 'AMF', 'systemManagement', 'System Management', 'set', 'n12_ip', 'Set N12 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"0~64","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (880, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_ip', 'Set N2 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (881, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_port', 'Set N2 Port', 'General', '[{"comment":"","display":"Port","filter":"0~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (882, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpversion', 'Set NTP Version', 'General', '[{"comment":"","display":"Version","filter":"","name":"version","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (883, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpmaxdiff', 'Set NTP Max Diff', 'General', '[{"comment":"","display":"Max Value(ms)","filter":"100~2000","name":"value","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (884, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpsynctimer', 'Set NTP Sync Timer', 'General', '[{"comment":"","display":"Periods(second)","filter":"","name":"periods","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (885, 'AMF', 'systemManagement', 'System Management', 'add', 'slice', 'Add Slice', 'General', '[{"comment":"","display":"SST","filter":"","name":"sst","optional":"false","type":"string"},{"comment":"","display":"SD","filter":"","name":"sd","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (886, 'AMF', 'systemManagement', 'System Management', 'deregister', 'imsi', 'Deregister IMSI', 'General', '[{"comment":"","display":"IMSI","filter":"","name":"IMSI","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (887, 'AMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (888, 'AMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO "mml_system" VALUES (889, 'UDM', 'udmManagement', 'UDM Management', 'help', '', 'List UDM MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (890, 'UDM', 'systemManagement', 'System Management', 'set', 'n8ip', 'Set N8 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"ipv4"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (891, 'UDM', 'systemManagement', 'System Management', 'set', 'n8port', 'Set N8 Port', 'General', '[{"comment":"","display":"Port","filter":"1~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (892, 'UDM', 'systemManagement', 'System Management', 'set', 'n8scheme', 'Set N8 Scheme', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (893, 'UDM', 'systemManagement', 'System Management', 'set', 'n10ip', 'Set N10 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (894, 'UDM', 'systemManagement', 'System Management', 'set', 'n10port', 'Set N10 Port', 'General', '[{"comment":"","display":"Port","filter":"1~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (895, 'UDM', 'systemManagement', 'System Management', 'set', 'n10scheme', 'Set N10 Scheme', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (896, 'UDM', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{"comment":"","display":"CMD","filter":"","name":"cmd","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (897, 'UDM', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO "mml_system" VALUES (898, 'AUSF', 'ausfManagement', 'AUSF Management', 'help', '', 'List AUSF MML CMD', 'General', 'null', 'Active'); +INSERT INTO "mml_system" VALUES (899, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12ip', 'Set N12 IP Address', 'General', '[{"comment":"","display":"IP Address","filter":"","name":"ip","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (900, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12port', 'Set N12 Port', 'General', '[{"comment":"","display":"Port","filter":"1~65535","name":"port","optional":"false","type":"int"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (901, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12scheme', 'Set N12 Scheme', 'General', '[{"comment":"","display":"Scheme","filter":"{\"0\":\"http\", \"1\":\"https\"}","name":"scheme","optional":"false","type":"enum"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (902, 'AUSF', 'systemManagement', 'System Management', 'set', 'supirange', 'Set SUPI Range', 'General', '[{"comment":"","display":"SUPI Range","filter":"","name":"supirange","optional":"false","type":"string"}]', 'Inactive'); +INSERT INTO "mml_system" VALUES (903, 'AUSF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO "mml_system" VALUES (904, 'MME', 'mmeManagement', 'MME Management', 'help', '', 'List MME MML CMD', 'General', 'null', 'Active'); diff --git a/build/database/std/common/mml_system.sql b/build/database/std/common/mml_system.sql index f19b51c7..696dc145 100644 --- a/build/database/std/common/mml_system.sql +++ b/build/database/std/common/mml_system.sql @@ -29,7 +29,7 @@ CREATE TABLE `mml_system` ( `operation` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `object` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `mml_display` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, - `object_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'mml', + `object_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'General', `param_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL, `status` enum('Active','Inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Active' COMMENT '激活: Active 未激活: Inactive', PRIMARY KEY (`id`) USING BTREE @@ -38,66 +38,66 @@ CREATE TABLE `mml_system` ( -- ---------------------------- -- Records of mml_system -- ---------------------------- -INSERT INTO `mml_system` VALUES (833, 'UPF', 'upfManagement', 'UPF Management', 'help', '', 'List UPF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (834, 'UPF', 'systemManagement', 'System Management', 'set', 'n3 driver', 'Set N3 Driver', 'mml', '[{\"comment\":\"\",\"display\":\"Type\",\"filter\":\"\",\"name\":\"type\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"IP address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mask\",\"filter\":\"\",\"name\":\"mask\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mac address\",\"filter\":\"\",\"name\":\"mac\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"PCI address\",\"filter\":\"\",\"name\":\"pci\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (835, 'UPF', 'systemManagement', 'System Management', 'set', 'n4 ip', 'Set N4 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (836, 'UPF', 'systemManagement', 'System Management', 'set', 'n6 driver', 'Set N6 Driver', 'mml', '[{\"comment\":\"\",\"display\":\"Type\",\"filter\":\"\",\"name\":\"type\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"IP address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mask\",\"filter\":\"\",\"name\":\"mask\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mac address\",\"filter\":\"\",\"name\":\"mac\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"PCI address\",\"filter\":\"\",\"name\":\"pci\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (837, 'UPF', 'systemManagement', 'System Management', 'set', 'n9 driver', 'Set N9 Driver', 'mml', '[{\"comment\":\"\",\"display\":\"Type\",\"filter\":\"\",\"name\":\"type\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"IP address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mask\",\"filter\":\"\",\"name\":\"mask\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mac address\",\"filter\":\"\",\"name\":\"mac\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"PCI address\",\"filter\":\"\",\"name\":\"pci\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (838, 'UPF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'mml', '[{\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"\",\"name\":\"dnn\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (839, 'UPF', 'systemManagement', 'System Management', 'set', 'pfcp', 'Set PFCP', 'mml', '[{\"comment\":\"\",\"display\":\"Path\",\"filter\":\"\",\"name\":\"path\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Local IP Address\",\"filter\":\"\",\"name\":\"local\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Remote IP Address\",\"filter\":\"\",\"name\":\"remote\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (840, 'UPF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'mml', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"5qi\",\"filter\":\"\",\"name\":\"5qi\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"\",\"name\":\"priority\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"MBR\",\"filter\":\"\",\"name\":\"mbr\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"GBR\",\"filter\":\"\",\"name\":\"gbr\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (841, 'UPF', 'systemManagement', 'System Management', 'set', 'pccrule', 'Set PCC Rule', 'mml', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"0~65535\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"Precedence\",\"filter\":\"\",\"name\":\"precedence\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"QOS Index\",\"filter\":\"\",\"name\":\"qosindex\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"Filter Direction\",\"filter\":\"{\\\"0\\\":\\\"NA\\\", \\\"1\\\":\\\"Uplink\\\", \\\"2\\\":\\\"Downlink\\\", \\\"3\\\":\\\"Bidirectionallink\\\"}\",\"name\":\"direction\",\"optional\":\"true\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"Filter\",\"filter\":\"\",\"name\":\"filter\",\"optional\":\"true\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Application ID\",\"filter\":\"\",\"name\":\"appid\",\"optional\":\"true\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (842, 'UPF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (843, 'UPF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO `mml_system` VALUES (853, 'SMF', 'smfManagement', 'SMF Management', 'help', '', 'List SMF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (854, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 server', 'Set N7 Server', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (855, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 client', 'Set N7 Client', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (856, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 server', 'Set N10 Server', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (857, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 client', 'Set N10 Client', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (858, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 server', 'Set N11 Server', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (859, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 client', 'Set N11 Client', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (860, 'SMF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'mml', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"\",\"name\":\"DNN\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (862, 'SMF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'mml', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"SD\",\"filter\":\"\",\"name\":\"5qi\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"5qipl\",\"filter\":\"\",\"name\":\"5qipl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"arppl\",\"filter\":\"\",\"name\":\"arppl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"arppci\",\"filter\":\"\",\"name\":\"arppci\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"arppvi\",\"filter\":\"\",\"name\":\"arppvi\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"mfbrul\",\"filter\":\"\",\"name\":\"mfbrul\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"mfbrdl\",\"filter\":\"\",\"name\":\"mfbrdl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"gfbrul\",\"filter\":\"\",\"name\":\"gfbrul\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"gfbrdl\",\"filter\":\"\",\"name\":\"gfbrdl\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (863, 'SMF', 'systemManagement', 'System Management', 'set', 'snssai', 'Set Snssai', 'mml', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"display\":\"sst-sd\",\"filter\":\"\",\"name\":\"sst-sd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (864, 'SMF', 'systemManagement', 'System Management', 'release', 'imsi', 'Release IMSI', 'mml', '[{\"comment\":\"\",\"display\":\"IMSI\",\"filter\":\"\",\"name\":\"imsi\",\"optional\":\"false\",\"type\":\"string\"},{\"display\":\"PDU Session Id\",\"filter\":\"\",\"name\":\"pduSessId\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (865, 'SMF', 'systemManagement', 'System Management', 'set', 'urr', 'Set URR', 'mml', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Volume Tatol\",\"filter\":\"\",\"name\":\"quotavolumetatol\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Volume UL\",\"filter\":\"\",\"name\":\"quotavolumeul\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Volume DL\",\"filter\":\"\",\"name\":\"quotavolumedl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Time\",\"filter\":\"\",\"name\":\"quotatime\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (866, 'SMF', 'systemManagement', 'System Management', 'set', 'dpi', 'Set DPI', 'mml', '[{\"comment\":\"\",\"display\":\"Flag\",\"filter\":\"{\\\"0\\\":\\\"disable\\\", \\\"1\\\":\\\"enable\\\"}\",\"name\":\"flag\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"Max Detect Packet Number\",\"filter\":\"\",\"name\":\"max\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (867, 'SMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (868, 'SMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO `mml_system` VALUES (870, 'IMS', 'imsManagement', 'IMS Management', 'help', '', 'List IMS MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (871, 'N3IWF', 'n3iwfManagement', 'N3IWF Management', 'help', '', 'List N3IWF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (872, 'NSSF', 'nssfManagement', 'NSSF Management', 'help', '', 'List NSSF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (873, 'NRF', 'nrfManagement', 'NRF Management', 'help', '', 'List NRF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (874, 'PCF', 'pcfManagement', 'PCF Management', 'help', '', 'List PCF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (875, 'AMF', 'subsManagement', 'Subscriber Management', 'list', 'imsi', 'List Online IMSI', 'mml', '[{\"comment\":\"\",\"display\":\"IMSI\",\"filter\":\"32\",\"name\":\"imsi\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (876, 'AMF', 'amfManagement', 'AMF Management', 'help', '', 'List AMF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (877, 'AMF', 'systemManagement', 'System Management', 'set', 'n8_ip', 'Set N8 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (878, 'AMF', 'systemManagement', 'System Management', 'set', 'n11_ip', 'Set N11 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (879, 'AMF', 'systemManagement', 'System Management', 'set', 'n12_ip', 'Set N12 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (880, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_ip', 'Set N2 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (881, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_port', 'Set N2 Port', 'mml', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (882, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpversion', 'Set NTP Version', 'mml', '[{\"comment\":\"\",\"display\":\"Version\",\"filter\":\"\",\"name\":\"version\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (883, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpmaxdiff', 'Set NTP Max Diff', 'mml', '[{\"comment\":\"\",\"display\":\"Max Value(ms)\",\"filter\":\"100~2000\",\"name\":\"value\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (884, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpsynctimer', 'Set NTP Sync Timer', 'mml', '[{\"comment\":\"\",\"display\":\"Periods(second)\",\"filter\":\"\",\"name\":\"periods\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (885, 'AMF', 'systemManagement', 'System Management', 'add', 'slice', 'Add Slice', 'mml', '[{\"comment\":\"\",\"display\":\"SST\",\"filter\":\"\",\"name\":\"sst\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"SD\",\"filter\":\"\",\"name\":\"sd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (886, 'AMF', 'systemManagement', 'System Management', 'deregister', 'imsi', 'Deregister IMSI', 'mml', '[{\"comment\":\"\",\"display\":\"IMSI\",\"filter\":\"\",\"name\":\"IMSI\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (887, 'AMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (888, 'AMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO `mml_system` VALUES (889, 'UDM', 'udmManagement', 'UDM Management', 'help', '', 'List UDM MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (890, 'UDM', 'systemManagement', 'System Management', 'set', 'n8ip', 'Set N8 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"ipv4\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (891, 'UDM', 'systemManagement', 'System Management', 'set', 'n8port', 'Set N8 Port', 'mml', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"1~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (892, 'UDM', 'systemManagement', 'System Management', 'set', 'n8scheme', 'Set N8 Scheme', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (893, 'UDM', 'systemManagement', 'System Management', 'set', 'n10ip', 'Set N10 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (894, 'UDM', 'systemManagement', 'System Management', 'set', 'n10port', 'Set N10 Port', 'mml', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"1~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (895, 'UDM', 'systemManagement', 'System Management', 'set', 'n10scheme', 'Set N10 Scheme', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (896, 'UDM', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'mml', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (897, 'UDM', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO `mml_system` VALUES (898, 'AUSF', 'ausfManagement', 'AUSF Management', 'help', '', 'List AUSF MML CMD', 'mml', 'null', 'Active'); -INSERT INTO `mml_system` VALUES (899, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12ip', 'Set N12 IP Address', 'mml', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (900, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12port', 'Set N12 Port', 'mml', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"1~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (901, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12scheme', 'Set N12 Scheme', 'mml', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (902, 'AUSF', 'systemManagement', 'System Management', 'set', 'supirange', 'Set SUPI Range', 'mml', '[{\"comment\":\"\",\"display\":\"SUPI Range\",\"filter\":\"\",\"name\":\"supirange\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); -INSERT INTO `mml_system` VALUES (903, 'AUSF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'mml', 'null', 'Inactive'); -INSERT INTO `mml_system` VALUES (904, 'MME', 'mmeManagement', 'MME Management', 'help', '', 'List MME MML CMD', 'mml', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (833, 'UPF', 'upfManagement', 'UPF Management', 'help', '', 'List UPF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (834, 'UPF', 'systemManagement', 'System Management', 'set', 'n3 driver', 'Set N3 Driver', 'General', '[{\"comment\":\"\",\"display\":\"Type\",\"filter\":\"\",\"name\":\"type\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"IP address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mask\",\"filter\":\"\",\"name\":\"mask\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mac address\",\"filter\":\"\",\"name\":\"mac\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"PCI address\",\"filter\":\"\",\"name\":\"pci\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (835, 'UPF', 'systemManagement', 'System Management', 'set', 'n4 ip', 'Set N4 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (836, 'UPF', 'systemManagement', 'System Management', 'set', 'n6 driver', 'Set N6 Driver', 'General', '[{\"comment\":\"\",\"display\":\"Type\",\"filter\":\"\",\"name\":\"type\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"IP address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mask\",\"filter\":\"\",\"name\":\"mask\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mac address\",\"filter\":\"\",\"name\":\"mac\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"PCI address\",\"filter\":\"\",\"name\":\"pci\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (837, 'UPF', 'systemManagement', 'System Management', 'set', 'n9 driver', 'Set N9 Driver', 'General', '[{\"comment\":\"\",\"display\":\"Type\",\"filter\":\"\",\"name\":\"type\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"IP address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mask\",\"filter\":\"\",\"name\":\"mask\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Mac address\",\"filter\":\"\",\"name\":\"mac\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"PCI address\",\"filter\":\"\",\"name\":\"pci\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (838, 'UPF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'General', '[{\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"\",\"name\":\"dnn\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (839, 'UPF', 'systemManagement', 'System Management', 'set', 'pfcp', 'Set PFCP', 'General', '[{\"comment\":\"\",\"display\":\"Path\",\"filter\":\"\",\"name\":\"path\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Local IP Address\",\"filter\":\"\",\"name\":\"local\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Remote IP Address\",\"filter\":\"\",\"name\":\"remote\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (840, 'UPF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'General', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"5qi\",\"filter\":\"\",\"name\":\"5qi\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Priority Level\",\"filter\":\"\",\"name\":\"priority\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"MBR\",\"filter\":\"\",\"name\":\"mbr\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"GBR\",\"filter\":\"\",\"name\":\"gbr\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (841, 'UPF', 'systemManagement', 'System Management', 'set', 'pccrule', 'Set PCC Rule', 'General', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"0~65535\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"Precedence\",\"filter\":\"\",\"name\":\"precedence\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"QOS Index\",\"filter\":\"\",\"name\":\"qosindex\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"Filter Direction\",\"filter\":\"{\\\"0\\\":\\\"NA\\\", \\\"1\\\":\\\"Uplink\\\", \\\"2\\\":\\\"Downlink\\\", \\\"3\\\":\\\"Bidirectionallink\\\"}\",\"name\":\"direction\",\"optional\":\"true\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"Filter\",\"filter\":\"\",\"name\":\"filter\",\"optional\":\"true\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Application ID\",\"filter\":\"\",\"name\":\"appid\",\"optional\":\"true\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (842, 'UPF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (843, 'UPF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO `mml_system` VALUES (853, 'SMF', 'smfManagement', 'SMF Management', 'help', '', 'List SMF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (854, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 server', 'Set N7 Server', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (855, 'SMF', 'systemManagement', 'System Management', 'set', 'n7 client', 'Set N7 Client', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (856, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 server', 'Set N10 Server', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (857, 'SMF', 'systemManagement', 'System Management', 'set', 'n10 client', 'Set N10 Client', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (858, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 server', 'Set N11 Server', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (859, 'SMF', 'systemManagement', 'System Management', 'set', 'n11 client', 'Set N11 Client', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (860, 'SMF', 'systemManagement', 'System Management', 'set', 'dnn', 'Set DNN', 'General', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"int\"},{\"comment\":\"\",\"display\":\"DNN\",\"filter\":\"\",\"name\":\"DNN\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (862, 'SMF', 'systemManagement', 'System Management', 'set', 'qos', 'Set Qos', 'General', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"SD\",\"filter\":\"\",\"name\":\"5qi\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"5qipl\",\"filter\":\"\",\"name\":\"5qipl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"arppl\",\"filter\":\"\",\"name\":\"arppl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"arppci\",\"filter\":\"\",\"name\":\"arppci\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"arppvi\",\"filter\":\"\",\"name\":\"arppvi\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"mfbrul\",\"filter\":\"\",\"name\":\"mfbrul\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"mfbrdl\",\"filter\":\"\",\"name\":\"mfbrdl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"gfbrul\",\"filter\":\"\",\"name\":\"gfbrul\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"gfbrdl\",\"filter\":\"\",\"name\":\"gfbrdl\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (863, 'SMF', 'systemManagement', 'System Management', 'set', 'snssai', 'Set Snssai', 'General', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"display\":\"sst-sd\",\"filter\":\"\",\"name\":\"sst-sd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (864, 'SMF', 'systemManagement', 'System Management', 'release', 'imsi', 'Release IMSI', 'General', '[{\"comment\":\"\",\"display\":\"IMSI\",\"filter\":\"\",\"name\":\"imsi\",\"optional\":\"false\",\"type\":\"string\"},{\"display\":\"PDU Session Id\",\"filter\":\"\",\"name\":\"pduSessId\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (865, 'SMF', 'systemManagement', 'System Management', 'set', 'urr', 'Set URR', 'General', '[{\"comment\":\"\",\"display\":\"Index\",\"filter\":\"\",\"name\":\"index\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Volume Tatol\",\"filter\":\"\",\"name\":\"quotavolumetatol\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Volume UL\",\"filter\":\"\",\"name\":\"quotavolumeul\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Volume DL\",\"filter\":\"\",\"name\":\"quotavolumedl\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"Quota Time\",\"filter\":\"\",\"name\":\"quotatime\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (866, 'SMF', 'systemManagement', 'System Management', 'set', 'dpi', 'Set DPI', 'General', '[{\"comment\":\"\",\"display\":\"Flag\",\"filter\":\"{\\\"0\\\":\\\"disable\\\", \\\"1\\\":\\\"enable\\\"}\",\"name\":\"flag\",\"optional\":\"false\",\"type\":\"enum\"},{\"comment\":\"\",\"display\":\"Max Detect Packet Number\",\"filter\":\"\",\"name\":\"max\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (867, 'SMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (868, 'SMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO `mml_system` VALUES (870, 'IMS', 'imsManagement', 'IMS Management', 'help', '', 'List IMS MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (871, 'N3IWF', 'n3iwfManagement', 'N3IWF Management', 'help', '', 'List N3IWF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (872, 'NSSF', 'nssfManagement', 'NSSF Management', 'help', '', 'List NSSF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (873, 'NRF', 'nrfManagement', 'NRF Management', 'help', '', 'List NRF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (874, 'PCF', 'pcfManagement', 'PCF Management', 'help', '', 'List PCF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (875, 'AMF', 'subsManagement', 'Subscriber Management', 'list', 'imsi', 'List Online IMSI', 'General', '[{\"comment\":\"\",\"display\":\"IMSI\",\"filter\":\"32\",\"name\":\"imsi\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (876, 'AMF', 'amfManagement', 'AMF Management', 'help', '', 'List AMF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (877, 'AMF', 'systemManagement', 'System Management', 'set', 'n8_ip', 'Set N8 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (878, 'AMF', 'systemManagement', 'System Management', 'set', 'n11_ip', 'Set N11 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (879, 'AMF', 'systemManagement', 'System Management', 'set', 'n12_ip', 'Set N12 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"0~64\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (880, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_ip', 'Set N2 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (881, 'AMF', 'systemManagement', 'System Management', 'set', 'n2_port', 'Set N2 Port', 'General', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"0~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (882, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpversion', 'Set NTP Version', 'General', '[{\"comment\":\"\",\"display\":\"Version\",\"filter\":\"\",\"name\":\"version\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (883, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpmaxdiff', 'Set NTP Max Diff', 'General', '[{\"comment\":\"\",\"display\":\"Max Value(ms)\",\"filter\":\"100~2000\",\"name\":\"value\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (884, 'AMF', 'systemManagement', 'System Management', 'set', 'ntpsynctimer', 'Set NTP Sync Timer', 'General', '[{\"comment\":\"\",\"display\":\"Periods(second)\",\"filter\":\"\",\"name\":\"periods\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (885, 'AMF', 'systemManagement', 'System Management', 'add', 'slice', 'Add Slice', 'General', '[{\"comment\":\"\",\"display\":\"SST\",\"filter\":\"\",\"name\":\"sst\",\"optional\":\"false\",\"type\":\"string\"},{\"comment\":\"\",\"display\":\"SD\",\"filter\":\"\",\"name\":\"sd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (886, 'AMF', 'systemManagement', 'System Management', 'deregister', 'imsi', 'Deregister IMSI', 'General', '[{\"comment\":\"\",\"display\":\"IMSI\",\"filter\":\"\",\"name\":\"IMSI\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (887, 'AMF', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (888, 'AMF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO `mml_system` VALUES (889, 'UDM', 'udmManagement', 'UDM Management', 'help', '', 'List UDM MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (890, 'UDM', 'systemManagement', 'System Management', 'set', 'n8ip', 'Set N8 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"ipv4\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (891, 'UDM', 'systemManagement', 'System Management', 'set', 'n8port', 'Set N8 Port', 'General', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"1~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (892, 'UDM', 'systemManagement', 'System Management', 'set', 'n8scheme', 'Set N8 Scheme', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (893, 'UDM', 'systemManagement', 'System Management', 'set', 'n10ip', 'Set N10 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (894, 'UDM', 'systemManagement', 'System Management', 'set', 'n10port', 'Set N10 Port', 'General', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"1~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (895, 'UDM', 'systemManagement', 'System Management', 'set', 'n10scheme', 'Set N10 Scheme', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (896, 'UDM', 'systemManagement', 'System Management', 'exec', 'shell', 'Execute Shell Command', 'General', '[{\"comment\":\"\",\"display\":\"CMD\",\"filter\":\"\",\"name\":\"cmd\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (897, 'UDM', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO `mml_system` VALUES (898, 'AUSF', 'ausfManagement', 'AUSF Management', 'help', '', 'List AUSF MML CMD', 'General', 'null', 'Active'); +INSERT INTO `mml_system` VALUES (899, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12ip', 'Set N12 IP Address', 'General', '[{\"comment\":\"\",\"display\":\"IP Address\",\"filter\":\"\",\"name\":\"ip\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (900, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12port', 'Set N12 Port', 'General', '[{\"comment\":\"\",\"display\":\"Port\",\"filter\":\"1~65535\",\"name\":\"port\",\"optional\":\"false\",\"type\":\"int\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (901, 'AUSF', 'systemManagement', 'System Management', 'set', 'n12scheme', 'Set N12 Scheme', 'General', '[{\"comment\":\"\",\"display\":\"Scheme\",\"filter\":\"{\\\"0\\\":\\\"http\\\", \\\"1\\\":\\\"https\\\"}\",\"name\":\"scheme\",\"optional\":\"false\",\"type\":\"enum\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (902, 'AUSF', 'systemManagement', 'System Management', 'set', 'supirange', 'Set SUPI Range', 'General', '[{\"comment\":\"\",\"display\":\"SUPI Range\",\"filter\":\"\",\"name\":\"supirange\",\"optional\":\"false\",\"type\":\"string\"}]', 'Inactive'); +INSERT INTO `mml_system` VALUES (903, 'AUSF', 'systemManagement', 'System Management', 'reload', '', 'Reload Config', 'General', 'null', 'Inactive'); +INSERT INTO `mml_system` VALUES (904, 'MME', 'mmeManagement', 'MME Management', 'help', '', 'List MME MML CMD', 'General', 'null', 'Active'); SET FOREIGN_KEY_CHECKS = 1; From 500ae6f79c816e6e0ef6dda71849a438728d2ad6 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 4 Aug 2025 18:20:40 +0800 Subject: [PATCH 56/80] =?UTF-8?q?fix:=20MML=E5=91=BD=E4=BB=A4=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=9B=9E=E8=BD=A6\r\n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/tool/controller/mml.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/modules/tool/controller/mml.go b/src/modules/tool/controller/mml.go index 079ae666..86bb05f1 100644 --- a/src/modules/tool/controller/mml.go +++ b/src/modules/tool/controller/mml.go @@ -72,7 +72,7 @@ func (s MMLController) Command(c *gin.Context) { } // 网元主机的Telnet客户端 num := 1 - if body.Type == "Standard" { + if body.NeType == "UPF" && body.Type == "Standard" { num = 2 } telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, num) @@ -80,14 +80,18 @@ func (s MMLController) Command(c *gin.Context) { c.JSON(200, resp.ErrMsg(err.Error())) return } + telnetClient.RunCMD("\r\n") defer telnetClient.Close() - if body.Type == "Standard" { + if body.NeType == "UPF" && body.Type == "Standard" { telnetClient.WindowChange(1024, 1024) } // 发送MML result := []string{} for _, v := range body.Command { - output, err := telnetClient.RunCMD(v + "\r\r") + if v == "" { + continue + } + output, err := telnetClient.RunCMD(v + "\r\n") if err != nil { result = append(result, err.Error()) continue From 5b37b3eab86d6c897c2767edbde49d1b27423f00 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 4 Aug 2025 19:23:56 +0800 Subject: [PATCH 57/80] =?UTF-8?q?fix:=20UDM=E7=AD=BE=E7=BA=A6=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1rfsp=E5=92=8Cusagetype=E5=8F=82=E6=95=B0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/service/udm_sub.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/network_data/service/udm_sub.go b/src/modules/network_data/service/udm_sub.go index 76cc5c76..2accef0b 100644 --- a/src/modules/network_data/service/udm_sub.go +++ b/src/modules/network_data/service/udm_sub.go @@ -318,6 +318,12 @@ func (r *UDMSubUser) ParseCommandParams(item model.UDMSubUser) string { if item.CnTypeRestrictions != "" { conditions = append(conditions, fmt.Sprintf("cn=%s", item.CnTypeRestrictions)) } + if item.RfspIndex != "" { + conditions = append(conditions, fmt.Sprintf("rfsp=%s", item.RfspIndex)) + } + if item.UeUsageType != "" { + conditions = append(conditions, fmt.Sprintf("usagetype=%s", item.UeUsageType)) + } if item.MicoAllowed != "" { conditions = append(conditions, fmt.Sprintf("mico=%s", item.MicoAllowed)) } From 51a16c4ff567972e50cb1a714c4674c98b1b65c9 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 5 Aug 2025 11:20:39 +0800 Subject: [PATCH 58/80] =?UTF-8?q?fix:=20MML=E5=91=BD=E4=BB=A4=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=9B=9E=E8=BD=A6\r\n=20-=20IMS=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/tool/controller/mml.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/tool/controller/mml.go b/src/modules/tool/controller/mml.go index 86bb05f1..caafe85e 100644 --- a/src/modules/tool/controller/mml.go +++ b/src/modules/tool/controller/mml.go @@ -80,8 +80,10 @@ func (s MMLController) Command(c *gin.Context) { c.JSON(200, resp.ErrMsg(err.Error())) return } - telnetClient.RunCMD("\r\n") defer telnetClient.Close() + if body.NeType != "IMS" { + telnetClient.RunCMD("\r\n") + } if body.NeType == "UPF" && body.Type == "Standard" { telnetClient.WindowChange(1024, 1024) } From 0698f02c61af951b390b72b856bd7530f7dbf358 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 5 Aug 2025 11:21:20 +0800 Subject: [PATCH 59/80] =?UTF-8?q?fix:=20=E5=9F=BA=E7=AB=99=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E8=AE=B0=E5=BD=95=E6=97=B6=E9=97=B4=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=AD=97=E6=AE=B5create=5Ftime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/repository/nb_state.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/network_data/repository/nb_state.go b/src/modules/network_data/repository/nb_state.go index 6faf437c..0c3fa1ed 100644 --- a/src/modules/network_data/repository/nb_state.go +++ b/src/modules/network_data/repository/nb_state.go @@ -5,7 +5,6 @@ import ( "be.ems/src/framework/database/db" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" "be.ems/src/modules/network_data/model" ) @@ -36,14 +35,14 @@ func (r NBState) SelectByPage(query model.NBStateQuery) ([]model.NBState, int64) if len(startTime) == 10 { startTime = startTime + "000" } - tx = tx.Where("time >= ?", date.ParseDateToStr(startTime, date.YYYY_MM_DDTHH_MM_SSZ)) + tx = tx.Where("create_time >= ?", startTime) } if query.EndTime != "" { endTime := query.EndTime if len(endTime) == 10 { endTime = endTime + "999" } - tx = tx.Where("time <= ?", date.ParseDateToStr(endTime, date.YYYY_MM_DDTHH_MM_SSZ)) + tx = tx.Where("create_time <= ?", endTime) } // 查询结果 From 96b15d4cf2742d2336ca44540f5307faee2919fd Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 5 Aug 2025 17:31:31 +0800 Subject: [PATCH 60/80] =?UTF-8?q?feat:=20MML=E6=97=A5=E5=BF=97=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=8A=9F=E8=83=BD=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/mml_log.sql | 6 +- build/database/lite/upgrade/upg_mml_log.sql | 19 ++++++ build/database/std/install/mml_log.sql | 37 ++---------- build/database/std/upgrade/upg_mml_log.sql | 18 ++++++ src/modules/tool/controller/mml.go | 29 ++++++++- src/modules/tool/model/mml_log.go | 18 ++++++ src/modules/tool/repository/mml_log.go | 67 +++++++++++++++++++++ src/modules/tool/service/mml_log.go | 26 ++++++++ src/modules/tool/tool.go | 4 ++ 9 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 build/database/lite/upgrade/upg_mml_log.sql create mode 100644 build/database/std/upgrade/upg_mml_log.sql create mode 100644 src/modules/tool/model/mml_log.go create mode 100644 src/modules/tool/repository/mml_log.go create mode 100644 src/modules/tool/service/mml_log.go diff --git a/build/database/lite/install/mml_log.sql b/build/database/lite/install/mml_log.sql index 392309ec..8c2a5391 100644 --- a/build/database/lite/install/mml_log.sql +++ b/build/database/lite/install/mml_log.sql @@ -8,9 +8,9 @@ CREATE TABLE "mml_log" ( "ip" text(64), "ne_type" text(32), "ne_id" text(32), - "mml" text(1024), - "result" text(2048), - "log_time" text, + "command" text(512), + "result" text(255), + "log_time" integer, PRIMARY KEY ("id") ); diff --git a/build/database/lite/upgrade/upg_mml_log.sql b/build/database/lite/upgrade/upg_mml_log.sql new file mode 100644 index 00000000..8c2a5391 --- /dev/null +++ b/build/database/lite/upgrade/upg_mml_log.sql @@ -0,0 +1,19 @@ +-- ---------------------------- +-- Table structure for mml_log +-- ---------------------------- +DROP TABLE IF EXISTS "mml_log"; +CREATE TABLE "mml_log" ( + "id" integer NOT NULL, + "user" text(32), + "ip" text(64), + "ne_type" text(32), + "ne_id" text(32), + "command" text(512), + "result" text(255), + "log_time" integer, + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Records of mml_log +-- ---------------------------- diff --git a/build/database/std/install/mml_log.sql b/build/database/std/install/mml_log.sql index e6a817c9..22c7ca66 100644 --- a/build/database/std/install/mml_log.sql +++ b/build/database/std/install/mml_log.sql @@ -1,47 +1,18 @@ --- MariaDB dump 10.19 Distrib 10.6.16-MariaDB, for debian-linux-gnu (x86_64) --- --- Host: 192.168.2.219 Database: omc_db --- ------------------------------------------------------ --- Server version 10.3.38-MariaDB - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - -- -- Table structure for table `mml_log` -- DROP TABLE IF EXISTS `mml_log`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; CREATE TABLE `mml_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user` varchar(32) DEFAULT NULL, `ip` varchar(64) DEFAULT NULL, `ne_type` varchar(32) DEFAULT NULL, `ne_id` varchar(32) DEFAULT NULL, - `mml` varchar(1024) DEFAULT NULL, - `result` varchar(2048) DEFAULT NULL, - `log_time` datetime DEFAULT NULL, + `command` varchar(512) DEFAULT NULL COMMENT '命令 ; 分隔', + `result` varchar(255) DEFAULT NULL COMMENT '成功和有错误', + `log_time` bigint DEFAULT '0' COMMENT '记录时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=467 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; -/*!40101 SET character_set_client = @saved_cs_client */; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; -- Dump completed on 2024-03-06 17:26:56 diff --git a/build/database/std/upgrade/upg_mml_log.sql b/build/database/std/upgrade/upg_mml_log.sql new file mode 100644 index 00000000..22c7ca66 --- /dev/null +++ b/build/database/std/upgrade/upg_mml_log.sql @@ -0,0 +1,18 @@ +-- +-- Table structure for table `mml_log` +-- + +DROP TABLE IF EXISTS `mml_log`; +CREATE TABLE `mml_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user` varchar(32) DEFAULT NULL, + `ip` varchar(64) DEFAULT NULL, + `ne_type` varchar(32) DEFAULT NULL, + `ne_id` varchar(32) DEFAULT NULL, + `command` varchar(512) DEFAULT NULL COMMENT '命令 ; 分隔', + `result` varchar(255) DEFAULT NULL COMMENT '成功和有错误', + `log_time` bigint DEFAULT '0' COMMENT '记录时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; + +-- Dump completed on 2024-03-06 17:26:56 diff --git a/src/modules/tool/controller/mml.go b/src/modules/tool/controller/mml.go index caafe85e..16dcda09 100644 --- a/src/modules/tool/controller/mml.go +++ b/src/modules/tool/controller/mml.go @@ -4,13 +4,14 @@ import ( "fmt" "strings" + "github.com/gin-gonic/gin" + "be.ems/src/framework/i18n" "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" neService "be.ems/src/modules/network_element/service" + "be.ems/src/modules/tool/model" "be.ems/src/modules/tool/service" - - "github.com/gin-gonic/gin" ) // 实例化控制层 MMLController 结构体 @@ -18,6 +19,7 @@ var NewMML = &MMLController{ neInfoService: neService.NewNeInfo, mmlSystemService: service.NewMMLSystem, mmlSubscriberService: service.NewMMLSubscriber, + mmlLogService: service.NewMMLLog, } // MML 网元MML @@ -27,6 +29,7 @@ type MMLController struct { neInfoService *neService.NeInfo // 网元信息服务 mmlSystemService *service.MMLSystem mmlSubscriberService *service.MMLSubscriber + mmlLogService *service.MMLLog } // SystemList MML网元列表 @@ -47,6 +50,15 @@ func (s MMLController) SubscriberList(c *gin.Context) { c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } +// LogList MML日志列表 +// +// GET /log/list +func (s MMLController) LogList(c *gin.Context) { + query := reqctx.QueryMap(c) + rows, total := s.mmlLogService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} + // Command MML命令执行 // // POST /command @@ -89,6 +101,7 @@ func (s MMLController) Command(c *gin.Context) { } // 发送MML result := []string{} + resultStr := "Success" for _, v := range body.Command { if v == "" { continue @@ -96,9 +109,21 @@ func (s MMLController) Command(c *gin.Context) { output, err := telnetClient.RunCMD(v + "\r\n") if err != nil { result = append(result, err.Error()) + resultStr = "there is an error" continue } result = append(result, strings.TrimSpace(output)) } + + // 记录日志 + mmlLog := model.MMLLog{ + NeType: body.NeType, + NeId: body.NeId, + User: reqctx.LoginUserToUserName(c), + Ip: c.ClientIP(), + Command: strings.Join(body.Command, ";"), + Result: resultStr, + } + s.mmlLogService.Insert(mmlLog) c.JSON(200, resp.OkData(result)) } diff --git a/src/modules/tool/model/mml_log.go b/src/modules/tool/model/mml_log.go new file mode 100644 index 00000000..383a0943 --- /dev/null +++ b/src/modules/tool/model/mml_log.go @@ -0,0 +1,18 @@ +package model + +// MMLLog MML网元命令 +type MMLLog struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + User string `json:"user" gorm:"column:user"` + Ip string `json:"ip" gorm:"column:ip"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeId string `json:"neId" gorm:"column:ne_id"` + Command string `json:"command" gorm:"column:command"` // 命令 + Result string `json:"result" gorm:"column:result"` + LogTime int64 `json:"logTime" gorm:"column:log_time"` +} + +// TableName 表名称 +func (*MMLLog) TableName() string { + return "mml_log" +} diff --git a/src/modules/tool/repository/mml_log.go b/src/modules/tool/repository/mml_log.go new file mode 100644 index 00000000..52422396 --- /dev/null +++ b/src/modules/tool/repository/mml_log.go @@ -0,0 +1,67 @@ +package repository + +import ( + "fmt" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/tool/model" +) + +// 实例化数据层 MMLLog 结构体 +var NewMMLLog = &MMLLog{} + +// MMLLog MML日志 数据层处理 +type MMLLog struct{} + +// SelectByPage 分页查询集合 +func (r MMLLog) SelectByPage(query map[string]string) ([]model.MMLLog, int64) { + tx := db.DB("").Model(&model.MMLLog{}) + // 查询条件拼接 + if v, ok := query["neType"]; ok && v != "" { + tx = tx.Where("ne_type = ?", v) + } + if v, ok := query["beginTime"]; ok && v != "" { + if len(v) == 10 { + v = fmt.Sprintf("%s000", v) + } + tx = tx.Where("log_time >= ?", v) + } + if v, ok := query["endTime"]; ok && v != "" { + if len(v) == 10 { + v = fmt.Sprintf("%s999", v) + } + tx = tx.Where("log_time <= ?", v) + } + + // 查询结果 + var total int64 = 0 + rows := []model.MMLLog{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 查询数据分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error + if err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows, total + } + return rows, total +} + +// Insert 新增信息 返回新增数据ID +func (r MMLLog) Insert(param model.MMLLog) int64 { + param.LogTime = time.Now().UnixMilli() + // 执行插入 + if err := db.DB("").Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.ID +} diff --git a/src/modules/tool/service/mml_log.go b/src/modules/tool/service/mml_log.go new file mode 100644 index 00000000..f7d31cdd --- /dev/null +++ b/src/modules/tool/service/mml_log.go @@ -0,0 +1,26 @@ +package service + +import ( + "be.ems/src/modules/tool/model" + "be.ems/src/modules/tool/repository" +) + +// 实例化数据层 MMLLog 结构体 +var NewMMLLog = &MMLLog{ + mmlLogRepository: repository.NewMMLLog, +} + +// MMLLog MML网元日志 服务层处理 +type MMLLog struct { + mmlLogRepository *repository.MMLLog +} + +// FindByPage 分页查询列表数据 +func (s MMLLog) FindByPage(query map[string]string) ([]model.MMLLog, int64) { + return s.mmlLogRepository.SelectByPage(query) +} + +// Insert 新增日志 +func (s MMLLog) Insert(param model.MMLLog) int64 { + return s.mmlLogRepository.Insert(param) +} diff --git a/src/modules/tool/tool.go b/src/modules/tool/tool.go index de8243d6..355b238d 100644 --- a/src/modules/tool/tool.go +++ b/src/modules/tool/tool.go @@ -67,6 +67,10 @@ func Setup(router *gin.Engine) { middleware.AuthorizeUser(nil), mml.SubscriberList, ) + mmlGroup.GET("/log/list", + middleware.AuthorizeUser(nil), + mml.LogList, + ) mmlGroup.POST("/command", middleware.AuthorizeUser(nil), mml.Command, From cc2c18e75defe03ebd385886b0e52bb3f64903ec Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 5 Aug 2025 17:39:26 +0800 Subject: [PATCH 61/80] =?UTF-8?q?fix:=20=E7=B3=BB=E7=BB=9F=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E8=B4=A6=E5=8F=B7=E7=AE=80=E5=8D=954=E4=BD=8D?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=EF=BC=8C=E5=AF=86=E7=A0=81=E7=AE=80=E5=8D=95?= =?UTF-8?q?6=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_config.sql | 2 +- .../database/lite/upgrade/upg_sys_config.sql | 45 +++++++++++++++++++ build/database/std/install/sys_config.sql | 2 +- build/database/std/upgrade/upg_sys_config.sql | 2 +- src/framework/utils/regular/regular.go | 2 +- src/modules/system/controller/sys_user.go | 2 +- 6 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 build/database/lite/upgrade/upg_sys_config.sql diff --git a/build/database/lite/install/sys_config.sql b/build/database/lite/install/sys_config.sql index 25a0aee7..8daff267 100644 --- a/build/database/lite/install/sys_config.sql +++ b/build/database/lite/install/sys_config.sql @@ -28,7 +28,7 @@ INSERT INTO "sys_config" VALUES (5, 'config.sys.user.lockTime', 'sys.user.lockTi INSERT INTO "sys_config" VALUES (6, 'config.sys.officialUrl', 'sys.officialUrl', '#', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.officialUrlRemark'); INSERT INTO "sys_config" VALUES (7, 'config.sys.helpDoc', 'sys.helpDoc', '/static/helpDoc/{language}_doc.pdf', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.helpDocRemark'); INSERT INTO "sys_config" VALUES (8, 'sys.account.captchaType', 'sys.account.captchaType', 'math', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'sys.account.captchaTypeRemark'); -INSERT INTO "sys_config" VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{"minLength":8,"specialChars":2,"uppercase":1,"lowercase":1}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); +INSERT INTO "sys_config" VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{"minLength":6,"specialChars":0,"uppercase":0,"lowercase":0}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); INSERT INTO "sys_config" VALUES (10, 'config.sys.user.passwdExpire', 'sys.user.passwdExpire', '{"expHours":0,"alertHours":360}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdExpireRemark'); INSERT INTO "sys_config" VALUES (11, 'config.sys.user.fristPasswdChange', 'sys.user.fristPasswdChange', 'false', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.fristPasswdChangeRemark'); INSERT INTO "sys_config" VALUES (12, 'config.sys.user.passwdNotAllowedHistory', 'sys.user.passwdNotAllowedHistory', '0', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdNotAllowedHistoryRemark'); diff --git a/build/database/lite/upgrade/upg_sys_config.sql b/build/database/lite/upgrade/upg_sys_config.sql new file mode 100644 index 00000000..5c378642 --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_config.sql @@ -0,0 +1,45 @@ +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_config" ( + "config_id" integer NOT NULL, + "config_name" text(64), + "config_key" text(64), + "config_value" text(500), + "config_type" text(1), + "del_flag" text(1), + "create_by" text(64), + "create_time" integer, + "update_by" text(64), + "update_time" integer, + "remark" text(500), + PRIMARY KEY ("config_id") +); + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +REPLACE INTO "sys_config" VALUES (1, 'config.sys.user.initPassword', 'sys.user.initPassword', 'Abcd@1234..', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.initPasswordRemark'); +REPLACE INTO "sys_config" VALUES (2, 'config.sys.account.captchaEnabled', 'sys.account.captchaEnabled', 'false', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.account.captchaEnabledRemark'); +REPLACE INTO "sys_config" VALUES (3, 'config.sys.account.registerUser', 'sys.account.registerUser', 'false', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.account.registerUserRemark'); +REPLACE INTO "sys_config" VALUES (4, 'config.sys.user.maxRetryCount', 'sys.user.maxRetryCount', '5', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.maxRetryCountRemark'); +REPLACE INTO "sys_config" VALUES (5, 'config.sys.user.lockTime', 'sys.user.lockTime', '10', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.lockTimeRemark'); +REPLACE INTO "sys_config" VALUES (6, 'config.sys.officialUrl', 'sys.officialUrl', '#', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.officialUrlRemark'); +REPLACE INTO "sys_config" VALUES (7, 'config.sys.helpDoc', 'sys.helpDoc', '/static/helpDoc/{language}_doc.pdf', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.helpDocRemark'); +REPLACE INTO "sys_config" VALUES (8, 'sys.account.captchaType', 'sys.account.captchaType', 'math', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'sys.account.captchaTypeRemark'); +REPLACE INTO "sys_config" VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{"minLength":6,"specialChars":0,"uppercase":0,"lowercase":0}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); +REPLACE INTO "sys_config" VALUES (10, 'config.sys.user.passwdExpire', 'sys.user.passwdExpire', '{"expHours":0,"alertHours":360}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdExpireRemark'); +REPLACE INTO "sys_config" VALUES (11, 'config.sys.user.fristPasswdChange', 'sys.user.fristPasswdChange', 'false', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.fristPasswdChangeRemark'); +REPLACE INTO "sys_config" VALUES (12, 'config.sys.user.passwdNotAllowedHistory', 'sys.user.passwdNotAllowedHistory', '0', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdNotAllowedHistoryRemark'); +REPLACE INTO "sys_config" VALUES (21, 'config.monitor.sysResource.storeDays', 'monitor.sysResource.storeDays', '30', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.monitor.sysResource.storeDaysRemark'); +REPLACE INTO "sys_config" VALUES (22, 'config.sys.logo.type', 'sys.logo.type', 'brand', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.logo.typeRemark'); +REPLACE INTO "sys_config" VALUES (23, 'config.sys.logo.filePathIcon', 'sys.logo.filePathIcon', '/static/logo/{language}_icon.png', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.logo.filePathIconRemark'); +REPLACE INTO "sys_config" VALUES (24, 'config.sys.logo.filePathBrand', 'sys.logo.filePathBrand', '/static/logo/{language}_brand.png', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.logo.filePathBrandRemark'); +REPLACE INTO "sys_config" VALUES (25, 'config.sys.loginBackground', 'sys.loginBackground', '#', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.loginBackgroundRemark'); +REPLACE INTO "sys_config" VALUES (26, 'config.sys.title', 'sys.title', 'config.sys.titleValue', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.titleRemark'); +REPLACE INTO "sys_config" VALUES (27, 'config.sys.copyright', 'sys.copyright', 'config.sys.copyrightValue', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.copyrightRemark'); +REPLACE INTO "sys_config" VALUES (28, 'config.sys.i18nOpen', 'sys.i18n.open', 'true', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.i18nOpenRemark'); +REPLACE INTO "sys_config" VALUES (29, 'config.sys.i18nDefault', 'sys.i18n.default', 'en_US', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.i18nDefaultRemark'); +REPLACE INTO "sys_config" VALUES (30, 'config.sys.lockTime', 'sys.lockTime', '0', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.lockTimeRemark'); +REPLACE INTO "sys_config" VALUES (31, 'config.sys.homePage', 'sys.homePage', 'configManage/neOverview/index', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.homePageRemark'); +REPLACE INTO "sys_config" VALUES (32, 'config.neData.backupDataFTP', 'neData.backupDataFTP', 'VXEECeDMoYhX29pqsb753ecJOnPfxB6XrEa9QdUrRqwKI7EmJei5HlvehvL+wL0Osjo3Y2Qs7ADA6eL3SrisiVXAVVXv38KMhvcSU9eaAzl/jrY4ahsq6a/eSbzxFDgE21US7/YnsyDRG7eGAc7W5Q==', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.neData.backupDataFTPRemark'); diff --git a/build/database/std/install/sys_config.sql b/build/database/std/install/sys_config.sql index 2300c5ef..43ea90f5 100644 --- a/build/database/std/install/sys_config.sql +++ b/build/database/std/install/sys_config.sql @@ -32,7 +32,7 @@ INSERT INTO `sys_config` VALUES (5, 'config.sys.user.lockTime', 'sys.user.lockTi INSERT INTO `sys_config` VALUES (6, 'config.sys.officialUrl', 'sys.officialUrl', '#', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.officialUrlRemark'); INSERT INTO `sys_config` VALUES (7, 'config.sys.helpDoc', 'sys.helpDoc', '/static/helpDoc/{language}_doc.pdf', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.helpDocRemark'); INSERT INTO `sys_config` VALUES (8, 'sys.account.captchaType', 'sys.account.captchaType', 'math', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'sys.account.captchaTypeRemark'); -INSERT INTO `sys_config` VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{\"minLength\":8,\"specialChars\":2,\"uppercase\":1,\"lowercase\":1}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); +INSERT INTO `sys_config` VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{\"minLength\":6,\"specialChars\":0,\"uppercase\":0,\"lowercase\":0}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); INSERT INTO `sys_config` VALUES (10, 'config.sys.user.passwdExpire', 'sys.user.passwdExpire', '{\"expHours\":0,\"alertHours\":360}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdExpireRemark'); INSERT INTO `sys_config` VALUES (11, 'config.sys.user.fristPasswdChange', 'sys.user.fristPasswdChange', 'false', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.fristPasswdChangeRemark'); INSERT INTO `sys_config` VALUES (12, 'config.sys.user.passwdNotAllowedHistory', 'sys.user.passwdNotAllowedHistory', '0', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdNotAllowedHistoryRemark'); diff --git a/build/database/std/upgrade/upg_sys_config.sql b/build/database/std/upgrade/upg_sys_config.sql index b7859ba5..d9236c58 100644 --- a/build/database/std/upgrade/upg_sys_config.sql +++ b/build/database/std/upgrade/upg_sys_config.sql @@ -41,7 +41,7 @@ REPLACE INTO `sys_config` VALUES (5, 'config.sys.user.lockTime', 'sys.user.lockT REPLACE INTO `sys_config` VALUES (6, 'config.sys.officialUrl', 'sys.officialUrl', '#', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.officialUrlRemark'); REPLACE INTO `sys_config` VALUES (7, 'config.sys.helpDoc', 'sys.helpDoc', '/static/helpDoc/{language}_doc.pdf', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.helpDocRemark'); REPLACE INTO `sys_config` VALUES (8, 'sys.account.captchaType', 'sys.account.captchaType', 'math', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'sys.account.captchaTypeRemark'); -REPLACE INTO `sys_config` VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{\"minLength\":8,\"specialChars\":2,\"uppercase\":1,\"lowercase\":1}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); +REPLACE INTO `sys_config` VALUES (9, 'config.sys.user.passwordPolicy', 'sys.user.passwordPolicy', '{\"minLength\":6,\"specialChars\":0,\"uppercase\":0,\"lowercase\":0}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwordPolicyRemark'); REPLACE INTO `sys_config` VALUES (10, 'config.sys.user.passwdExpire', 'sys.user.passwdExpire', '{\"expHours\":0,\"alertHours\":360}', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdExpireRemark'); REPLACE INTO `sys_config` VALUES (11, 'config.sys.user.fristPasswdChange', 'sys.user.fristPasswdChange', 'false', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.fristPasswdChangeRemark'); REPLACE INTO `sys_config` VALUES (12, 'config.sys.user.passwdNotAllowedHistory', 'sys.user.passwdNotAllowedHistory', '0', 'Y', '0', 'system', 1704960008300, 'system', 1704960008300, 'config.sys.user.passwdNotAllowedHistoryRemark'); diff --git a/src/framework/utils/regular/regular.go b/src/framework/utils/regular/regular.go index 3eeb31c6..c3804698 100644 --- a/src/framework/utils/regular/regular.go +++ b/src/framework/utils/regular/regular.go @@ -19,7 +19,7 @@ func ValidUsername(username string) bool { if username == "" { return false } - pattern := `^[a-zA-Z][a-z0-9A-Z]{5,}` + pattern := `^.{4,}$` //`^[a-zA-Z][a-z0-9A-Z]{5,}` match, err := regexp.MatchString(pattern, username) if err != nil { return false diff --git a/src/modules/system/controller/sys_user.go b/src/modules/system/controller/sys_user.go index 60758dc3..3ea14fef 100644 --- a/src/modules/system/controller/sys_user.go +++ b/src/modules/system/controller/sys_user.go @@ -186,7 +186,7 @@ func (s *SysUserController) Add(c *gin.Context) { } if !regular.ValidUsername(body.UserName) { // msg := fmt.Sprintf("新增用户【%s】失败,登录账号用户账号只能包含大写小写字母,数字,且不少于4位", body.UserName) - msg := fmt.Sprintf("Add a new user [%s] failed to log in the account user account can only contain upper and lower case letters, numbers, and not less than 4 digits", body.UserName) + msg := fmt.Sprintf("Add a new user [%s] failed to log in the account user account not less than 4 digits", body.UserName) c.JSON(400, resp.ErrMsg(msg)) return } From fc4309136e4c8564934257af5a1a5cba21ac81fa Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 5 Aug 2025 17:39:40 +0800 Subject: [PATCH 62/80] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E9=87=8D=E5=A4=8D=E8=AE=B0=E5=BD=95=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E4=BF=A1=E6=81=AF=E5=B9=B6=E8=B7=B3=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/database/db/expand.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/framework/database/db/expand.go b/src/framework/database/db/expand.go index 209c4eea..e17d3ddb 100644 --- a/src/framework/database/db/expand.go +++ b/src/framework/database/db/expand.go @@ -103,6 +103,10 @@ func processSQLFile(db *gorm.DB, filePath string) { } else if strings.Contains(errorStr, "duplicate key") { // 忽略重复索引错误 // Error 1061 (42000): Duplicate key name 'key_name' + } else if strings.Contains(errorStr, "duplicate entry") { + // 忽略重复记录错误 + // Error 1062 (23000): Duplicate entry 'value' for key 'key_name' + log.Println(errorStr) } else if strings.Contains(errorStr, "unknown column") { // 忽略未知字段错误 // Error 1054 (42S22): Unknown column 'field_name' in 'table' From 581fc441e0c7802f4eb0cc016dd127cdd36f2c03 Mon Sep 17 00:00:00 2001 From: zhangsz Date: Wed, 6 Aug 2025 12:03:03 +0800 Subject: [PATCH 63/80] fix: issue update event post old message to CBC --- .../network_data/repository/cbc_message.go | 36 ++++++++++++++----- .../network_data/service/cbc_message.go | 6 ++-- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/modules/network_data/repository/cbc_message.go b/src/modules/network_data/repository/cbc_message.go index d7c09198..f37c9866 100644 --- a/src/modules/network_data/repository/cbc_message.go +++ b/src/modules/network_data/repository/cbc_message.go @@ -157,18 +157,36 @@ func (s *CBCMessage) SelectByEventName(eventName string) (*model.CBCMessage, err // @return error 错误信息 // @example // mfCBCMessageService.UpdateCBCMessage(msg) -func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error { +func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) (*model.CBCMessage, error) { + var msg model.CBCMessage now := time.Now().UnixMilli() - if err := db.DB("").Table("cbc_message"). - Where("id = ?", id). - Updates(map[string]any{ - "message_json": messageJson, - "updated_at": now, - }).Error; err != nil { - return fmt.Errorf("failed to update CBC message: %w", err) + + err := db.DB("").Transaction(func(tx *gorm.DB) error { + // 在事务中更新 + if err := tx.Table("cbc_message"). + Where("id = ?", id). + Updates(map[string]any{ + "message_json": messageJson, + "updated_at": now, + }).Error; err != nil { + return fmt.Errorf("failed to update CBC message: %w", err) + } + + // 在事务中查询更新后的记录 + if err := tx.Table("cbc_message"). + Where("id = ?", id). + First(&msg).Error; err != nil { + return fmt.Errorf("failed to fetch updated CBC message: %w", err) + } + + return nil + }) + + if err != nil { + return nil, err } - return nil + return &msg, nil } // UpdateCBCMessage 更新CB消息 diff --git a/src/modules/network_data/service/cbc_message.go b/src/modules/network_data/service/cbc_message.go index 1772faa7..c5aad39c 100644 --- a/src/modules/network_data/service/cbc_message.go +++ b/src/modules/network_data/service/cbc_message.go @@ -90,8 +90,7 @@ func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error { // 检查是否已存在相同的eventName var err error - var msg *model.CBCMessage - if msg, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil { + if _, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil { if err == gorm.ErrRecordNotFound { return fmt.Errorf("no existing CBC message found with eventName: %s", eventName) } @@ -99,7 +98,8 @@ func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error { } // 如果存在,更新记录 - if err := s.cbcMessageRepository.Update(id, messageJson); err != nil { + var msg *model.CBCMessage + if msg, err = s.cbcMessageRepository.Update(id, messageJson); err != nil { return fmt.Errorf("failed to update CBC message: %w", err) } From 26fde7f1cae110285457acd36a47e62a9d856e76 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 7 Aug 2025 11:35:12 +0800 Subject: [PATCH 64/80] =?UTF-8?q?fix:=20=E8=87=AA=E5=AE=9A=E4=B9=89KPI?= =?UTF-8?q?=E8=AE=A1=E7=AE=97NaN=E5=AF=BC=E8=87=B4=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8C=96=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/service/kpi.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/modules/oam/service/kpi.go b/src/modules/oam/service/kpi.go index 3a3766bf..d5e82ad6 100644 --- a/src/modules/oam/service/kpi.go +++ b/src/modules/oam/service/kpi.go @@ -3,6 +3,7 @@ package service import ( "encoding/json" "fmt" + "math" "time" "be.ems/src/framework/utils/date" @@ -91,7 +92,10 @@ func (s *KPI) saveKPIData(k oam.KPI, index int64) error { KpiValues = append(KpiValues, item) } - KpiValuesByte, _ := json.Marshal(KpiValues) + KpiValuesByte, err := json.Marshal(KpiValues) + if err != nil { + return err + } // KPI 信息 kpiData := neDataModel.KpiReport{ @@ -180,13 +184,13 @@ func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { } else { if v.Unit == "%" { resultV, ok := result.(float64) - if !ok { + if !ok || math.IsNaN(resultV) { resultV = 0 } if resultV > 100 { result = 100 } - if resultV < 0 { + if resultV <= 0 { result = 0 } } @@ -195,7 +199,10 @@ func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { } KpiValues = append(KpiValues, item) } - KpiValuesByte, _ := json.Marshal(KpiValues) + KpiValuesByte, err := json.Marshal(KpiValues) + if err != nil { + return err + } // KPI 信息 kpiCData := neDataModel.KpiCReport{ From 7b2f8359354dfb7e9626ac864b90992290daaa15 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 8 Aug 2025 12:13:03 +0800 Subject: [PATCH 65/80] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2508.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index daaf8d90..2761ca88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # 版本发布日志 +## 2.2508.1-20250808 + +- 修复 MML类型object_type初始值mml更新General,MML日志记录功能接口 +- 修复 UDM签约缺失rfsp和usagetype参数修改 +- 修复 MML命令执行回车\r\n ,特殊IMS无法输出问题 +- 修复 基站状态记录时间变更查询字段create_time +- 优化 系统用户账号简单4位长度,密码简单6位 +- 修复 更新数据库重复记录错误输出信息并跳过 +- 修复 自定义KPI计算NaN导致序列化失败 + ## 2.2507.4-20250801 - 修复 密码强制修改非首次登录校验去除日期判断,补充参数说明翻译信息 From 05399474718fce84b973fd55a1148855b5599be9 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 8 Aug 2025 18:28:39 +0800 Subject: [PATCH 66/80] =?UTF-8?q?style:=20=E5=91=8A=E8=AD=A6=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=AD=97=E5=85=B8=E5=80=BC=E4=BF=AE=E6=AD=A3=E4=B8=BA?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_dict_data.sql | 4 ++-- build/database/lite/upgrade/upg_sys_dict_data.sql | 4 ++-- build/database/std/install/sys_dict_data.sql | 4 ++-- build/database/std/upgrade/upg_sys_dict_data.sql | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/database/lite/install/sys_dict_data.sql b/build/database/lite/install/sys_dict_data.sql index de9062dc..6833a738 100644 --- a/build/database/lite/install/sys_dict_data.sql +++ b/build/database/lite/install/sys_dict_data.sql @@ -53,8 +53,8 @@ INSERT INTO "sys_dict_data" VALUES (27, 'trace_type', 'dictData.trace.user', '3' INSERT INTO "sys_dict_data" VALUES (28, 'sys_job_save_log', 'dictData.jobSaveLog.no', '0', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (29, 'sys_job_save_log', 'dictData.jobSaveLog.yes', '1', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (30, 'ne_host_type', 'dictData.ne_host_type.redis', 'redis', 2, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', '0', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO "sys_dict_data" VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', '1', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', 'Clear', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', 'Active', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (33, 'sys_role_datascope', 'dictData.datascope.all', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (34, 'sys_role_datascope', 'dictData.datascope.custom', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/lite/upgrade/upg_sys_dict_data.sql b/build/database/lite/upgrade/upg_sys_dict_data.sql index 5cc0ad84..21634cef 100644 --- a/build/database/lite/upgrade/upg_sys_dict_data.sql +++ b/build/database/lite/upgrade/upg_sys_dict_data.sql @@ -52,8 +52,8 @@ REPLACE INTO "sys_dict_data" VALUES (27, 'trace_type', 'dictData.trace.user', '3 REPLACE INTO "sys_dict_data" VALUES (28, 'sys_job_save_log', 'dictData.jobSaveLog.no', '0', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (29, 'sys_job_save_log', 'dictData.jobSaveLog.yes', '1', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (30, 'ne_host_type', 'dictData.ne_host_type.redis', 'redis', 2, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO "sys_dict_data" VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', '0', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO "sys_dict_data" VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', '1', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', 'Clear', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', 'Active', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (33, 'sys_role_datascope', 'dictData.datascope.all', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (34, 'sys_role_datascope', 'dictData.datascope.custom', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/std/install/sys_dict_data.sql b/build/database/std/install/sys_dict_data.sql index 160440f2..3555e337 100644 --- a/build/database/std/install/sys_dict_data.sql +++ b/build/database/std/install/sys_dict_data.sql @@ -56,8 +56,8 @@ INSERT INTO `sys_dict_data` VALUES (27, 'trace_type', 'dictData.trace.user', '3' INSERT INTO `sys_dict_data` VALUES (28, 'sys_job_save_log', 'dictData.jobSaveLog.no', '0', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (29, 'sys_job_save_log', 'dictData.jobSaveLog.yes', '1', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (30, 'ne_host_type', 'dictData.ne_host_type.redis', 'redis', 2, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', '0', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -INSERT INTO `sys_dict_data` VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', '1', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', 'Clear', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', 'Active', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (33, 'sys_role_datascope', 'dictData.datascope.all', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (34, 'sys_role_datascope', 'dictData.datascope.custom', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/std/upgrade/upg_sys_dict_data.sql b/build/database/std/upgrade/upg_sys_dict_data.sql index 20af7de4..4d078c0b 100644 --- a/build/database/std/upgrade/upg_sys_dict_data.sql +++ b/build/database/std/upgrade/upg_sys_dict_data.sql @@ -60,8 +60,8 @@ REPLACE INTO `sys_dict_data` VALUES (27, 'trace_type', 'dictData.trace.user', '3 REPLACE INTO `sys_dict_data` VALUES (28, 'sys_job_save_log', 'dictData.jobSaveLog.no', '0', 8, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (29, 'sys_job_save_log', 'dictData.jobSaveLog.yes', '1', 9, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (30, 'ne_host_type', 'dictData.ne_host_type.redis', 'redis', 2, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', '0', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); -REPLACE INTO `sys_dict_data` VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', '1', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (31, 'alarm_status', 'dictData.alarmStatus.history', 'Clear', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (32, 'alarm_status', 'dictData.alarmStatus.active', 'Active', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (33, 'sys_role_datascope', 'dictData.datascope.all', '1', 1, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (34, 'sys_role_datascope', 'dictData.datascope.custom', '2', 2, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (35, 'sys_role_datascope', 'dictData.datascope.dept', '3', 3, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); From c0f5ea000369d3f0c3c8331bb1ed3d4cd2a02041 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 8 Aug 2025 18:30:03 +0800 Subject: [PATCH 67/80] =?UTF-8?q?feat:=20=E5=91=8A=E8=AD=A6=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=9F=A5=E8=AF=A2=E8=A1=A5=E5=85=85=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/repository/alarm_log.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/network_data/repository/alarm_log.go b/src/modules/network_data/repository/alarm_log.go index 1ee20cec..5008241f 100644 --- a/src/modules/network_data/repository/alarm_log.go +++ b/src/modules/network_data/repository/alarm_log.go @@ -24,6 +24,9 @@ func (r AlarmLog) SelectByPage(query model.AlarmLogQuery) ([]model.AlarmLog, int if query.NeID != "" { tx = tx.Where("ne_id = ?", query.NeID) } + if query.AlarmStatus != "" { + tx = tx.Where("alarm_status = ?", query.AlarmStatus) + } if query.BeginTime != 0 { tx = tx.Where("created_at >= ?", query.BeginTime) } From b7e4948fbbd0e578e5ca3980d6432634acc6200b Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 8 Aug 2025 19:17:09 +0800 Subject: [PATCH 68/80] =?UTF-8?q?fix:=20cdr/ue=E6=9F=A5=E8=AF=A2=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E5=AD=97=E6=AE=B5=E6=94=B9=E7=94=A8=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E6=97=B6=E9=97=B4=EF=BC=8C=E4=BC=A0=E5=85=A5=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=97=B6=E5=8C=BAUTC0=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E6=AD=A3=E5=B8=B8=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/repository/cdr_event.go | 4 ++-- src/modules/network_data/repository/ue_event.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/network_data/repository/cdr_event.go b/src/modules/network_data/repository/cdr_event.go index 4ce8532e..0123ea0b 100644 --- a/src/modules/network_data/repository/cdr_event.go +++ b/src/modules/network_data/repository/cdr_event.go @@ -29,13 +29,13 @@ func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model. if len(v) == 10 { v = v + "000" } - tx = tx.Where("timestamp >= ?", v) + tx = tx.Where("created_at >= ?", v) } if v, ok := query["endTime"]; ok && v != "" { if len(v) == 10 { v = v + "000" } - tx = tx.Where("timestamp <= ?", v) + tx = tx.Where("created_at <= ?", v) } // 各个网元特殊查询条件 diff --git a/src/modules/network_data/repository/ue_event.go b/src/modules/network_data/repository/ue_event.go index d06730f7..e026e7eb 100644 --- a/src/modules/network_data/repository/ue_event.go +++ b/src/modules/network_data/repository/ue_event.go @@ -29,13 +29,13 @@ func (r UEEvent) SelectByPage(neType string, query map[string]string) ([]model.U if len(v) == 10 { v = v + "000" } - tx = tx.Where("timestamp >= ?", v) + tx = tx.Where("created_at >= ?", v) } if v, ok := query["endTime"]; ok && v != "" { if len(v) == 10 { v = v + "000" } - tx = tx.Where("timestamp <= ?", v) + tx = tx.Where("created_at <= ?", v) } if v, ok := query["eventType"]; ok && v != "" { eventTypes := strings.Split(v, ",") From 9e57c145d1198ac539eff02e4aead063bc3bee59 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:12:46 +0800 Subject: [PATCH 69/80] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E7=99=BB=E5=BD=95=E8=AE=A4=E8=AF=81=E5=92=8C?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/common/mml_command.sql | 8 - build/database/lite/install/cbc_message.sql | 34 +-- build/database/lite/install/sys_dict_data.sql | 4 + build/database/lite/install/sys_dict_type.sql | 1 + build/database/lite/install/sys_i18n.sql | 44 ++-- .../lite/install/sys_login_source.sql | 33 +++ build/database/lite/install/sys_menu.sql | 5 + build/database/lite/install/sys_role_menu.sql | 44 ++-- build/database/lite/install/sys_user.sql | 10 +- .../database/lite/upgrade/upg_cbc_message.sql | 31 ++- .../lite/upgrade/upg_sys_dict_data.sql | 4 + .../lite/upgrade/upg_sys_dict_type.sql | 54 +++++ build/database/lite/upgrade/upg_sys_i18n.sql | 44 ++-- .../lite/upgrade/upg_sys_login_source.sql | 32 +++ build/database/lite/upgrade/upg_sys_menu.sql | 5 + .../lite/upgrade/upg_sys_role_menu.sql | 45 ++-- build/database/lite/upgrade/upg_sys_user.sql | 46 ++++ build/database/std/common/mml_command.sql | 26 +-- build/database/std/install/cbc_message.sql | 44 +--- build/database/std/install/sys_dict_data.sql | 4 + build/database/std/install/sys_dict_type.sql | 1 + build/database/std/install/sys_i18n.sql | 8 + .../database/std/install/sys_login_source.sql | 24 ++ build/database/std/install/sys_menu.sql | 5 + build/database/std/install/sys_role_menu.sql | 50 ++--- build/database/std/install/sys_user.sql | 18 +- .../database/std/upgrade/upg_cbc_message.sql | 44 +--- .../std/upgrade/upg_sys_dict_data.sql | 4 + .../std/upgrade/upg_sys_dict_type.sql | 1 + build/database/std/upgrade/upg_sys_i18n.sql | 8 + .../std/upgrade/upg_sys_login_source.sql | 23 ++ build/database/std/upgrade/upg_sys_menu.sql | 5 + .../std/upgrade/upg_sys_role_menu.sql | 51 ++--- build/database/std/upgrade/upg_sys_user.sql | 20 +- src/modules/auth/auth.go | 62 +++++- src/modules/auth/controller/account.go | 172 +-------------- src/modules/auth/controller/account_info.go | 93 ++++++++ src/modules/auth/controller/account_ldap.go | 80 +++++++ src/modules/auth/controller/account_oauth2.go | 107 +++++++++ src/modules/auth/controller/account_smtp.go | 80 +++++++ src/modules/auth/controller/account_system.go | 104 +++++++++ src/modules/auth/model/login_body.go | 15 +- src/modules/auth/model/login_source_vo.go | 22 ++ src/modules/auth/model/register_body.go | 23 +- src/modules/auth/service/account.go | 205 ++++-------------- src/modules/auth/service/account_info.go | 36 +++ src/modules/auth/service/account_ldap.go | 108 +++++++++ src/modules/auth/service/account_oauth2.go | 168 ++++++++++++++ src/modules/auth/service/account_smtp.go | 88 ++++++++ src/modules/auth/service/account_sysstem.go | 138 ++++++++++++ src/modules/auth/service/register.go | 10 +- .../controller/sys_login_source.go} | 107 +++++---- src/modules/system/controller/sys_user.go | 33 ++- src/modules/system/model/sys_login_source.go | 22 ++ src/modules/system/model/sys_user.go | 2 + src/modules/system/model/vo/login_source.go | 28 +++ .../system/repository/sys_login_source.go | 150 +++++++++++++ src/modules/system/repository/sys_menu.go | 10 +- src/modules/system/repository/sys_user.go | 22 +- .../system/service/sys_login_source.go | 95 ++++++++ src/modules/system/service/sys_user.go | 18 +- src/modules/system/system.go | 29 +++ 62 files changed, 2086 insertions(+), 721 deletions(-) create mode 100644 build/database/lite/install/sys_login_source.sql create mode 100644 build/database/lite/upgrade/upg_sys_dict_type.sql create mode 100644 build/database/lite/upgrade/upg_sys_login_source.sql create mode 100644 build/database/lite/upgrade/upg_sys_user.sql create mode 100644 build/database/std/install/sys_login_source.sql create mode 100644 build/database/std/upgrade/upg_sys_login_source.sql create mode 100644 src/modules/auth/controller/account_info.go create mode 100644 src/modules/auth/controller/account_ldap.go create mode 100644 src/modules/auth/controller/account_oauth2.go create mode 100644 src/modules/auth/controller/account_smtp.go create mode 100644 src/modules/auth/controller/account_system.go create mode 100644 src/modules/auth/model/login_source_vo.go create mode 100644 src/modules/auth/service/account_info.go create mode 100644 src/modules/auth/service/account_ldap.go create mode 100644 src/modules/auth/service/account_oauth2.go create mode 100644 src/modules/auth/service/account_smtp.go create mode 100644 src/modules/auth/service/account_sysstem.go rename src/modules/{oauth2/controller/oauth2_client.go => system/controller/sys_login_source.go} (51%) create mode 100644 src/modules/system/model/sys_login_source.go create mode 100644 src/modules/system/model/vo/login_source.go create mode 100644 src/modules/system/repository/sys_login_source.go create mode 100644 src/modules/system/service/sys_login_source.go diff --git a/build/database/lite/common/mml_command.sql b/build/database/lite/common/mml_command.sql index 0a21cf1e..c87dafd8 100644 --- a/build/database/lite/common/mml_command.sql +++ b/build/database/lite/common/mml_command.sql @@ -15,14 +15,6 @@ CREATE TABLE "mml_command" ( PRIMARY KEY ("id") ); --- ---------------------------- --- Indexes structure for table mml_command --- ---------------------------- -CREATE INDEX "id" -ON "mml_command" ( - "id" ASC -); - -- ---------------------------- -- Records of mml_command -- ---------------------------- diff --git a/build/database/lite/install/cbc_message.sql b/build/database/lite/install/cbc_message.sql index 4f6d38c6..956983db 100755 --- a/build/database/lite/install/cbc_message.sql +++ b/build/database/lite/install/cbc_message.sql @@ -1,21 +1,25 @@ -- ---------------------------- -- 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, - `updated_at` INTEGER +CREATE TABLE "cbc_message" ( + "id" integer NOT NULL, + "ne_type" text(32), + "ne_id" text(32), + "message_json" text(10240), + "status" text(32), + "detail" text(255), + "created_at" integer, + "updated_at" integer, + PRIMARY KEY ("id") ); --- Create indexes -CREATE INDEX `idx_id` ON `cbc_message`(`id`); -CREATE INDEX `idx_ne_time` ON `cbc_message`(`ne_type`, `ne_id`, `created_at`); +-- ---------------------------- +-- Indexes structure for table cbc_message +-- ---------------------------- +CREATE INDEX "idx_cbcm_ne_time" +ON "cbc_message" ( + "ne_type" ASC, + "ne_id" ASC, + "created_at" ASC +); diff --git a/build/database/lite/install/sys_dict_data.sql b/build/database/lite/install/sys_dict_data.sql index 6833a738..c879e3eb 100644 --- a/build/database/lite/install/sys_dict_data.sql +++ b/build/database/lite/install/sys_dict_data.sql @@ -192,4 +192,8 @@ INSERT INTO "sys_dict_data" VALUES (166, 'cdr_sip_code_cause', 'dictData.cdr_sip INSERT INTO "sys_dict_data" VALUES (167, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.606', '606', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (168, 'trace_interfaces', 'dictData.trace_interfaces.14', 'N14', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_data" VALUES (169, 'trace_interfaces', 'dictData.trace_interfaces.5', 'N5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (170, 'sys_user_type', 'dictData.sys_user_type.system', 'System', 1, '', 'default', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (171, 'sys_user_type', 'dictData.sys_user_type.ldap', 'LDAP', 2, '', 'lime', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (172, 'sys_user_type', 'dictData.sys_user_type.smtp', 'SMTP', 3, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO "sys_dict_data" VALUES (173, 'sys_user_type', 'dictData.sys_user_type.oauth2', 'OAuth2', 4, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/lite/install/sys_dict_type.sql b/build/database/lite/install/sys_dict_type.sql index 30bb5f99..39b564de 100644 --- a/build/database/lite/install/sys_dict_type.sql +++ b/build/database/lite/install/sys_dict_type.sql @@ -27,6 +27,7 @@ INSERT INTO "sys_dict_type" VALUES (5, 'dictType.sys_job_group', 'sys_job_group' INSERT INTO "sys_dict_type" VALUES (6, 'dictType.sys_yes_no', 'sys_yes_no', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_yes_no_remark'); INSERT INTO "sys_dict_type" VALUES (9, 'dictType.sys_oper_type', 'sys_oper_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_oper_type_remark'); INSERT INTO "sys_dict_type" VALUES (10, 'dictType.sys_common_status', 'sys_common_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_common_status_remark'); +INSERT INTO "sys_dict_type" VALUES (11, 'dictType.sys_user_type', 'sys_user_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO "sys_dict_type" VALUES (50, 'dictType.trace_type', 'trace_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.trace_type_remark'); INSERT INTO "sys_dict_type" VALUES (51, 'dictType.alarm_status', 'alarm_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.alarm_status_remark'); INSERT INTO "sys_dict_type" VALUES (52, 'dictType.ne_version_status', 'ne_version_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.ne_version_status_remark'); diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index 95ce5ffb..2e440a15 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -933,22 +933,30 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); +INSERT INTO "sys_i18n" VALUES (761, "dictType.sys_user_type", "用户类型", "User Type"); +INSERT INTO "sys_i18n" VALUES (762, "dictData.sys_user_type.system", "系统", "System"); +INSERT INTO "sys_i18n" VALUES (763, "dictData.sys_user_type.ldap", "LDAP", "LDAP"); +INSERT INTO "sys_i18n" VALUES (764, "dictData.sys_user_type.smtp", "SMTP", "SMTP"); +INSERT INTO "sys_i18n" VALUES (765, "dictData.sys_user_type.oauth2", "OAuth2", "OAuth2"); +INSERT INTO "sys_i18n" VALUES (766, "user.export.userType", "用户类型", "User Type"); +INSERT INTO "sys_i18n" VALUES (767, "menu.system.loginSource", "第三方登录认证", "Third Party Login Source"); +INSERT INTO "sys_i18n" VALUES (768, "log.operate.title.sysLoginSource", "认证源", "Login Source"); -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', '预警广播', 'Early Warning Broadcast'); -INSERT INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); +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', '预警广播', 'Early Warning Broadcast'); +INSERT INTO "sys_i18n" VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); diff --git a/build/database/lite/install/sys_login_source.sql b/build/database/lite/install/sys_login_source.sql new file mode 100644 index 00000000..fd9c6e99 --- /dev/null +++ b/build/database/lite/install/sys_login_source.sql @@ -0,0 +1,33 @@ +-- ---------------------------- +-- Table structure for sys_login_source +-- ---------------------------- +DROP TABLE IF EXISTS "sys_login_source"; +CREATE TABLE "sys_login_source" ( + "id" integer NOT NULL, + "uid" text(32), + "type" text(32), + "name" text(64), + "icon" text(255), + "active_flag" text(1), + "sync_flag" text(1), + "config" text, + "create_by" text(64), + "create_time" integer, + "update_by" text(64), + "update_time" integer, + "remark" text(500), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Indexes structure for table sys_login_source +-- ---------------------------- +CREATE INDEX "idx_ls_type_name" +ON "sys_login_source" ( + "type" ASC, + "name" ASC +); + +-- ---------------------------- +-- Records of sys_login_source +-- ---------------------------- diff --git a/build/database/lite/install/sys_menu.sql b/build/database/lite/install/sys_menu.sql index 3e7e61d2..fd8bd697 100644 --- a/build/database/lite/install/sys_menu.sql +++ b/build/database/lite/install/sys_menu.sql @@ -47,6 +47,7 @@ INSERT INTO "sys_menu" VALUES (105, 'menu.security.post', 2113, 6, 'post', 'syst INSERT INTO "sys_menu" VALUES (106, 'menu.system.dictType', 1, 30, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.dictTypeRemark'); INSERT INTO "sys_menu" VALUES (107, 'menu.system.dictData', 1, 31, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.dictDataRemark'); INSERT INTO "sys_menu" VALUES (108, 'menu.system.paramSet', 1, 59, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.paramSetRemark'); +INSERT INTO "sys_menu" VALUES (109, 'menu.system.loginSource', 2113, 12, 'login-source', 'system/login-source/index', '1', '1', 'M', '1', '1', 'system:loginSource:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (111, 'menu.system.systemLog', 1, 11, 'log', '', '1', '1', 'D', '0', '0', '', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemLogRemark'); INSERT INTO "sys_menu" VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemInfoRemark'); INSERT INTO "sys_menu" VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.cacheInfoRemark'); @@ -109,6 +110,10 @@ INSERT INTO "sys_menu" VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', ' INSERT INTO "sys_menu" VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (1057, 'menu.common.query', 109, 1, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:query', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (1058, 'menu.common.add', 109, 2, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:add', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (1059, 'menu.common.edit', 109, 3, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:edit', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (1060, 'menu.common.delete', 109, 4, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/lite/install/sys_role_menu.sql b/build/database/lite/install/sys_role_menu.sql index 15dc94cf..127372ce 100644 --- a/build/database/lite/install/sys_role_menu.sql +++ b/build/database/lite/install/sys_role_menu.sql @@ -3,8 +3,8 @@ -- ---------------------------- DROP TABLE IF EXISTS "sys_role_menu"; CREATE TABLE "sys_role_menu" ( - "role_id" integer(20) NOT NULL, - "menu_id" integer(20) NOT NULL, + "role_id" integer NOT NULL, + "menu_id" integer NOT NULL, PRIMARY KEY ("role_id", "menu_id") ); @@ -27,6 +27,7 @@ INSERT INTO "sys_role_menu" VALUES (2, 103); INSERT INTO "sys_role_menu" VALUES (2, 104); INSERT INTO "sys_role_menu" VALUES (2, 105); INSERT INTO "sys_role_menu" VALUES (2, 108); +INSERT INTO "sys_role_menu" VALUES (2, 109); INSERT INTO "sys_role_menu" VALUES (2, 111); INSERT INTO "sys_role_menu" VALUES (2, 112); INSERT INTO "sys_role_menu" VALUES (2, 115); @@ -63,10 +64,8 @@ INSERT INTO "sys_role_menu" VALUES (2, 1030); INSERT INTO "sys_role_menu" VALUES (2, 1032); INSERT INTO "sys_role_menu" VALUES (2, 1034); INSERT INTO "sys_role_menu" VALUES (2, 1039); -INSERT INTO "sys_role_menu" VALUES (2, 1040); INSERT INTO "sys_role_menu" VALUES (2, 1041); INSERT INTO "sys_role_menu" VALUES (2, 1042); -INSERT INTO "sys_role_menu" VALUES (2, 1043); INSERT INTO "sys_role_menu" VALUES (2, 1044); INSERT INTO "sys_role_menu" VALUES (2, 1045); INSERT INTO "sys_role_menu" VALUES (2, 1048); @@ -78,6 +77,10 @@ INSERT INTO "sys_role_menu" VALUES (2, 1053); INSERT INTO "sys_role_menu" VALUES (2, 1054); INSERT INTO "sys_role_menu" VALUES (2, 1055); INSERT INTO "sys_role_menu" VALUES (2, 1056); +INSERT INTO "sys_role_menu" VALUES (2, 1057); +INSERT INTO "sys_role_menu" VALUES (2, 1058); +INSERT INTO "sys_role_menu" VALUES (2, 1059); +INSERT INTO "sys_role_menu" VALUES (2, 1060); INSERT INTO "sys_role_menu" VALUES (2, 2000); INSERT INTO "sys_role_menu" VALUES (2, 2001); INSERT INTO "sys_role_menu" VALUES (2, 2002); @@ -168,7 +171,6 @@ INSERT INTO "sys_role_menu" VALUES (3, 65); INSERT INTO "sys_role_menu" VALUES (3, 66); INSERT INTO "sys_role_menu" VALUES (3, 108); INSERT INTO "sys_role_menu" VALUES (3, 112); -INSERT INTO "sys_role_menu" VALUES (3, 115); INSERT INTO "sys_role_menu" VALUES (3, 500); INSERT INTO "sys_role_menu" VALUES (3, 501); INSERT INTO "sys_role_menu" VALUES (3, 1030); @@ -176,7 +178,6 @@ INSERT INTO "sys_role_menu" VALUES (3, 1032); INSERT INTO "sys_role_menu" VALUES (3, 1034); INSERT INTO "sys_role_menu" VALUES (3, 1039); INSERT INTO "sys_role_menu" VALUES (3, 1042); -INSERT INTO "sys_role_menu" VALUES (3, 1048); INSERT INTO "sys_role_menu" VALUES (3, 2000); INSERT INTO "sys_role_menu" VALUES (3, 2001); INSERT INTO "sys_role_menu" VALUES (3, 2002); @@ -189,6 +190,7 @@ INSERT INTO "sys_role_menu" VALUES (3, 2009); INSERT INTO "sys_role_menu" VALUES (3, 2010); INSERT INTO "sys_role_menu" VALUES (3, 2011); INSERT INTO "sys_role_menu" VALUES (3, 2083); +INSERT INTO "sys_role_menu" VALUES (3, 2084); INSERT INTO "sys_role_menu" VALUES (3, 2086); INSERT INTO "sys_role_menu" VALUES (3, 2087); INSERT INTO "sys_role_menu" VALUES (3, 2088); @@ -200,10 +202,12 @@ INSERT INTO "sys_role_menu" VALUES (3, 2097); INSERT INTO "sys_role_menu" VALUES (3, 2107); INSERT INTO "sys_role_menu" VALUES (3, 2108); INSERT INTO "sys_role_menu" VALUES (3, 2109); -INSERT INTO "sys_role_menu" VALUES (3, 2113); +INSERT INTO "sys_role_menu" VALUES (3, 2112); INSERT INTO "sys_role_menu" VALUES (3, 2114); INSERT INTO "sys_role_menu" VALUES (3, 2115); INSERT INTO "sys_role_menu" VALUES (3, 2116); +INSERT INTO "sys_role_menu" VALUES (3, 2118); +INSERT INTO "sys_role_menu" VALUES (3, 2122); INSERT INTO "sys_role_menu" VALUES (3, 2123); INSERT INTO "sys_role_menu" VALUES (3, 2126); INSERT INTO "sys_role_menu" VALUES (3, 2128); @@ -224,11 +228,10 @@ INSERT INTO "sys_role_menu" VALUES (3, 2149); INSERT INTO "sys_role_menu" VALUES (3, 2151); INSERT INTO "sys_role_menu" VALUES (3, 2152); INSERT INTO "sys_role_menu" VALUES (3, 2153); -INSERT INTO "sys_role_menu" VALUES (3, 2154); -INSERT INTO "sys_role_menu" VALUES (3, 2155); -INSERT INTO "sys_role_menu" VALUES (3, 2156); INSERT INTO "sys_role_menu" VALUES (3, 2157); INSERT INTO "sys_role_menu" VALUES (3, 2158); +INSERT INTO "sys_role_menu" VALUES (3, 2162); +INSERT INTO "sys_role_menu" VALUES (3, 2163); INSERT INTO "sys_role_menu" VALUES (3, 2165); INSERT INTO "sys_role_menu" VALUES (3, 2166); INSERT INTO "sys_role_menu" VALUES (3, 2167); @@ -238,9 +241,6 @@ INSERT INTO "sys_role_menu" VALUES (3, 20000); INSERT INTO "sys_role_menu" VALUES (4, 1); INSERT INTO "sys_role_menu" VALUES (4, 4); -INSERT INTO "sys_role_menu" VALUES (4, 60); -INSERT INTO "sys_role_menu" VALUES (4, 65); -INSERT INTO "sys_role_menu" VALUES (4, 66); INSERT INTO "sys_role_menu" VALUES (4, 112); INSERT INTO "sys_role_menu" VALUES (4, 115); INSERT INTO "sys_role_menu" VALUES (4, 500); @@ -250,17 +250,18 @@ INSERT INTO "sys_role_menu" VALUES (4, 1041); INSERT INTO "sys_role_menu" VALUES (4, 1042); INSERT INTO "sys_role_menu" VALUES (4, 1044); INSERT INTO "sys_role_menu" VALUES (4, 1048); -INSERT INTO "sys_role_menu" VALUES (4, 2083); -INSERT INTO "sys_role_menu" VALUES (4, 2086); INSERT INTO "sys_role_menu" VALUES (4, 2087); INSERT INTO "sys_role_menu" VALUES (4, 2088); INSERT INTO "sys_role_menu" VALUES (4, 2089); +INSERT INTO "sys_role_menu" VALUES (4, 2091); INSERT INTO "sys_role_menu" VALUES (4, 2092); INSERT INTO "sys_role_menu" VALUES (4, 2094); INSERT INTO "sys_role_menu" VALUES (4, 2097); +INSERT INTO "sys_role_menu" VALUES (4, 2112); INSERT INTO "sys_role_menu" VALUES (4, 2113); -INSERT INTO "sys_role_menu" VALUES (4, 2114); +INSERT INTO "sys_role_menu" VALUES (4, 2115); INSERT INTO "sys_role_menu" VALUES (4, 2116); +INSERT INTO "sys_role_menu" VALUES (4, 2123); INSERT INTO "sys_role_menu" VALUES (4, 2126); INSERT INTO "sys_role_menu" VALUES (4, 2128); INSERT INTO "sys_role_menu" VALUES (4, 2129); @@ -274,11 +275,7 @@ INSERT INTO "sys_role_menu" VALUES (4, 2141); INSERT INTO "sys_role_menu" VALUES (4, 2147); INSERT INTO "sys_role_menu" VALUES (4, 2148); INSERT INTO "sys_role_menu" VALUES (4, 2149); -INSERT INTO "sys_role_menu" VALUES (4, 2151); -INSERT INTO "sys_role_menu" VALUES (4, 2152); -INSERT INTO "sys_role_menu" VALUES (4, 2153); INSERT INTO "sys_role_menu" VALUES (4, 2157); -INSERT INTO "sys_role_menu" VALUES (4, 2163); INSERT INTO "sys_role_menu" VALUES (4, 2165); INSERT INTO "sys_role_menu" VALUES (4, 2166); INSERT INTO "sys_role_menu" VALUES (4, 2167); @@ -290,6 +287,13 @@ INSERT INTO "sys_role_menu" VALUES (5, 4); INSERT INTO "sys_role_menu" VALUES (5, 112); INSERT INTO "sys_role_menu" VALUES (5, 2087); INSERT INTO "sys_role_menu" VALUES (5, 2115); +INSERT INTO "sys_role_menu" VALUES (5, 2126); +INSERT INTO "sys_role_menu" VALUES (5, 2128); +INSERT INTO "sys_role_menu" VALUES (5, 2130); INSERT INTO "sys_role_menu" VALUES (5, 2131); INSERT INTO "sys_role_menu" VALUES (5, 2132); INSERT INTO "sys_role_menu" VALUES (5, 2165); +INSERT INTO "sys_role_menu" VALUES (5, 2166); +INSERT INTO "sys_role_menu" VALUES (5, 2167); +INSERT INTO "sys_role_menu" VALUES (5, 2168); +INSERT INTO "sys_role_menu" VALUES (5, 2169); diff --git a/build/database/lite/install/sys_user.sql b/build/database/lite/install/sys_user.sql index 077b217e..2e185d3b 100644 --- a/build/database/lite/install/sys_user.sql +++ b/build/database/lite/install/sys_user.sql @@ -12,6 +12,8 @@ CREATE TABLE "sys_user" ( "sex" text(1), "avatar" text(255), "password" text(128), + "user_type" text(20), + "user_source" text(32), "status_flag" text(1), "del_flag" text(1), "password_update_time" integer, @@ -29,7 +31,7 @@ CREATE TABLE "sys_user" ( -- ---------------------------- -- Records of sys_user -- ---------------------------- -INSERT INTO `sys_user` VALUES (1, 100, 'supervisor', 'supervisor', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (1, 100, 'supervisor', 'supervisor', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); diff --git a/build/database/lite/upgrade/upg_cbc_message.sql b/build/database/lite/upgrade/upg_cbc_message.sql index 251d96d5..b2a1924d 100755 --- a/build/database/lite/upgrade/upg_cbc_message.sql +++ b/build/database/lite/upgrade/upg_cbc_message.sql @@ -1,17 +1,24 @@ -- ---------------------------- -- 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, - `updated_at` INTEGER +CREATE TABLE IF NOT EXISTS "cbc_message" ( + "id" integer NOT NULL, + "ne_type" text(32), + "ne_id" text(32), + "message_json" text(10240), + "status" text(32), + "detail" text(255), + "created_at" integer, + "updated_at" integer, + PRIMARY KEY ("id") ); --- 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`); +-- ---------------------------- +-- Indexes structure for table cbc_message +-- ---------------------------- +CREATE INDEX IF NOT EXISTS "idx_cbcm_ne_time" +ON "cbc_message" ( + "ne_type" ASC, + "ne_id" ASC, + "created_at" ASC +); diff --git a/build/database/lite/upgrade/upg_sys_dict_data.sql b/build/database/lite/upgrade/upg_sys_dict_data.sql index 21634cef..aae60d22 100644 --- a/build/database/lite/upgrade/upg_sys_dict_data.sql +++ b/build/database/lite/upgrade/upg_sys_dict_data.sql @@ -191,4 +191,8 @@ REPLACE INTO "sys_dict_data" VALUES (166, 'cdr_sip_code_cause', 'dictData.cdr_si REPLACE INTO "sys_dict_data" VALUES (167, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.606', '606', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (168, 'trace_interfaces', 'dictData.trace_interfaces.14', 'N14', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO "sys_dict_data" VALUES (169, 'trace_interfaces', 'dictData.trace_interfaces.5', 'N5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (170, 'sys_user_type', 'dictData.sys_user_type.system', 'System', 1, '', 'default', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (171, 'sys_user_type', 'dictData.sys_user_type.ldap', 'LDAP', 2, '', 'lime', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (172, 'sys_user_type', 'dictData.sys_user_type.smtp', 'SMTP', 3, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_data" VALUES (173, 'sys_user_type', 'dictData.sys_user_type.oauth2', 'OAuth2', 4, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/lite/upgrade/upg_sys_dict_type.sql b/build/database/lite/upgrade/upg_sys_dict_type.sql new file mode 100644 index 00000000..dca3cac3 --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_dict_type.sql @@ -0,0 +1,54 @@ +-- ---------------------------- +-- Table structure for sys_dict_type +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_dict_type" ( + "dict_id" integer NOT NULL, + "dict_name" text(64) NOT NULL, + "dict_type" text(64) NOT NULL, + "status_flag" text(1), + "del_flag" text(1), + "create_by" text(64), + "create_time" integer(20), + "update_by" text(64), + "update_time" integer(20), + "remark" text(500), + PRIMARY KEY ("dict_id") +); + +-- ---------------------------- +-- Records of sys_dict_type +-- ---------------------------- +REPLACE INTO "sys_dict_type" VALUES (1, 'dictType.sys_user_sex', 'sys_user_sex', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_user_sex_remark'); +REPLACE INTO "sys_dict_type" VALUES (2, 'dictType.sys_show_hide', 'sys_show_hide', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_show_hide_remark'); +REPLACE INTO "sys_dict_type" VALUES (3, 'dictType.sys_normal_disable', 'sys_normal_disable', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_normal_disable_remark'); +REPLACE INTO "sys_dict_type" VALUES (4, 'dictType.sys_job_status', 'sys_job_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_job_status_remark'); +REPLACE INTO "sys_dict_type" VALUES (5, 'dictType.sys_job_group', 'sys_job_group', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_job_group_remark'); +REPLACE INTO "sys_dict_type" VALUES (6, 'dictType.sys_yes_no', 'sys_yes_no', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_yes_no_remark'); +REPLACE INTO "sys_dict_type" VALUES (9, 'dictType.sys_oper_type', 'sys_oper_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_oper_type_remark'); +REPLACE INTO "sys_dict_type" VALUES (10, 'dictType.sys_common_status', 'sys_common_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_common_status_remark'); +REPLACE INTO "sys_dict_type" VALUES (11, 'dictType.sys_user_type', 'sys_user_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (50, 'dictType.trace_type', 'trace_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.trace_type_remark'); +REPLACE INTO "sys_dict_type" VALUES (51, 'dictType.alarm_status', 'alarm_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.alarm_status_remark'); +REPLACE INTO "sys_dict_type" VALUES (52, 'dictType.ne_version_status', 'ne_version_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.ne_version_status_remark'); +REPLACE INTO "sys_dict_type" VALUES (53, 'dictType.sys_role_datascope', 'sys_role_datascope', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_role_datascope_remark'); +REPLACE INTO "sys_dict_type" VALUES (54, 'dictType.active_alarm_type', 'active_alarm_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.active_alarm_type_remark'); +REPLACE INTO "sys_dict_type" VALUES (55, 'dictType.active_clear_type', 'active_clear_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.active_clear_type_remark'); +REPLACE INTO "sys_dict_type" VALUES (56, 'dictType.active_ack_state', 'active_ack_state', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.active_ack_state_remark'); +REPLACE INTO "sys_dict_type" VALUES (57, 'dictType.active_alarm_severity', 'active_alarm_severity', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.active_alarm_severity_remark'); +REPLACE INTO "sys_dict_type" VALUES (58, 'dictType.index_status', 'index_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.index_status_remark'); +REPLACE INTO "sys_dict_type" VALUES (59, 'dictType.cdr_sip_code', 'cdr_sip_code', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (60, 'dictType.cdr_call_type', 'cdr_call_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (61, 'dictType.ue_auth_code', 'ue_auth_code', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (62, 'dictType.ue_event_type', 'ue_event_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (63, 'dictType.ue_event_cm_state', 'ue_event_cm_state', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (64, 'dictType.ne_host_type', 'ne_host_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (65, 'dictType.ne_host_groupId', 'ne_host_groupId', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (66, 'dictType.ne_host_authMode', 'ne_host_authMode', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (67, 'dictType.ne_host_cmd_groupId', 'ne_host_cmd_groupId', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (68, 'dictType.ne_info_status', 'ne_info_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (69, 'dictType.ne_license_status', 'ne_license_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (70, 'dictType.cdr_cause_code', 'cdr_cause_code', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (71, 'dictType.trace_msg_type', 'trace_msg_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (72, 'dictType.trace_msg_direct', 'trace_msg_direct', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (73, 'dictType.trace_interfaces', 'trace_interfaces', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO "sys_dict_type" VALUES (74, 'dictType.cdr_sip_code_cause', 'cdr_sip_code_cause', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); diff --git a/build/database/lite/upgrade/upg_sys_i18n.sql b/build/database/lite/upgrade/upg_sys_i18n.sql index a393a9c9..256fbb8a 100644 --- a/build/database/lite/upgrade/upg_sys_i18n.sql +++ b/build/database/lite/upgrade/upg_sys_i18n.sql @@ -932,22 +932,30 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); +REPLACE INTO "sys_i18n" VALUES (761, "dictType.sys_user_type", "用户类型", "User Type"); +REPLACE INTO "sys_i18n" VALUES (762, "dictData.sys_user_type.system", "系统", "System"); +REPLACE INTO "sys_i18n" VALUES (763, "dictData.sys_user_type.ldap", "LDAP", "LDAP"); +REPLACE INTO "sys_i18n" VALUES (764, "dictData.sys_user_type.smtp", "SMTP", "SMTP"); +REPLACE INTO "sys_i18n" VALUES (765, "dictData.sys_user_type.oauth2", "OAuth2", "OAuth2"); +REPLACE INTO "sys_i18n" VALUES (766, "user.export.userType", "用户类型", "User Type"); +REPLACE INTO "sys_i18n" VALUES (767, "menu.system.loginSource", "第三方登录认证", "Third Party Login Source"); +REPLACE INTO "sys_i18n" VALUES (768, "log.operate.title.sysLoginSource", "认证源", "Login Source"); -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', '预警广播', 'Early Warning Broadcast'); -REPLACE INTO `sys_i18n` VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); +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', '预警广播', 'Early Warning Broadcast'); +REPLACE INTO "sys_i18n" VALUES (2017, 'log.operate.title.cbcMessage', '预警广播', 'Early Warning Broadcast'); diff --git a/build/database/lite/upgrade/upg_sys_login_source.sql b/build/database/lite/upgrade/upg_sys_login_source.sql new file mode 100644 index 00000000..34071608 --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_login_source.sql @@ -0,0 +1,32 @@ +-- ---------------------------- +-- Table structure for sys_login_source +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "sys_login_source" ( + "id" integer NOT NULL, + "uid" text(32), + "type" text(32), + "name" text(64), + "icon" text(255), + "active_flag" text(1), + "sync_flag" text(1), + "config" text, + "create_by" text(64), + "create_time" integer, + "update_by" text(64), + "update_time" integer, + "remark" text(500), + PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Indexes structure for table sys_login_source +-- ---------------------------- +CREATE INDEX IF NOT EXISTS "idx_ls_type_name" +ON "sys_login_source" ( + "type" ASC, + "name" ASC +); + +-- ---------------------------- +-- Records of sys_login_source +-- ---------------------------- diff --git a/build/database/lite/upgrade/upg_sys_menu.sql b/build/database/lite/upgrade/upg_sys_menu.sql index 316e40dc..1cc7a1c7 100644 --- a/build/database/lite/upgrade/upg_sys_menu.sql +++ b/build/database/lite/upgrade/upg_sys_menu.sql @@ -46,6 +46,7 @@ REPLACE INTO "sys_menu" VALUES (105, 'menu.security.post', 2113, 6, 'post', 'sys REPLACE INTO "sys_menu" VALUES (106, 'menu.system.dictType', 1, 30, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.dictTypeRemark'); REPLACE INTO "sys_menu" VALUES (107, 'menu.system.dictData', 1, 31, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.dictDataRemark'); REPLACE INTO "sys_menu" VALUES (108, 'menu.system.paramSet', 1, 59, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.paramSetRemark'); +REPLACE INTO "sys_menu" VALUES (109, 'menu.system.loginSource', 2113, 12, 'login-source', 'system/login-source/index', '1', '1', 'M', '1', '1', 'system:loginSource:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (111, 'menu.system.systemLog', 1, 11, 'log', '', '1', '1', 'D', '0', '0', '', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemLogRemark'); REPLACE INTO "sys_menu" VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemInfoRemark'); REPLACE INTO "sys_menu" VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.cacheInfoRemark'); @@ -108,6 +109,10 @@ REPLACE INTO "sys_menu" VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', REPLACE INTO "sys_menu" VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1057, 'menu.common.query', 109, 1, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:query', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1058, 'menu.common.add', 109, 2, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:add', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1059, 'menu.common.edit', 109, 3, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:edit', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO "sys_menu" VALUES (1060, 'menu.common.delete', 109, 4, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); REPLACE INTO "sys_menu" VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/lite/upgrade/upg_sys_role_menu.sql b/build/database/lite/upgrade/upg_sys_role_menu.sql index 995e7c22..15b8ae6a 100644 --- a/build/database/lite/upgrade/upg_sys_role_menu.sql +++ b/build/database/lite/upgrade/upg_sys_role_menu.sql @@ -2,11 +2,12 @@ -- Table structure for sys_role_menu -- ---------------------------- CREATE TABLE IF NOT EXISTS "sys_role_menu" ( - "role_id" integer(20) NOT NULL, - "menu_id" integer(20) NOT NULL, + "role_id" integer NOT NULL, + "menu_id" integer NOT NULL, PRIMARY KEY ("role_id", "menu_id") ); +DELETE FROM "sys_role_menu" WHERE "role_id" IN (2,3,4,5); -- ---------------------------- -- Records of sys_role_menu -- ---------------------------- @@ -26,6 +27,7 @@ REPLACE INTO "sys_role_menu" VALUES (2, 103); REPLACE INTO "sys_role_menu" VALUES (2, 104); REPLACE INTO "sys_role_menu" VALUES (2, 105); REPLACE INTO "sys_role_menu" VALUES (2, 108); +REPLACE INTO "sys_role_menu" VALUES (2, 109); REPLACE INTO "sys_role_menu" VALUES (2, 111); REPLACE INTO "sys_role_menu" VALUES (2, 112); REPLACE INTO "sys_role_menu" VALUES (2, 115); @@ -62,10 +64,8 @@ REPLACE INTO "sys_role_menu" VALUES (2, 1030); REPLACE INTO "sys_role_menu" VALUES (2, 1032); REPLACE INTO "sys_role_menu" VALUES (2, 1034); REPLACE INTO "sys_role_menu" VALUES (2, 1039); -REPLACE INTO "sys_role_menu" VALUES (2, 1040); REPLACE INTO "sys_role_menu" VALUES (2, 1041); REPLACE INTO "sys_role_menu" VALUES (2, 1042); -REPLACE INTO "sys_role_menu" VALUES (2, 1043); REPLACE INTO "sys_role_menu" VALUES (2, 1044); REPLACE INTO "sys_role_menu" VALUES (2, 1045); REPLACE INTO "sys_role_menu" VALUES (2, 1048); @@ -77,6 +77,10 @@ REPLACE INTO "sys_role_menu" VALUES (2, 1053); REPLACE INTO "sys_role_menu" VALUES (2, 1054); REPLACE INTO "sys_role_menu" VALUES (2, 1055); REPLACE INTO "sys_role_menu" VALUES (2, 1056); +REPLACE INTO "sys_role_menu" VALUES (2, 1057); +REPLACE INTO "sys_role_menu" VALUES (2, 1058); +REPLACE INTO "sys_role_menu" VALUES (2, 1059); +REPLACE INTO "sys_role_menu" VALUES (2, 1060); REPLACE INTO "sys_role_menu" VALUES (2, 2000); REPLACE INTO "sys_role_menu" VALUES (2, 2001); REPLACE INTO "sys_role_menu" VALUES (2, 2002); @@ -167,7 +171,6 @@ REPLACE INTO "sys_role_menu" VALUES (3, 65); REPLACE INTO "sys_role_menu" VALUES (3, 66); REPLACE INTO "sys_role_menu" VALUES (3, 108); REPLACE INTO "sys_role_menu" VALUES (3, 112); -REPLACE INTO "sys_role_menu" VALUES (3, 115); REPLACE INTO "sys_role_menu" VALUES (3, 500); REPLACE INTO "sys_role_menu" VALUES (3, 501); REPLACE INTO "sys_role_menu" VALUES (3, 1030); @@ -175,7 +178,6 @@ REPLACE INTO "sys_role_menu" VALUES (3, 1032); REPLACE INTO "sys_role_menu" VALUES (3, 1034); REPLACE INTO "sys_role_menu" VALUES (3, 1039); REPLACE INTO "sys_role_menu" VALUES (3, 1042); -REPLACE INTO "sys_role_menu" VALUES (3, 1048); REPLACE INTO "sys_role_menu" VALUES (3, 2000); REPLACE INTO "sys_role_menu" VALUES (3, 2001); REPLACE INTO "sys_role_menu" VALUES (3, 2002); @@ -188,6 +190,7 @@ REPLACE INTO "sys_role_menu" VALUES (3, 2009); REPLACE INTO "sys_role_menu" VALUES (3, 2010); REPLACE INTO "sys_role_menu" VALUES (3, 2011); REPLACE INTO "sys_role_menu" VALUES (3, 2083); +REPLACE INTO "sys_role_menu" VALUES (3, 2084); REPLACE INTO "sys_role_menu" VALUES (3, 2086); REPLACE INTO "sys_role_menu" VALUES (3, 2087); REPLACE INTO "sys_role_menu" VALUES (3, 2088); @@ -199,10 +202,12 @@ REPLACE INTO "sys_role_menu" VALUES (3, 2097); REPLACE INTO "sys_role_menu" VALUES (3, 2107); REPLACE INTO "sys_role_menu" VALUES (3, 2108); REPLACE INTO "sys_role_menu" VALUES (3, 2109); -REPLACE INTO "sys_role_menu" VALUES (3, 2113); +REPLACE INTO "sys_role_menu" VALUES (3, 2112); REPLACE INTO "sys_role_menu" VALUES (3, 2114); REPLACE INTO "sys_role_menu" VALUES (3, 2115); REPLACE INTO "sys_role_menu" VALUES (3, 2116); +REPLACE INTO "sys_role_menu" VALUES (3, 2118); +REPLACE INTO "sys_role_menu" VALUES (3, 2122); REPLACE INTO "sys_role_menu" VALUES (3, 2123); REPLACE INTO "sys_role_menu" VALUES (3, 2126); REPLACE INTO "sys_role_menu" VALUES (3, 2128); @@ -223,11 +228,10 @@ REPLACE INTO "sys_role_menu" VALUES (3, 2149); REPLACE INTO "sys_role_menu" VALUES (3, 2151); REPLACE INTO "sys_role_menu" VALUES (3, 2152); REPLACE INTO "sys_role_menu" VALUES (3, 2153); -REPLACE INTO "sys_role_menu" VALUES (3, 2154); -REPLACE INTO "sys_role_menu" VALUES (3, 2155); -REPLACE INTO "sys_role_menu" VALUES (3, 2156); REPLACE INTO "sys_role_menu" VALUES (3, 2157); REPLACE INTO "sys_role_menu" VALUES (3, 2158); +REPLACE INTO "sys_role_menu" VALUES (3, 2162); +REPLACE INTO "sys_role_menu" VALUES (3, 2163); REPLACE INTO "sys_role_menu" VALUES (3, 2165); REPLACE INTO "sys_role_menu" VALUES (3, 2166); REPLACE INTO "sys_role_menu" VALUES (3, 2167); @@ -237,9 +241,6 @@ REPLACE INTO "sys_role_menu" VALUES (3, 20000); REPLACE INTO "sys_role_menu" VALUES (4, 1); REPLACE INTO "sys_role_menu" VALUES (4, 4); -REPLACE INTO "sys_role_menu" VALUES (4, 60); -REPLACE INTO "sys_role_menu" VALUES (4, 65); -REPLACE INTO "sys_role_menu" VALUES (4, 66); REPLACE INTO "sys_role_menu" VALUES (4, 112); REPLACE INTO "sys_role_menu" VALUES (4, 115); REPLACE INTO "sys_role_menu" VALUES (4, 500); @@ -249,17 +250,18 @@ REPLACE INTO "sys_role_menu" VALUES (4, 1041); REPLACE INTO "sys_role_menu" VALUES (4, 1042); REPLACE INTO "sys_role_menu" VALUES (4, 1044); REPLACE INTO "sys_role_menu" VALUES (4, 1048); -REPLACE INTO "sys_role_menu" VALUES (4, 2083); -REPLACE INTO "sys_role_menu" VALUES (4, 2086); REPLACE INTO "sys_role_menu" VALUES (4, 2087); REPLACE INTO "sys_role_menu" VALUES (4, 2088); REPLACE INTO "sys_role_menu" VALUES (4, 2089); +REPLACE INTO "sys_role_menu" VALUES (4, 2091); REPLACE INTO "sys_role_menu" VALUES (4, 2092); REPLACE INTO "sys_role_menu" VALUES (4, 2094); REPLACE INTO "sys_role_menu" VALUES (4, 2097); +REPLACE INTO "sys_role_menu" VALUES (4, 2112); REPLACE INTO "sys_role_menu" VALUES (4, 2113); -REPLACE INTO "sys_role_menu" VALUES (4, 2114); +REPLACE INTO "sys_role_menu" VALUES (4, 2115); REPLACE INTO "sys_role_menu" VALUES (4, 2116); +REPLACE INTO "sys_role_menu" VALUES (4, 2123); REPLACE INTO "sys_role_menu" VALUES (4, 2126); REPLACE INTO "sys_role_menu" VALUES (4, 2128); REPLACE INTO "sys_role_menu" VALUES (4, 2129); @@ -273,11 +275,7 @@ REPLACE INTO "sys_role_menu" VALUES (4, 2141); REPLACE INTO "sys_role_menu" VALUES (4, 2147); REPLACE INTO "sys_role_menu" VALUES (4, 2148); REPLACE INTO "sys_role_menu" VALUES (4, 2149); -REPLACE INTO "sys_role_menu" VALUES (4, 2151); -REPLACE INTO "sys_role_menu" VALUES (4, 2152); -REPLACE INTO "sys_role_menu" VALUES (4, 2153); REPLACE INTO "sys_role_menu" VALUES (4, 2157); -REPLACE INTO "sys_role_menu" VALUES (4, 2163); REPLACE INTO "sys_role_menu" VALUES (4, 2165); REPLACE INTO "sys_role_menu" VALUES (4, 2166); REPLACE INTO "sys_role_menu" VALUES (4, 2167); @@ -289,6 +287,13 @@ REPLACE INTO "sys_role_menu" VALUES (5, 4); REPLACE INTO "sys_role_menu" VALUES (5, 112); REPLACE INTO "sys_role_menu" VALUES (5, 2087); REPLACE INTO "sys_role_menu" VALUES (5, 2115); +REPLACE INTO "sys_role_menu" VALUES (5, 2126); +REPLACE INTO "sys_role_menu" VALUES (5, 2128); +REPLACE INTO "sys_role_menu" VALUES (5, 2130); REPLACE INTO "sys_role_menu" VALUES (5, 2131); REPLACE INTO "sys_role_menu" VALUES (5, 2132); REPLACE INTO "sys_role_menu" VALUES (5, 2165); +REPLACE INTO "sys_role_menu" VALUES (5, 2166); +REPLACE INTO "sys_role_menu" VALUES (5, 2167); +REPLACE INTO "sys_role_menu" VALUES (5, 2168); +REPLACE INTO "sys_role_menu" VALUES (5, 2169); diff --git a/build/database/lite/upgrade/upg_sys_user.sql b/build/database/lite/upgrade/upg_sys_user.sql new file mode 100644 index 00000000..89eab69f --- /dev/null +++ b/build/database/lite/upgrade/upg_sys_user.sql @@ -0,0 +1,46 @@ +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +ALTER TABLE "sys_user" RENAME TO "sys_user_old"; +CREATE TABLE "sys_user" ( + "user_id" integer NOT NULL, + "dept_id" integer, + "user_name" text(36) NOT NULL, + "nick_name" text(36) NOT NULL, + "email" text(64), + "phone" text(32), + "sex" text(1), + "avatar" text(255), + "password" text(128), + "user_type" text(20), + "user_source" text(32), + "status_flag" text(1), + "del_flag" text(1), + "password_update_time" integer, + "login_count" integer, + "login_ip" text(128), + "login_time" integer, + "create_by" text(64), + "create_time" integer, + "update_by" text(64), + "update_time" integer, + "remark" text(200), + PRIMARY KEY ("user_id") +); + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO "sys_user" ( +"user_id", "dept_id", "user_name", "nick_name", "email", "phone", "sex", "avatar", "password", "status_flag", "del_flag", "password_update_time", "login_count", "login_ip", "login_time", "create_by", "create_time", "update_by", "update_time", "remark") +SELECT +"user_id", "dept_id", "user_name", "nick_name", "email", "phone", "sex", "avatar", "password", "status_flag", "del_flag", "password_update_time", "login_count", "login_ip", "login_time", "create_by", "create_time", "update_by", "update_time", "remark" +FROM "sys_user_old"; + +-- UPDATE "user_type", "user_source" +UPDATE sys_user SET +user_type = COALESCE((SELECT user_type FROM sys_user_old WHERE sys_user_old.user_id = sys_user.user_id), 'Sytem'), +user_source = COALESCE((SELECT user_source FROM sys_user_old WHERE sys_user_old.user_id = sys_user.user_id), '#') +WHERE EXISTS (SELECT 1 FROM sys_user_old WHERE sys_user_old.user_id = sys_user.user_id); + +DROP TABLE IF EXISTS "sys_user_old"; \ No newline at end of file diff --git a/build/database/std/common/mml_command.sql b/build/database/std/common/mml_command.sql index 43d1e488..ef32e0d4 100644 --- a/build/database/std/common/mml_command.sql +++ b/build/database/std/common/mml_command.sql @@ -1,22 +1,3 @@ -/* - Navicat Premium Data Transfer - - Source Server : local_mariadb - Source Server Type : MariaDB - Source Server Version : 100338 (10.3.38-MariaDB) - Source Host : localhost:33066 - Source Schema : omc_db - - Target Server Type : MariaDB - Target Server Version : 100338 (10.3.38-MariaDB) - File Encoding : 65001 - - Date: 14/05/2024 11:55:53 -*/ - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -- ---------------------------- -- Table structure for mml_command -- ---------------------------- @@ -31,9 +12,8 @@ CREATE TABLE `mml_command` ( `mml_display` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `param_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL, `status` enum('Active','Inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Active' COMMENT '激活: Active 未激活: Inactive', - PRIMARY KEY (`id`) USING BTREE, - INDEX `id`(`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1626 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of mml_command @@ -71,5 +51,3 @@ INSERT INTO `mml_command` VALUES (1622, 'OMC', 'logManagement', 'Log Management' INSERT INTO `mml_command` VALUES (1623, 'OMC', 'logManagement', 'Log Management', 'lst', 'eventlog', 'List NE Event Log', '[{\"alias\":\"ne_type\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"NE type\",\"filter\":\"\",\"loc\":\"true\",\"name\":\"netype\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"ne_id\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"NE ID\",\"filter\":\"\",\"loc\":\"true\",\"name\":\"neid\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"log_time\\u003e\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Log time(\\u003e=)\",\"filter\":\"\",\"name\":\"starttime\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"log_time\\u003c\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Log time(\\u003c=)\",\"filter\":\"\",\"name\":\"endtime\",\"optional\":\"true\",\"type\":\"string\"}]', 'Active'); INSERT INTO `mml_command` VALUES (1624, 'OMC', 'mmlManagement', 'MML Management', 'lst', 'mmlcmd', 'List MML Command', '[{\"alias\":\"ne_type\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Category\",\"filter\":\"\",\"name\":\"category\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"operation\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Operation\",\"filter\":\"\",\"name\":\"operation\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"object\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Object\",\"filter\":\"\",\"name\":\"object\",\"optional\":\"true\",\"type\":\"string\"}]', 'Active'); INSERT INTO `mml_command` VALUES (1625, 'OMC', 'systemManagement', 'System Management', 'dsp', 'sysinfo', 'Display NE System Information', '[{\"alias\":\"neType\",\"apostr\":\"false\",\"comment\":\"\",\"display\":\"NE type\",\"filter\":\"\",\"name\":\"netype\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"neId\",\"comment\":\"\",\"display\":\"NE ID\",\"filter\":\"\",\"name\":\"neid\",\"optional\":\"true\",\"type\":\"string\"}]', 'Active'); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/build/database/std/install/cbc_message.sql b/build/database/std/install/cbc_message.sql index 8eae21f5..78d119b1 100755 --- a/build/database/std/install/cbc_message.sql +++ b/build/database/std/install/cbc_message.sql @@ -1,38 +1,16 @@ -/* - 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 NULL, - `updated_at` bigint(20) NULL DEFAULT NULL, +CREATE TABLE `cbc_message` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `message_json` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'INACTIVE' COMMENT 'ACTIVE/INACTIVE', + `detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `created_at` bigint DEFAULT NULL, + `updated_at` bigint 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; + KEY `idx_cbcm_ne_time` (`ne_type`,`ne_id`,`created_at`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='CDR事件_MF'; diff --git a/build/database/std/install/sys_dict_data.sql b/build/database/std/install/sys_dict_data.sql index 3555e337..0dbcda4f 100644 --- a/build/database/std/install/sys_dict_data.sql +++ b/build/database/std/install/sys_dict_data.sql @@ -195,6 +195,10 @@ INSERT INTO `sys_dict_data` VALUES (166, 'cdr_sip_code_cause', 'dictData.cdr_sip INSERT INTO `sys_dict_data` VALUES (167, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.606', '606', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (168, 'trace_interfaces', 'dictData.trace_interfaces.14', 'N14', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_data` VALUES (169, 'trace_interfaces', 'dictData.trace_interfaces.5', 'N5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (170, 'sys_user_type', 'dictData.sys_user_type.system', 'System', 1, '', 'default', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (171, 'sys_user_type', 'dictData.sys_user_type.ldap', 'LDAP', 2, '', 'lime', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (172, 'sys_user_type', 'dictData.sys_user_type.smtp', 'SMTP', 3, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +INSERT INTO `sys_dict_data` VALUES (173, 'sys_user_type', 'dictData.sys_user_type.oauth2', 'OAuth2', 4, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); SET FOREIGN_KEY_CHECKS = 1; diff --git a/build/database/std/install/sys_dict_type.sql b/build/database/std/install/sys_dict_type.sql index 750c56d1..a03a372b 100644 --- a/build/database/std/install/sys_dict_type.sql +++ b/build/database/std/install/sys_dict_type.sql @@ -31,6 +31,7 @@ INSERT INTO `sys_dict_type` VALUES (5, 'dictType.sys_job_group', 'sys_job_group' INSERT INTO `sys_dict_type` VALUES (6, 'dictType.sys_yes_no', 'sys_yes_no', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_yes_no_remark'); INSERT INTO `sys_dict_type` VALUES (9, 'dictType.sys_oper_type', 'sys_oper_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_oper_type_remark'); INSERT INTO `sys_dict_type` VALUES (10, 'dictType.sys_common_status', 'sys_common_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_common_status_remark'); +INSERT INTO `sys_dict_type` VALUES (11, 'dictType.sys_user_type', 'sys_user_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); INSERT INTO `sys_dict_type` VALUES (50, 'dictType.trace_type', 'trace_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.trace_type_remark'); INSERT INTO `sys_dict_type` VALUES (51, 'dictType.alarm_status', 'alarm_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.alarm_status_remark'); INSERT INTO `sys_dict_type` VALUES (52, 'dictType.ne_version_status', 'ne_version_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.ne_version_status_remark'); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index e8675d6b..88c198b5 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -775,6 +775,14 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); +INSERT INTO `sys_i18n` VALUES (761, "dictType.sys_user_type", "用户类型", "User Type"); +INSERT INTO `sys_i18n` VALUES (762, "dictData.sys_user_type.system", "系统", "System"); +INSERT INTO `sys_i18n` VALUES (763, "dictData.sys_user_type.ldap", "LDAP", "LDAP"); +INSERT INTO `sys_i18n` VALUES (764, "dictData.sys_user_type.smtp", "SMTP", "SMTP"); +INSERT INTO `sys_i18n` VALUES (765, "dictData.sys_user_type.oauth2", "OAuth2", "OAuth2"); +INSERT INTO `sys_i18n` VALUES (766, "user.export.userType", "用户类型", "User Type"); +INSERT INTO `sys_i18n` VALUES (767, "menu.system.loginSource", "第三方登录认证", "Third Party Login Source"); +INSERT INTO `sys_i18n` VALUES (768, "log.operate.title.sysLoginSource", "认证源", "Login Source"); INSERT INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent'); INSERT INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information'); diff --git a/build/database/std/install/sys_login_source.sql b/build/database/std/install/sys_login_source.sql new file mode 100644 index 00000000..073189af --- /dev/null +++ b/build/database/std/install/sys_login_source.sql @@ -0,0 +1,24 @@ +-- +-- Table structure for table `sys_login_source` +-- + +DROP TABLE IF EXISTS `sys_login_source`; +CREATE TABLE `sys_login_source` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'UID 16位长度字符串', + `type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证类型 LDAP SMTP OAuth2', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证名称', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '图标', + `active_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '激活标记(0未激活 1激活)', + `sync_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '同步标记(0未同步 1同步)', + `config` text COLLATE utf8mb4_general_ci COMMENT '认证配置', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` bigint NULL DEFAULT 0 COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` bigint NULL DEFAULT 0 COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_ls_type_name` (`type`,`name`) USING BTREE COMMENT '认证类型_认证名称' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统_认证源表'; + +-- Dump completed on 2025-08-05 16:20:56 diff --git a/build/database/std/install/sys_menu.sql b/build/database/std/install/sys_menu.sql index 869ffb04..a83b723a 100644 --- a/build/database/std/install/sys_menu.sql +++ b/build/database/std/install/sys_menu.sql @@ -50,6 +50,7 @@ INSERT INTO `sys_menu` VALUES (105, 'menu.security.post', 2113, 6, 'post', 'syst INSERT INTO `sys_menu` VALUES (106, 'menu.system.dictType', 1, 30, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.dictTypeRemark'); INSERT INTO `sys_menu` VALUES (107, 'menu.system.dictData', 1, 31, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.dictDataRemark'); INSERT INTO `sys_menu` VALUES (108, 'menu.system.paramSet', 1, 59, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.paramSetRemark'); +INSERT INTO `sys_menu` VALUES (109, 'menu.system.loginSource', 2113, 12, 'login-source', 'system/login-source/index', '1', '1', 'M', '1', '1', 'system:loginSource:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (111, 'menu.system.systemLog', 1, 11, 'log', '', '1', '1', 'D', '0', '0', '', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemLogRemark'); INSERT INTO `sys_menu` VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemInfoRemark'); INSERT INTO `sys_menu` VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.cacheInfoRemark'); @@ -112,6 +113,10 @@ INSERT INTO `sys_menu` VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', ' INSERT INTO `sys_menu` VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (1057, 'menu.common.query', 109, 1, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:query', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (1058, 'menu.common.add', 109, 2, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:add', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (1059, 'menu.common.edit', 109, 3, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:edit', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (1060, 'menu.common.delete', 109, 4, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); diff --git a/build/database/std/install/sys_role_menu.sql b/build/database/std/install/sys_role_menu.sql index c8e6b38e..542dc973 100644 --- a/build/database/std/install/sys_role_menu.sql +++ b/build/database/std/install/sys_role_menu.sql @@ -1,6 +1,3 @@ -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -- ---------------------------- -- Table structure for sys_role_menu -- ---------------------------- @@ -14,9 +11,6 @@ CREATE TABLE `sys_role_menu` ( -- -- Dumping data for table `sys_role_menu` -- - -LOCK TABLES `sys_role_menu` WRITE; - INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 4); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 5); @@ -33,6 +27,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 103); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 104); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 105); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 108); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 109); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 111); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 112); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 115); @@ -69,10 +64,8 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1030); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1032); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1034); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1039); -INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1040); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1041); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1042); -INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1043); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1044); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1045); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1048); @@ -84,6 +77,10 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1053); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1054); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1055); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1056); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1057); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1058); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1059); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1060); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2000); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2001); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2002); @@ -91,8 +88,8 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2003); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2004); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2005); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2007); -INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2008); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2010); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2011); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2083); @@ -174,7 +171,6 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 65); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 66); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 108); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 112); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 115); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 500); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 501); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1030); @@ -182,7 +178,6 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1032); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1034); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1039); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1042); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1048); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2000); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2001); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2002); @@ -195,6 +190,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2010); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2011); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2083); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2084); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2086); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2087); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2088); @@ -206,10 +202,12 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2097); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2107); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2108); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2109); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2113); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2112); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2114); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2115); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2116); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2118); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2122); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2123); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2126); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2128); @@ -230,11 +228,10 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2149); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2151); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2152); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2153); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2154); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2155); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2156); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2157); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2158); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2162); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2163); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2165); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2166); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2167); @@ -244,9 +241,6 @@ 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); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 60); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 65); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 66); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 112); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 115); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 500); @@ -256,17 +250,18 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1041); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1042); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1044); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1048); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2083); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2086); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2087); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2088); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2089); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2091); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2092); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2094); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2097); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2112); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2113); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2114); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2115); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2116); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2123); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2126); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2128); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2129); @@ -280,11 +275,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2141); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2147); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2148); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2149); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2151); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2152); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2153); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2157); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2163); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2165); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2166); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2167); @@ -296,10 +287,15 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (5, 4); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 112); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2087); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2115); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2126); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2128); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2130); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2131); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2132); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2165); - -UNLOCK TABLES; +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2166); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2167); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2168); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2169); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/install/sys_user.sql b/build/database/std/install/sys_user.sql index 557efe35..c8db9d4f 100644 --- a/build/database/std/install/sys_user.sql +++ b/build/database/std/install/sys_user.sql @@ -1,4 +1,3 @@ --- MariaDB dump 10.19 Distrib 10.6.16-MariaDB, for debian-linux-gnu (x86_64) -- -- Table structure for table `sys_user` -- @@ -14,6 +13,8 @@ CREATE TABLE `sys_user` ( `sex` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '用户性别(0未选择 1男 2女)', `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '头像地址', `password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '密码', + `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'System' COMMENT '用户类型(System系统用户)', + `user_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '#' COMMENT '用户来源UID(#系统)', `status_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '账号状态(0停用 1正常)', `del_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标记(0存在 1删除)', `password_update_time` bigint NULL DEFAULT 0 COMMENT '密码更新时间', @@ -30,15 +31,10 @@ CREATE TABLE `sys_user` ( -- -- Dumping data for table `sys_user` --- - -LOCK TABLES `sys_user` WRITE; -/*!40000 ALTER TABLE `sys_user` DISABLE KEYS */; -INSERT INTO `sys_user` VALUES (1, 100, 'supervisor', 'supervisor', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); - -UNLOCK TABLES; +-- +INSERT INTO `sys_user` VALUES (1, 100, 'supervisor', 'supervisor', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/upgrade/upg_cbc_message.sql b/build/database/std/upgrade/upg_cbc_message.sql index 88a75dca..845c049a 100755 --- a/build/database/std/upgrade/upg_cbc_message.sql +++ b/build/database/std/upgrade/upg_cbc_message.sql @@ -1,37 +1,15 @@ -/* - 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 NULL, - `updated_at` bigint(20) NULL DEFAULT NULL, +CREATE TABLE IF NOT EXISTS `cbc_message` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `ne_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `message_json` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'INACTIVE' COMMENT 'ACTIVE/INACTIVE', + `detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `created_at` bigint DEFAULT NULL, + `updated_at` bigint 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; + KEY `idx_cbcm_ne_time` (`ne_type`,`ne_id`,`created_at`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='CDR事件_MF'; diff --git a/build/database/std/upgrade/upg_sys_dict_data.sql b/build/database/std/upgrade/upg_sys_dict_data.sql index 4d078c0b..51ae420a 100644 --- a/build/database/std/upgrade/upg_sys_dict_data.sql +++ b/build/database/std/upgrade/upg_sys_dict_data.sql @@ -199,6 +199,10 @@ REPLACE INTO `sys_dict_data` VALUES (166, 'cdr_sip_code_cause', 'dictData.cdr_si REPLACE INTO `sys_dict_data` VALUES (167, 'cdr_sip_code_cause', 'dictData.cdr_sip_code_cause.606', '606', 22, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (168, 'trace_interfaces', 'dictData.trace_interfaces.14', 'N14', 14, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_data` VALUES (169, 'trace_interfaces', 'dictData.trace_interfaces.5', 'N5', 5, '', '', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (170, 'sys_user_type', 'dictData.sys_user_type.system', 'System', 1, '', 'default', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (171, 'sys_user_type', 'dictData.sys_user_type.ldap', 'LDAP', 2, '', 'lime', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (172, 'sys_user_type', 'dictData.sys_user_type.smtp', 'SMTP', 3, '', 'magenta', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); +REPLACE INTO `sys_dict_data` VALUES (173, 'sys_user_type', 'dictData.sys_user_type.oauth2', 'OAuth2', 4, '', 'gold', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); SET FOREIGN_KEY_CHECKS = 1; diff --git a/build/database/std/upgrade/upg_sys_dict_type.sql b/build/database/std/upgrade/upg_sys_dict_type.sql index baa43888..0dc114a0 100644 --- a/build/database/std/upgrade/upg_sys_dict_type.sql +++ b/build/database/std/upgrade/upg_sys_dict_type.sql @@ -31,6 +31,7 @@ REPLACE INTO `sys_dict_type` VALUES (5, 'dictType.sys_job_group', 'sys_job_group REPLACE INTO `sys_dict_type` VALUES (6, 'dictType.sys_yes_no', 'sys_yes_no', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_yes_no_remark'); REPLACE INTO `sys_dict_type` VALUES (9, 'dictType.sys_oper_type', 'sys_oper_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_oper_type_remark'); REPLACE INTO `sys_dict_type` VALUES (10, 'dictType.sys_common_status', 'sys_common_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.sys_common_status_remark'); +REPLACE INTO `sys_dict_type` VALUES (11, 'dictType.sys_user_type', 'sys_user_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, ''); REPLACE INTO `sys_dict_type` VALUES (50, 'dictType.trace_type', 'trace_type', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.trace_type_remark'); REPLACE INTO `sys_dict_type` VALUES (51, 'dictType.alarm_status', 'alarm_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.alarm_status_remark'); REPLACE INTO `sys_dict_type` VALUES (52, 'dictType.ne_version_status', 'ne_version_status', '1', '0', 'system', 1699348237468, 'system', 1699348237468, 'dictType.ne_version_status_remark'); diff --git a/build/database/std/upgrade/upg_sys_i18n.sql b/build/database/std/upgrade/upg_sys_i18n.sql index e1855bf5..45033918 100644 --- a/build/database/std/upgrade/upg_sys_i18n.sql +++ b/build/database/std/upgrade/upg_sys_i18n.sql @@ -772,6 +772,14 @@ 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 (760, "menu.perf.kpiIMSOverview", "语音数据概览", "Voice Data Overview"); +REPLACE INTO `sys_i18n` VALUES (761, "dictType.sys_user_type", "用户类型", "User Type"); +REPLACE INTO `sys_i18n` VALUES (762, "dictData.sys_user_type.system", "系统", "System"); +REPLACE INTO `sys_i18n` VALUES (763, "dictData.sys_user_type.ldap", "LDAP", "LDAP"); +REPLACE INTO `sys_i18n` VALUES (764, "dictData.sys_user_type.smtp", "SMTP", "SMTP"); +REPLACE INTO `sys_i18n` VALUES (765, "dictData.sys_user_type.oauth2", "OAuth2", "OAuth2"); +REPLACE INTO `sys_i18n` VALUES (766, "user.export.userType", "用户类型", "User Type"); +REPLACE INTO `sys_i18n` VALUES (767, "menu.system.loginSource", "第三方登录认证", "Third Party Login Source"); +REPLACE INTO `sys_i18n` VALUES (768, "log.operate.title.sysLoginSource", "认证源", "Login Source"); REPLACE INTO `sys_i18n` VALUES (2000, 'menu.psap.agent', '座席', 'Agent'); REPLACE INTO `sys_i18n` VALUES (2001, 'menu.psap.agent.callings', '并行话务', 'Calling Information'); diff --git a/build/database/std/upgrade/upg_sys_login_source.sql b/build/database/std/upgrade/upg_sys_login_source.sql new file mode 100644 index 00000000..e68e205a --- /dev/null +++ b/build/database/std/upgrade/upg_sys_login_source.sql @@ -0,0 +1,23 @@ +-- +-- Table structure for table `sys_login_source` +-- + +CREATE TABLE IF NOT EXISTS `sys_login_source` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'UID 16位长度字符串', + `type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证类型 LDAP SMTP OAuth2', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证名称', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '图标', + `active_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '激活标记(0未激活 1激活)', + `sync_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '同步标记(0未同步 1同步)', + `config` text COLLATE utf8mb4_general_ci COMMENT '认证配置', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` bigint NULL DEFAULT 0 COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` bigint NULL DEFAULT 0 COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_ls_type_name` (`type`,`name`) USING BTREE COMMENT '认证类型_认证名称' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统_认证源表'; + +-- Dump completed on 2025-08-05 16:20:56 diff --git a/build/database/std/upgrade/upg_sys_menu.sql b/build/database/std/upgrade/upg_sys_menu.sql index 10e5e0de..6f2770ed 100644 --- a/build/database/std/upgrade/upg_sys_menu.sql +++ b/build/database/std/upgrade/upg_sys_menu.sql @@ -72,6 +72,7 @@ REPLACE INTO `sys_menu` VALUES (105, 'menu.security.post', 2113, 6, 'post', 'sys REPLACE INTO `sys_menu` VALUES (106, 'menu.system.dictType', 1, 30, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.dictTypeRemark'); REPLACE INTO `sys_menu` VALUES (107, 'menu.system.dictData', 1, 31, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.dictDataRemark'); REPLACE INTO `sys_menu` VALUES (108, 'menu.system.paramSet', 1, 59, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.paramSetRemark'); +REPLACE INTO `sys_menu` VALUES (109, 'menu.system.loginSource', 2113, 12, 'login-source', 'system/login-source/index', '1', '1', 'M', '1', '1', 'system:loginSource:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (111, 'menu.system.systemLog', 1, 11, 'log', '', '1', '1', 'D', '0', '0', '', '#', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemLogRemark'); REPLACE INTO `sys_menu` VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemInfoRemark'); REPLACE INTO `sys_menu` VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.cacheInfoRemark'); @@ -134,6 +135,10 @@ REPLACE INTO `sys_menu` VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', REPLACE INTO `sys_menu` VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (1057, 'menu.common.query', 109, 1, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:query', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (1058, 'menu.common.add', 109, 2, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:add', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (1059, 'menu.common.edit', 109, 3, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:edit', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); +REPLACE INTO `sys_menu` VALUES (1060, 'menu.common.delete', 109, 4, '#', '', '1', '1', 'B', '1', '1', 'system:loginSource:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); REPLACE INTO `sys_menu` VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); diff --git a/build/database/std/upgrade/upg_sys_role_menu.sql b/build/database/std/upgrade/upg_sys_role_menu.sql index 2c9c27ac..8733307c 100644 --- a/build/database/std/upgrade/upg_sys_role_menu.sql +++ b/build/database/std/upgrade/upg_sys_role_menu.sql @@ -1,6 +1,3 @@ -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -- ---------------------------- -- Table structure for sys_role_menu -- ---------------------------- @@ -10,12 +7,10 @@ CREATE TABLE IF NOT EXISTS `sys_role_menu` ( PRIMARY KEY (`role_id`, `menu_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统_角色和菜单关联表' ROW_FORMAT = Dynamic; +DELETE FROM `sys_role_menu` WHERE `role_id` IN (2,3,4,5); -- -- Dumping data for table `sys_role_menu` -- - -LOCK TABLES `sys_role_menu` WRITE; - INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 4); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 5); @@ -32,6 +27,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 103); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 104); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 105); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 108); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 109); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 111); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 112); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 115); @@ -68,10 +64,8 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1030); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1032); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1034); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1039); -INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1040); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1041); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1042); -INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1043); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1044); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1045); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1048); @@ -83,6 +77,10 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1053); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1054); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1055); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1056); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1057); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1058); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1059); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1060); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2000); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2001); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2002); @@ -90,8 +88,8 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2003); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2004); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2005); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2007); -INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2008); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2010); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2011); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2083); @@ -173,7 +171,6 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 65); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 66); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 108); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 112); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 115); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 500); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 501); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1030); @@ -181,7 +178,6 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1032); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1034); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1039); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1042); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 1048); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2000); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2001); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2002); @@ -194,6 +190,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2010); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2011); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2083); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2084); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2086); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2087); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2088); @@ -205,10 +202,12 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2097); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2107); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2108); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2109); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2113); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2112); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2114); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2115); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2116); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2118); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2122); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2123); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2126); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2128); @@ -229,11 +228,10 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2149); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2151); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2152); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2153); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2154); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2155); -INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2156); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2157); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2158); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2162); +INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2163); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2165); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2166); INSERT IGNORE INTO `sys_role_menu` VALUES (3, 2167); @@ -243,9 +241,6 @@ 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); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 60); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 65); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 66); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 112); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 115); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 500); @@ -255,17 +250,18 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1041); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1042); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1044); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 1048); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2083); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2086); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2087); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2088); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2089); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2091); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2092); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2094); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2097); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2112); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2113); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2114); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2115); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2116); +INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2123); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2126); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2128); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2129); @@ -279,11 +275,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2141); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2147); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2148); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2149); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2151); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2152); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2153); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2157); -INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2163); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2165); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2166); INSERT IGNORE INTO `sys_role_menu` VALUES (4, 2167); @@ -295,10 +287,15 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (5, 4); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 112); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2087); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2115); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2126); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2128); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2130); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2131); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2132); INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2165); - -UNLOCK TABLES; +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2166); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2167); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2168); +INSERT IGNORE INTO `sys_role_menu` VALUES (5, 2169); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/upgrade/upg_sys_user.sql b/build/database/std/upgrade/upg_sys_user.sql index eb89d6b1..35e4a953 100644 --- a/build/database/std/upgrade/upg_sys_user.sql +++ b/build/database/std/upgrade/upg_sys_user.sql @@ -1,6 +1,7 @@ -- -- Table structure for table `sys_user` -- + CREATE TABLE IF NOT EXISTS `sys_user` ( `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', `dept_id` bigint NULL DEFAULT 0 COMMENT '部门ID', @@ -11,6 +12,8 @@ CREATE TABLE IF NOT EXISTS `sys_user` ( `sex` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '用户性别(0未选择 1男 2女)', `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '头像地址', `password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '密码', + `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'System' COMMENT '用户类型(System系统用户)', + `user_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '#' COMMENT '用户来源UID (系统#)', `status_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '账号状态(0停用 1正常)', `del_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标记(0存在 1删除)', `password_update_time` bigint NULL DEFAULT 0 COMMENT '密码更新时间', @@ -28,10 +31,6 @@ CREATE TABLE IF NOT EXISTS `sys_user` ( -- ---------------------------- -- COLUMN for sys_user -- ---------------------------- -ALTER TABLE `sys_user` DROP COLUMN `user_type`; -ALTER TABLE `sys_user` DROP COLUMN `phonenumber`; -ALTER TABLE `sys_user` DROP COLUMN `status`; -ALTER TABLE `sys_user` DROP COLUMN `login_date`; ALTER TABLE `sys_user` MODIFY COLUMN `user_name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户账号' AFTER `dept_id`; ALTER TABLE `sys_user` MODIFY COLUMN `nick_name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称' AFTER `user_name`; ALTER TABLE `sys_user` ADD COLUMN `phone` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '手机号码' AFTER `email`; @@ -45,15 +44,18 @@ ALTER TABLE `sys_user` ADD COLUMN `login_time` bigint(20) NULL DEFAULT 0 COMMENT ALTER TABLE `sys_user` MODIFY COLUMN `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者' AFTER `login_time`; ALTER TABLE `sys_user` MODIFY COLUMN `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者' AFTER `create_time`; ALTER TABLE `sys_user` MODIFY COLUMN `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注' AFTER `update_time`; +ALTER TABLE `sys_user` ADD COLUMN `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'System' COMMENT '用户类型(System系统用户)' AFTER `password`; +ALTER TABLE `sys_user` ADD COLUMN `user_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '#' COMMENT '用户来源UID (系统#)' AFTER `user_type`; ALTER TABLE `sys_user` COMMENT = '系统_用户信息表'; -- ---------------------------- -- Data for sys_user -- ---------------------------- -INSERT IGNORE INTO `sys_user` VALUES (1, 100, 'supervisor', 'supervisor', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT IGNORE INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT IGNORE INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT IGNORE INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); -UPDATE `sys_user` SET `status_flag` = '1' WHERE `user_id` in (1,2,3,4); +INSERT IGNORE INTO `sys_user` VALUES (1, 100, 'supervisor', 'supervisor', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT IGNORE INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT IGNORE INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT IGNORE INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); +UPDATE `sys_user` SET `status_flag` = '1', `user_type` = 'System', `user_source` = '#' WHERE `user_id` in (1,2,3,4); + -- Dump completed on 2025-02-14 15:26:56 diff --git a/src/modules/auth/auth.go b/src/modules/auth/auth.go index 11e64407..801e916f 100644 --- a/src/modules/auth/auth.go +++ b/src/modules/auth/auth.go @@ -23,38 +23,84 @@ func Setup(router *gin.Engine) { ) // 账号身份操作 + account := controller.NewAccount + accountGroup := router.Group("/auth") { - router.POST("/auth/login", + accountGroup.POST("/login", middleware.RateLimit(middleware.LimitOption{ Time: 180, Count: 15, Type: middleware.LIMIT_IP, }), - controller.NewAccount.Login, + account.Login, ) - router.POST("/auth/logout", + accountGroup.POST("/logout", middleware.RateLimit(middleware.LimitOption{ Time: 120, Count: 15, Type: middleware.LIMIT_IP, }), - controller.NewAccount.Logout, + account.Logout, ) - router.POST("/auth/refresh-token", + accountGroup.POST("/refresh-token", middleware.RateLimit(middleware.LimitOption{ Time: 60, Count: 5, Type: middleware.LIMIT_IP, }), - controller.NewAccount.RefreshToken, + account.RefreshToken, ) router.GET("/me", middleware.AuthorizeUser(nil), - controller.NewAccount.Me, + account.Me, ) router.GET("/router", middleware.AuthorizeUser(nil), - controller.NewAccount.Router, + account.Router, + ) + } + + // 登录认证源 + { + accountGroup.GET("/login/source", + middleware.RateLimit(middleware.LimitOption{ + Time: 300, + Count: 60, + Type: middleware.LIMIT_IP, + }), + account.LoginSource, + ) + accountGroup.POST("/login/ldap", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.LDAP, + ) + accountGroup.POST("/login/smtp", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.SMTP, + ) + accountGroup.GET("/login/oauth2/authorize", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.OAuth2CodeURL, + ) + accountGroup.POST("/login/oauth2/token", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.OAuth2Token, ) } diff --git a/src/modules/auth/controller/account.go b/src/modules/auth/controller/account.go index e3584682..b95cf140 100644 --- a/src/modules/auth/controller/account.go +++ b/src/modules/auth/controller/account.go @@ -4,16 +4,13 @@ import ( "fmt" "time" - "be.ems/src/framework/config" "be.ems/src/framework/constants" "be.ems/src/framework/i18n" "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/token" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/auth/model" "be.ems/src/modules/auth/service" - systemModelVO "be.ems/src/modules/system/model/vo" systemService "be.ems/src/modules/system/service" "github.com/gin-gonic/gin" @@ -33,95 +30,6 @@ type AccountController struct { sysLogLoginService *systemService.SysLogLogin // 系统登录访问 } -// Login 系统登录 -// -// POST /auth/login -// -// @Tags common/authorization -// @Accept json -// @Produce json -// @Param data body object true "Request Param" -// @Success 200 {object} object "Response Results" -// @Summary System Login -// @Description System Login -// @Router /auth/login [post] -func (s AccountController) Login(c *gin.Context) { - language := reqctx.AcceptLanguage(c) - var body model.LoginBody - if err := c.ShouldBindJSON(&body); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } - - // 当前请求信息 - ipaddr, location := reqctx.IPAddrLocation(c) - os, browser := reqctx.UaOsBrowser(c) - - // 校验验证码 根据错误信息,创建系统访问记录 - if err := s.accountService.ValidateCaptcha(body.Code, body.UUID); err != nil { - msg := fmt.Sprintf("%s code %s", err.Error(), body.Code) - s.sysLogLoginService.Insert( - body.Username, constants.STATUS_NO, msg, - [4]string{ipaddr, location, os, browser}, - ) - c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) - return - } - - // 登录用户信息 - info, err := s.accountService.ByUsername(body.Username, body.Password) - if err != nil { - s.sysLogLoginService.Insert( - body.Username, constants.STATUS_NO, err.Error(), - [4]string{ipaddr, location, os, browser}, - ) - c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) - return - } - - data := map[string]any{} - - if !config.IsSystemUser(info.UserId) { - // 强制改密码 - forcePasswdChange, err := s.accountService.PasswordCountOrExpireTime(info.User.LoginCount, info.User.PasswordUpdateTime) - if err != nil { - c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) - return - } - if forcePasswdChange { - data["forcePasswdChange"] = true - } - } - - deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId) - - // 生成访问令牌 - accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access") - if accessToken == "" || expiresIn == 0 { - c.JSON(200, resp.ErrMsg("token generation failed")) - return - } - // 生成刷新令牌 - refreshToken, refreshExpiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "refresh") - - // 记录令牌,创建系统访问记录 - token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser}) - s.accountService.UpdateLoginDateAndIP(info) - s.sysLogLoginService.Insert( - body.Username, constants.STATUS_YES, "app.common.loginSuccess", - [4]string{ipaddr, location, os, browser}, - ) - - data["tokenType"] = constants.HEADER_PREFIX - data["accessToken"] = accessToken - data["expiresIn"] = expiresIn - data["refreshToken"] = refreshToken - data["refreshExpiresIn"] = refreshExpiresIn - data["userId"] = info.UserId - c.JSON(200, resp.OkData(data)) -} - // Logout 系统登出 // // POST /auth/logout @@ -222,82 +130,10 @@ func (s AccountController) RefreshToken(c *gin.Context) { })) } -// Me 登录用户信息 +// LoginSource 登录认证源 // -// GET /me -// -// @Tags common/authorization -// @Accept json -// @Produce json -// @Success 200 {object} object "Response Results" -// @Security TokenAuth -// @Summary Login User Information -// @Description Login User Information -// @Router /me [get] -func (s AccountController) Me(c *gin.Context) { - language := reqctx.AcceptLanguage(c) - info, err := reqctx.LoginUser(c) - if err != nil { - c.JSON(401, resp.CodeMsg(resp.CODE_AUTH_INVALID, err.Error())) - return - } - - // 角色权限集合,系统管理员拥有所有权限 - isSystemUser := config.IsSystemUser(info.UserId) - roles, perms := s.accountService.RoleAndMenuPerms(info.UserId, isSystemUser) - - info.User.NickName = i18n.TKey(language, info.User.NickName) - info.User.Remark = i18n.TKey(language, info.User.Remark) - info.User.Dept.DeptName = i18n.TKey(language, info.User.Dept.DeptName) - for ri := range info.User.Roles { - info.User.Roles[ri].RoleName = i18n.TKey(language, info.User.Roles[ri].RoleName) - } - - data := map[string]any{ - "user": info.User, - "roles": roles, - "permissions": perms, - } - if !isSystemUser { - // 强制改密码 - forcePasswdChange, _ := s.accountService.PasswordCountOrExpireTime(info.User.LoginCount, info.User.PasswordUpdateTime) - if forcePasswdChange { - data["forcePasswdChange"] = true - } - } +// GET /auth/login/source +func (s AccountController) LoginSource(c *gin.Context) { + data := s.accountService.LoginSource() c.JSON(200, resp.OkData(data)) } - -// Router 登录用户路由信息 -// -// GET /router -// -// @Tags common/authorization -// @Accept json -// @Produce json -// @Success 200 {object} object "Response Results" -// @Security TokenAuth -// @Summary Login User Routing Information -// @Description Login User Routing Information -// @Router /router [get] -func (s AccountController) Router(c *gin.Context) { - loginUserId := reqctx.LoginUserToUserID(c) - - // 前端路由,系统管理员拥有所有 - isSystemUser := config.IsSystemUser(loginUserId) - buildMenus := s.accountService.RouteMenus(loginUserId, isSystemUser) - // 闭包函数处理多语言 - language := reqctx.AcceptLanguage(c) - var converI18n func(language string, arr *[]systemModelVO.Router) - converI18n = func(language string, arr *[]systemModelVO.Router) { - for i := range *arr { - (*arr)[i].Meta.Title = i18n.TKey(language, (*arr)[i].Meta.Title) - if len((*arr)[i].Children) > 0 { - converI18n(language, &(*arr)[i].Children) - } - } - } - converI18n(language, &buildMenus) - - c.JSON(200, resp.OkData(buildMenus)) -} diff --git a/src/modules/auth/controller/account_info.go b/src/modules/auth/controller/account_info.go new file mode 100644 index 00000000..49c5ec41 --- /dev/null +++ b/src/modules/auth/controller/account_info.go @@ -0,0 +1,93 @@ +package controller + +import ( + "be.ems/src/framework/config" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + systemModelVO "be.ems/src/modules/system/model/vo" + + "github.com/gin-gonic/gin" +) + +// Me 登录用户信息 +// +// GET /me +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Login User Information +// @Description Login User Information +// @Router /me [get] +func (s AccountController) Me(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + info, err := reqctx.LoginUser(c) + if err != nil { + c.JSON(401, resp.CodeMsg(resp.CODE_AUTH_INVALID, err.Error())) + return + } + + // 角色权限集合,系统管理员拥有所有权限 + isSystemUser := config.IsSystemUser(info.UserId) + roles, perms := s.accountService.RoleAndMenuPerms(info.UserId, isSystemUser) + + info.User.NickName = i18n.TKey(language, info.User.NickName) + info.User.Remark = i18n.TKey(language, info.User.Remark) + if info.User.Dept != nil { + info.User.Dept.DeptName = i18n.TKey(language, info.User.Dept.DeptName) + } + for ri := range info.User.Roles { + info.User.Roles[ri].RoleName = i18n.TKey(language, info.User.Roles[ri].RoleName) + } + + data := map[string]any{ + "user": info.User, + "roles": roles, + "permissions": perms, + } + if !isSystemUser { + // 强制改密码 + forcePasswdChange, _ := s.accountService.PasswordCountOrExpireTime(info.User.LoginCount, info.User.PasswordUpdateTime) + if forcePasswdChange { + data["forcePasswdChange"] = true + } + } + c.JSON(200, resp.OkData(data)) +} + +// Router 登录用户路由信息 +// +// GET /router +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Login User Routing Information +// @Description Login User Routing Information +// @Router /router [get] +func (s AccountController) Router(c *gin.Context) { + loginUserId := reqctx.LoginUserToUserID(c) + + // 前端路由,系统管理员拥有所有 + isSystemUser := config.IsSystemUser(loginUserId) + buildMenus := s.accountService.RouteMenus(loginUserId, isSystemUser) + // 闭包函数处理多语言 + language := reqctx.AcceptLanguage(c) + var converI18n func(language string, arr *[]systemModelVO.Router) + converI18n = func(language string, arr *[]systemModelVO.Router) { + for i := range *arr { + (*arr)[i].Meta.Title = i18n.TKey(language, (*arr)[i].Meta.Title) + if len((*arr)[i].Children) > 0 { + converI18n(language, &(*arr)[i].Children) + } + } + } + converI18n(language, &buildMenus) + + c.JSON(200, resp.OkData(buildMenus)) +} diff --git a/src/modules/auth/controller/account_ldap.go b/src/modules/auth/controller/account_ldap.go new file mode 100644 index 00000000..d2510d96 --- /dev/null +++ b/src/modules/auth/controller/account_ldap.go @@ -0,0 +1,80 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/constants" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/token" + "be.ems/src/modules/auth/model" + + "github.com/gin-gonic/gin" +) + +// LDAP LDAP认证登录 +// +// POST /auth/ldap +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/ldap [post] +func (s AccountController) LDAP(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginSourceBody + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 登录用户信息 + info, err := s.accountService.ByLDAP(body) + if err != nil { + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_NO, err.Error(), + [4]string{ipaddr, location, os, browser}, + ) + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + data := map[string]any{} + + deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId) + + // 生成访问令牌 + accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access") + if accessToken == "" || expiresIn == 0 { + c.JSON(200, resp.ErrMsg("token generation failed")) + return + } + // 生成刷新令牌 + refreshToken, refreshExpiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "refresh") + + // 记录令牌,创建系统访问记录 + token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser}) + s.accountService.UpdateLoginDateAndIP(info) + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_YES, "app.common.loginSuccess", + [4]string{ipaddr, location, os, browser}, + ) + + data["tokenType"] = constants.HEADER_PREFIX + data["accessToken"] = accessToken + data["expiresIn"] = expiresIn + data["refreshToken"] = refreshToken + data["refreshExpiresIn"] = refreshExpiresIn + data["userId"] = info.UserId + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/auth/controller/account_oauth2.go b/src/modules/auth/controller/account_oauth2.go new file mode 100644 index 00000000..1a90bccd --- /dev/null +++ b/src/modules/auth/controller/account_oauth2.go @@ -0,0 +1,107 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/constants" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/token" + "be.ems/src/modules/auth/model" + + "github.com/gin-gonic/gin" +) + +// OAuth2CodeURL OAuth2认证跳转登录URL +// +// GET /auth/login/oauth2/authorize +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/login/oauth2/authorize [get] +func (s AccountController) OAuth2CodeURL(c *gin.Context) { + state := c.Query("state") + if state == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: state is empty")) + return + } + + redirectURL, err := s.accountService.ByOAuth2CodeURL(state) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.Redirect(302, redirectURL) +} + +// OAuth2 OAuth2认证登录 +// +// POST /auth/login/oauth2/token +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/login/oauth2/token [post] +func (s AccountController) OAuth2Token(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginSourceOauth2Body + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 登录用户信息 + info, err := s.accountService.ByOAuth2(body) + if err != nil { + s.sysLogLoginService.Insert( + body.State, constants.STATUS_NO, err.Error(), + [4]string{ipaddr, location, os, browser}, + ) + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + data := map[string]any{} + + deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId) + + // 生成访问令牌 + accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access") + if accessToken == "" || expiresIn == 0 { + c.JSON(200, resp.ErrMsg("token generation failed")) + return + } + // 生成刷新令牌 + refreshToken, refreshExpiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "refresh") + + // 记录令牌,创建系统访问记录 + token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser}) + s.accountService.UpdateLoginDateAndIP(info) + s.sysLogLoginService.Insert( + body.State, constants.STATUS_YES, "app.common.loginSuccess", + [4]string{ipaddr, location, os, browser}, + ) + + data["tokenType"] = constants.HEADER_PREFIX + data["accessToken"] = accessToken + data["expiresIn"] = expiresIn + data["refreshToken"] = refreshToken + data["refreshExpiresIn"] = refreshExpiresIn + data["userId"] = info.UserId + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/auth/controller/account_smtp.go b/src/modules/auth/controller/account_smtp.go new file mode 100644 index 00000000..ab94e0bd --- /dev/null +++ b/src/modules/auth/controller/account_smtp.go @@ -0,0 +1,80 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/constants" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/token" + "be.ems/src/modules/auth/model" + + "github.com/gin-gonic/gin" +) + +// SMTP SMTP认证登录 +// +// POST /auth/smtp +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/smtp [post] +func (s AccountController) SMTP(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginSourceBody + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 登录用户信息 + info, err := s.accountService.BySMTP(body) + if err != nil { + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_NO, err.Error(), + [4]string{ipaddr, location, os, browser}, + ) + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + data := map[string]any{} + + deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId) + + // 生成访问令牌 + accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access") + if accessToken == "" || expiresIn == 0 { + c.JSON(200, resp.ErrMsg("token generation failed")) + return + } + // 生成刷新令牌 + refreshToken, refreshExpiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "refresh") + + // 记录令牌,创建系统访问记录 + token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser}) + s.accountService.UpdateLoginDateAndIP(info) + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_YES, "app.common.loginSuccess", + [4]string{ipaddr, location, os, browser}, + ) + + data["tokenType"] = constants.HEADER_PREFIX + data["accessToken"] = accessToken + data["expiresIn"] = expiresIn + data["refreshToken"] = refreshToken + data["refreshExpiresIn"] = refreshExpiresIn + data["userId"] = info.UserId + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/auth/controller/account_system.go b/src/modules/auth/controller/account_system.go new file mode 100644 index 00000000..d9721a1e --- /dev/null +++ b/src/modules/auth/controller/account_system.go @@ -0,0 +1,104 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/config" + "be.ems/src/framework/constants" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/token" + "be.ems/src/modules/auth/model" + + "github.com/gin-gonic/gin" +) + +// Login 系统登录 +// +// POST /auth/login +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/login [post] +func (s AccountController) Login(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginBody + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 校验验证码 根据错误信息,创建系统访问记录 + if err := s.accountService.ValidateCaptcha(body.Code, body.UUID); err != nil { + msg := fmt.Sprintf("%s code %s", err.Error(), body.Code) + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_NO, msg, + [4]string{ipaddr, location, os, browser}, + ) + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + // 登录用户信息 + info, err := s.accountService.ByUsername(body.Username, body.Password) + if err != nil { + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_NO, err.Error(), + [4]string{ipaddr, location, os, browser}, + ) + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + data := map[string]any{} + + if !config.IsSystemUser(info.UserId) { + // 强制改密码 + forcePasswdChange, err := s.accountService.PasswordCountOrExpireTime(info.User.LoginCount, info.User.PasswordUpdateTime) + if err != nil { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + if forcePasswdChange { + data["forcePasswdChange"] = true + } + } + + deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId) + + // 生成访问令牌 + accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access") + if accessToken == "" || expiresIn == 0 { + c.JSON(200, resp.ErrMsg("token generation failed")) + return + } + // 生成刷新令牌 + refreshToken, refreshExpiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "refresh") + + // 记录令牌,创建系统访问记录 + token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser}) + s.accountService.UpdateLoginDateAndIP(info) + s.sysLogLoginService.Insert( + body.Username, constants.STATUS_YES, "app.common.loginSuccess", + [4]string{ipaddr, location, os, browser}, + ) + + data["tokenType"] = constants.HEADER_PREFIX + data["accessToken"] = accessToken + data["expiresIn"] = expiresIn + data["refreshToken"] = refreshToken + data["refreshExpiresIn"] = refreshExpiresIn + data["userId"] = info.UserId + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/auth/model/login_body.go b/src/modules/auth/model/login_body.go index ec37763e..78546991 100644 --- a/src/modules/auth/model/login_body.go +++ b/src/modules/auth/model/login_body.go @@ -2,15 +2,8 @@ package model // LoginBody 用户登录对象 type LoginBody struct { - // Username 用户名 - Username string `json:"username" binding:"required"` - - // Password 用户密码 - Password string `json:"password" binding:"required"` - - // Code 验证码 - Code string `json:"code"` - - // UUID 验证码唯一标识 - UUID string `json:"uuid"` + Username string `json:"username" binding:"required"` // Username 用户名 + Password string `json:"password" binding:"required"` // Password 用户密码 + Code string `json:"code"` // Code 验证码 + UUID string `json:"uuid"` // UUID 验证码唯一标识 } diff --git a/src/modules/auth/model/login_source_vo.go b/src/modules/auth/model/login_source_vo.go new file mode 100644 index 00000000..7b63ad57 --- /dev/null +++ b/src/modules/auth/model/login_source_vo.go @@ -0,0 +1,22 @@ +package model + +// LoginSourceVo 认证源登录对象 +type LoginSourceVo struct { + UID string `json:"uid"` // UID 认证源UID + Name string `json:"name"` // Name 认证源名称 + Type string `json:"type"` // Type 认证源类型 + Icon string `json:"icon"` // Icon 认证源图标 +} + +// LoginSourceBody 认证源用户登录对象 +type LoginSourceBody struct { + Username string `json:"username" binding:"required"` // Username 用户名 + Password string `json:"password" binding:"required"` // Password 用户密码 + UID string `json:"uid" binding:"required"` // UID 认证源唯一标识 +} + +// LoginSourceOauth2Body 认证源OAuth2用户登录对象 +type LoginSourceOauth2Body struct { + Code string `json:"code" binding:"required"` // Code 授权码 + State string `json:"state" binding:"required"` // State 状态-认证源唯一标识 +} diff --git a/src/modules/auth/model/register_body.go b/src/modules/auth/model/register_body.go index 4bf11142..9354306a 100644 --- a/src/modules/auth/model/register_body.go +++ b/src/modules/auth/model/register_body.go @@ -2,21 +2,10 @@ package model // RegisterBody 用户注册对象 type RegisterBody struct { - // Username 用户名 - Username string `json:"username" binding:"required"` - - // Password 用户密码 - Password string `json:"password" binding:"required"` - - // ConfirmPassword 用户确认密码 - ConfirmPassword string `json:"confirmPassword" binding:"required"` - - // Code 验证码 - Code string `json:"code"` - - // UUID 验证码唯一标识 - UUID string `json:"uuid"` - - // UserType 标记用户类型 - UserType string `json:"userType"` + Username string `json:"username" binding:"required"` // Username 用户名 + Password string `json:"password" binding:"required"` // Password 用户密码 + ConfirmPassword string `json:"confirmPassword" binding:"required"` // ConfirmPassword 用户确认密码 + Code string `json:"code"` // Code 验证码 + UUID string `json:"uuid"` // UUID 验证码唯一标识 + UserType string `json:"userType"` // UserType 标记用户类型 } diff --git a/src/modules/auth/service/account.go b/src/modules/auth/service/account.go index bc8d605a..d4939326 100644 --- a/src/modules/auth/service/account.go +++ b/src/modules/auth/service/account.go @@ -2,102 +2,32 @@ package service import ( "fmt" - "time" "be.ems/src/framework/config" "be.ems/src/framework/constants" - "be.ems/src/framework/database/redis" "be.ems/src/framework/token" - "be.ems/src/framework/utils/crypto" "be.ems/src/framework/utils/parse" - systemModelVO "be.ems/src/modules/system/model/vo" + "be.ems/src/modules/auth/model" + systemModel "be.ems/src/modules/system/model" systemService "be.ems/src/modules/system/service" ) // 实例化服务层 Account 结构体 var NewAccount = &Account{ - sysUserService: systemService.NewSysUser, - sysConfigService: systemService.NewSysConfig, - sysRoleService: systemService.NewSysRole, - sysMenuService: systemService.NewSysMenu, + sysUserService: systemService.NewSysUser, + sysConfigService: systemService.NewSysConfig, + sysRoleService: systemService.NewSysRole, + sysMenuService: systemService.NewSysMenu, + sysLogSourceService: systemService.NewSysLoginSource, } // 账号身份操作服务 服务层处理 type Account struct { - sysUserService *systemService.SysUser // 用户信息服务 - sysConfigService *systemService.SysConfig // 参数配置服务 - sysRoleService *systemService.SysRole // 角色服务 - sysMenuService *systemService.SysMenu // 菜单服务 -} - -// ValidateCaptcha 校验验证码 -func (s *Account) ValidateCaptcha(code, uuid string) error { - // 验证码检查,从数据库配置获取验证码开关 true开启,false关闭 - captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled") - if !parse.Boolean(captchaEnabledStr) { - return nil - } - if code == "" || uuid == "" { - // 验证码信息错误 - return fmt.Errorf("captcha.err") - } - verifyKey := constants.CACHE_CAPTCHA_CODE + ":" + uuid - captcha, _ := redis.Get("", verifyKey) - if captcha == "" { - // 验证码已失效 - return fmt.Errorf("captcha.errValid") - } - _ = redis.Del("", verifyKey) - if captcha != code { - // 验证码错误 - return fmt.Errorf("captcha.err") - } - return nil -} - -// ByUsername 登录创建用户信息 -func (s Account) ByUsername(username, password string) (token.UserInfo, error) { - info := token.UserInfo{} - - // 检查密码重试次数 - retryKey, retryCount, lockTime, err := s.passwordRetryCount(username) - if err != nil { - return info, err - } - - // 查询用户登录账号 - sysUser := s.sysUserService.FindByUserName(username) - if sysUser.UserName != username { - return info, fmt.Errorf("login.errNameOrPasswd") - } - if sysUser.DelFlag == constants.STATUS_YES { - return info, fmt.Errorf("login.errDelFlag") - } - if sysUser.StatusFlag == constants.STATUS_NO { - return info, fmt.Errorf("login.errStatus") - } - - // 检验用户密码 - compareBool := crypto.BcryptCompare(password, sysUser.Password) - if compareBool { - s.CleanLoginRecordCache(sysUser.UserName) // 清除错误记录次数 - } else { - _ = redis.Set("", retryKey, retryCount+1, lockTime) - return info, fmt.Errorf("login.errNameOrPasswd") - } - - // 登录用户信息 - info.UserId = sysUser.UserId - info.DeptId = sysUser.DeptId - info.User = sysUser - // 用户权限组标识 - if config.IsSystemUser(sysUser.UserId) { - info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM} - } else { - perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId) - info.Permissions = parse.RemoveDuplicates(perms) - } - return info, nil + sysUserService *systemService.SysUser // 用户信息服务 + sysConfigService *systemService.SysConfig // 参数配置服务 + sysRoleService *systemService.SysRole // 角色服务 + sysMenuService *systemService.SysMenu // 菜单服务 + sysLogSourceService *systemService.SysLoginSource // 认证源 } // ByUserId 用户ID刷新令牌创建用户信息 @@ -140,86 +70,43 @@ func (s Account) UpdateLoginDateAndIP(info token.UserInfo) bool { return s.sysUserService.Update(user) > 0 } -// CleanLoginRecordCache 清除错误记录次数 -func (s Account) CleanLoginRecordCache(userName string) bool { - cacheKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName) - hasKey, err := redis.Has("", cacheKey) - if hasKey > 0 && err == nil { - return redis.Del("", cacheKey) == nil +// LoginSource 登录认证源 +func (s Account) LoginSource() []model.LoginSourceVo { + rows := s.sysLogSourceService.FindByActive("") + data := make([]model.LoginSourceVo, 0) + for _, v := range rows { + data = append(data, model.LoginSourceVo{ + UID: v.UID, + Name: v.Name, + Type: v.Type, + Icon: v.Icon, + }) } - return false + return data } -// passwordRetryCount 密码重试次数 -func (s Account) passwordRetryCount(userName string) (string, int64, time.Duration, error) { - // 从数据库配置获取登录次数和错误锁定时间 - maxRetryCountStr := s.sysConfigService.FindValueByKey("sys.user.maxRetryCount") - lockTimeStr := s.sysConfigService.FindValueByKey("sys.user.lockTime") - // 验证登录次数和错误锁定时间 - maxRetryCount := parse.Number(maxRetryCountStr) - lockTime := parse.Number(lockTimeStr) +// initLoginSourceUser 初始化登录源用户 +func (s *Account) initLoginSourceUser(uid, sType, username, password string) systemModel.SysUser { + sysUser := systemModel.SysUser{ + UserName: username, + NickName: username, // 昵称使用名称账号 + Password: password, // 原始密码 + UserType: sType, + UserSource: uid, + Sex: "0", // 性别未选择 + StatusFlag: constants.STATUS_YES, // 账号状态激活 + DeptId: 101, // 归属部门为根节点 + CreateBy: sType, // 创建来源 + } - // 验证缓存记录次数 - retryKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName) - retryCount, err := redis.Get("", retryKey) - if retryCount == "" || err != nil { - retryCount = "0" + // 新增用户的角色管理 + sysUser.RoleIds = []int64{5} + // 新增用户的岗位管理 + sysUser.PostIds = []int64{} + + insertId := s.sysUserService.Insert(sysUser) + if insertId > 0 { + sysUser.UserId = insertId } - // 是否超过错误值 - retryCountInt64 := parse.Number(retryCount) - if retryCountInt64 >= int64(maxRetryCount) { - // msg := fmt.Sprintf("密码输入错误 %d 次,帐户锁定 %d 分钟", maxRetryCount, lockTime) - msg := fmt.Errorf("login.errRetryPasswd") // 密码输入错误多次,帐户已被锁定 - return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, fmt.Errorf("%s", msg) - } - return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil -} - -// PasswordCountOrExpireTime 首次登录或密码过期时间 -func (s Account) PasswordCountOrExpireTime(loginCount, passwordUpdateTime int64) (bool, error) { - forcePasswdChange := false - // 从数据库配置获取-首次登录密码修改 - fristPasswdChangeStr := s.sysConfigService.FindValueByKey("sys.user.fristPasswdChange") - if parse.Boolean(fristPasswdChangeStr) { - forcePasswdChange = loginCount < 1 || passwordUpdateTime == 0 - } - - // 非首次登录,判断密码是否过期 - if !forcePasswdChange { - alert, err := s.sysUserService.ValidatePasswordExpireTime(passwordUpdateTime) - if err != nil { - return alert, err - } - forcePasswdChange = alert - } - return forcePasswdChange, nil -} - -// RoleAndMenuPerms 角色和菜单数据权限 -func (s Account) RoleAndMenuPerms(userId int64, isSystemUser bool) ([]string, []string) { - if isSystemUser { - return []string{constants.SYS_ROLE_SYSTEM_KEY}, []string{constants.SYS_PERMISSION_SYSTEM} - } - // 角色key - var roleGroup []string - roles := s.sysRoleService.FindByUserId(userId) - for _, role := range roles { - roleGroup = append(roleGroup, role.RoleKey) - } - // 菜单权限key - perms := s.sysMenuService.FindPermsByUserId(userId) - return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms) -} - -// RouteMenus 前端路由所需要的菜单 -func (s Account) RouteMenus(userId int64, isSystemUser bool) []systemModelVO.Router { - var buildMenus []systemModelVO.Router - if isSystemUser { - menus := s.sysMenuService.BuildTreeMenusByUserId(0) - buildMenus = s.sysMenuService.BuildRouteMenus(menus, "") - } else { - menus := s.sysMenuService.BuildTreeMenusByUserId(userId) - buildMenus = s.sysMenuService.BuildRouteMenus(menus, "") - } - return buildMenus + return s.sysUserService.FindByUserName(username, sType, uid) } diff --git a/src/modules/auth/service/account_info.go b/src/modules/auth/service/account_info.go new file mode 100644 index 00000000..5c22a16b --- /dev/null +++ b/src/modules/auth/service/account_info.go @@ -0,0 +1,36 @@ +package service + +import ( + "be.ems/src/framework/constants" + "be.ems/src/framework/utils/parse" + systemModelVO "be.ems/src/modules/system/model/vo" +) + +// RoleAndMenuPerms 角色和菜单数据权限 +func (s Account) RoleAndMenuPerms(userId int64, isSystemUser bool) ([]string, []string) { + if isSystemUser { + return []string{constants.SYS_ROLE_SYSTEM_KEY}, []string{constants.SYS_PERMISSION_SYSTEM} + } + // 角色key + var roleGroup []string + roles := s.sysRoleService.FindByUserId(userId) + for _, role := range roles { + roleGroup = append(roleGroup, role.RoleKey) + } + // 菜单权限key + perms := s.sysMenuService.FindPermsByUserId(userId) + return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms) +} + +// RouteMenus 前端路由所需要的菜单 +func (s Account) RouteMenus(userId int64, isSystemUser bool) []systemModelVO.Router { + var buildMenus []systemModelVO.Router + if isSystemUser { + menus := s.sysMenuService.BuildTreeMenusByUserId(0) + buildMenus = s.sysMenuService.BuildRouteMenus(menus, "") + } else { + menus := s.sysMenuService.BuildTreeMenusByUserId(userId) + buildMenus = s.sysMenuService.BuildRouteMenus(menus, "") + } + return buildMenus +} diff --git a/src/modules/auth/service/account_ldap.go b/src/modules/auth/service/account_ldap.go new file mode 100644 index 00000000..999fba21 --- /dev/null +++ b/src/modules/auth/service/account_ldap.go @@ -0,0 +1,108 @@ +package service + +import ( + "encoding/json" + "fmt" + + "github.com/go-ldap/ldap/v3" + + "be.ems/src/framework/config" + "be.ems/src/framework/constants" + "be.ems/src/framework/token" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/auth/model" + systemModelVo "be.ems/src/modules/system/model/vo" +) + +// ByLDAP 登录创建用户信息 +func (s *Account) ByLDAP(body model.LoginSourceBody) (token.UserInfo, error) { + info := token.UserInfo{} + rows := s.sysLogSourceService.FindByActive(body.UID) + if len(rows) != 1 { + return info, fmt.Errorf("ldap auth source not exist") + } + item := rows[0] + if item.Config == "" { + return info, fmt.Errorf("ldap auth source config is empty") + } + var source systemModelVo.SysLoginSourceLDAP + if err := json.Unmarshal([]byte(item.Config), &source); err != nil { + return info, err + } + + // 校验LDAP用户 + err := ldapAuth(source, body.Username, body.Password) + if err != nil { + return info, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID) + if sysUser.UserId == 0 || sysUser.UserName == "" { + sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password) + } + if sysUser.UserId == 0 || sysUser.UserName != body.Username { + return info, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == constants.STATUS_YES { + return info, fmt.Errorf("login.errDelFlag") + } + if sysUser.StatusFlag == constants.STATUS_NO { + return info, fmt.Errorf("login.errStatus") + } + + // 登录用户信息 + info.UserId = sysUser.UserId + info.DeptId = sysUser.DeptId + info.User = sysUser + // 用户权限组标识 + if config.IsSystemUser(sysUser.UserId) { + info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM} + } else { + perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId) + info.Permissions = parse.RemoveDuplicates(perms) + } + return info, nil +} + +// ldapAuth 校验LDAP用户 +func ldapAuth(source systemModelVo.SysLoginSourceLDAP, username, password string) error { + // 连接LDAP + l, err := ldap.DialURL(source.URL) + if err != nil { + return err + } + defer l.Close() + + // 绑定DN校验 + if source.BindDN != "" && source.BindPassword != "" { + if err := l.Bind(source.BindDN, source.BindPassword); err != nil { + return fmt.Errorf("ldap user bind %s", err) + } + } + + // 搜索用户 + searchRequest := ldap.NewSearchRequest( + source.BaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, + fmt.Sprintf(source.UserFilter, ldap.EscapeFilter(username)), + []string{"dn", "uid"}, + nil, + ) + sr, err := l.Search(searchRequest) + if err != nil { + return fmt.Errorf("ldap user search %s", err) + } + // for _, entry := range sr.Entries { + // fmt.Printf("%s ==== %v\n", entry.DN, entry.GetAttributeValue("uid")) + // } + if len(sr.Entries) != 1 { + return fmt.Errorf("ldap user does not exist or too many entries returned") + } + + // 校验密码 + if err = l.Bind(sr.Entries[0].DN, password); err != nil { + return fmt.Errorf("ldap user bind %s", err) + } + return nil +} diff --git a/src/modules/auth/service/account_oauth2.go b/src/modules/auth/service/account_oauth2.go new file mode 100644 index 00000000..c9c51d9e --- /dev/null +++ b/src/modules/auth/service/account_oauth2.go @@ -0,0 +1,168 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "strings" + "time" + + "golang.org/x/oauth2" + + "be.ems/src/framework/config" + "be.ems/src/framework/constants" + "be.ems/src/framework/token" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/auth/model" + systemModelVo "be.ems/src/modules/system/model/vo" +) + +// ByOAuth2CodeURL 获取OAuth2登录URL +func (s *Account) ByOAuth2CodeURL(state string) (string, error) { + rows := s.sysLogSourceService.FindByActive(state) + if len(rows) != 1 { + return "", fmt.Errorf("oauth2 auth source not exist") + } + item := rows[0] + if item.Config == "" { + return "", fmt.Errorf("oauth2 auth source config is empty") + } + var source systemModelVo.SysLoginSourceOAuth2 + json.Unmarshal([]byte(item.Config), &source) + + conf := oauth2.Config{ + ClientID: source.ClientID, + ClientSecret: source.ClientSecret, + RedirectURL: source.RedirectURL, + Scopes: source.Scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: source.AuthURL, + TokenURL: source.TokenURL, + }, + } + return conf.AuthCodeURL(state, oauth2.AccessTypeOffline), nil +} + +// ByOAuth2 登录创建用户信息 +func (s *Account) ByOAuth2(body model.LoginSourceOauth2Body) (token.UserInfo, error) { + info := token.UserInfo{} + rows := s.sysLogSourceService.FindByActive(body.State) + if len(rows) != 1 { + return info, fmt.Errorf("oauth2 auth source not exist") + } + item := rows[0] + if item.Config == "" { + return info, fmt.Errorf("oauth2 auth source config is empty") + } + var source systemModelVo.SysLoginSourceOAuth2 + if err := json.Unmarshal([]byte(item.Config), &source); err != nil { + return info, err + } + + // 校验OAuth2用户 + account, err := oauth2Auth(source, body.Code) + if err != nil { + return info, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(account, item.Type, item.UID) + if sysUser.UserId == 0 || sysUser.UserName == "" { + sysUser = s.initLoginSourceUser(item.UID, item.Type, account, account) + } + if sysUser.UserId == 0 || sysUser.UserName != account { + return info, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == constants.STATUS_YES { + return info, fmt.Errorf("login.errDelFlag") + } + if sysUser.StatusFlag == constants.STATUS_NO { + return info, fmt.Errorf("login.errStatus") + } + + // 登录用户信息 + info.UserId = sysUser.UserId + info.DeptId = sysUser.DeptId + info.User = sysUser + // 用户权限组标识 + if config.IsSystemUser(sysUser.UserId) { + info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM} + } else { + perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId) + info.Permissions = parse.RemoveDuplicates(perms) + } + return info, nil +} + +// oauth2Auth 校验OAuth2用户 +func oauth2Auth(source systemModelVo.SysLoginSourceOAuth2, code string) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + conf := oauth2.Config{ + ClientID: source.ClientID, + ClientSecret: source.ClientSecret, + RedirectURL: source.RedirectURL, + Scopes: source.Scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: source.AuthURL, + TokenURL: source.TokenURL, + }, + } + token, err := conf.Exchange(ctx, code) + if err != nil { + return "", err + } + // 使用token创建HTTP客户端 请求用户信息 + resp, err := conf.Client(ctx, token).Get(source.UserURL) + if err != nil { + return "", err + } + defer resp.Body.Close() + // 解析用户信息 + var userInfo map[string]any + if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil { + return "", err + } + + // 读取嵌套数据 + value, found := getValueByPath(userInfo, source.AccountField) + if !found { + return "", fmt.Errorf("oauth2 auth source account field not exist") + } + return fmt.Sprintf("%v", value), nil +} + +// getValueByPath 从嵌套的 map[string]any 获取嵌套键对应的值 +func getValueByPath(data map[string]any, path string) (any, bool) { + keys := strings.Split(path, ".") // 按照 "." 拆分路径 + return getValue(data, keys) +} + +// getValue 是递归查找嵌套 map 的函数 +func getValue(data map[string]any, keys []string) (any, bool) { + if len(keys) == 0 { + return data, false + } + + // 获取当前键 + key := keys[0] + + // 获取当前键的值 + val, ok := data[key] + if !ok { + return nil, false // 找不到键,返回 false + } + + // 如果还有嵌套键,继续查找 + if len(keys) > 1 { + // 递归查找嵌套 map + if reflect.TypeOf(val).Kind() == reflect.Map { + // 将 `any` 转换为 `map[string]any` 类型 + if nestedMap, ok := val.(map[string]any); ok { + return getValue(nestedMap, keys[1:]) + } + } + } + return val, true +} diff --git a/src/modules/auth/service/account_smtp.go b/src/modules/auth/service/account_smtp.go new file mode 100644 index 00000000..020cd4e4 --- /dev/null +++ b/src/modules/auth/service/account_smtp.go @@ -0,0 +1,88 @@ +package service + +import ( + "context" + "crypto/tls" + "encoding/json" + "fmt" + + "github.com/wneessen/go-mail" + + "be.ems/src/framework/config" + "be.ems/src/framework/constants" + "be.ems/src/framework/token" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/auth/model" + systemModelVo "be.ems/src/modules/system/model/vo" +) + +// BySMTP 登录创建用户信息 +func (s *Account) BySMTP(body model.LoginSourceBody) (token.UserInfo, error) { + info := token.UserInfo{} + rows := s.sysLogSourceService.FindByActive(body.UID) + if len(rows) != 1 { + return info, fmt.Errorf("smtp auth source not exist") + } + item := rows[0] + if item.Config == "" { + return info, fmt.Errorf("smtp auth source config is empty") + } + var source systemModelVo.SysLoginSourceSMTP + if err := json.Unmarshal([]byte(item.Config), &source); err != nil { + return info, err + } + + // 校验SMTP用户 + err := smtpAuth(source, body.Username, body.Password) + if err != nil { + return info, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID) + if sysUser.UserId == 0 || sysUser.UserName == "" { + sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password) + } + if sysUser.UserId == 0 || sysUser.UserName != body.Username { + return info, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == constants.STATUS_YES { + return info, fmt.Errorf("login.errDelFlag") + } + if sysUser.StatusFlag == constants.STATUS_NO { + return info, fmt.Errorf("login.errStatus") + } + + // 登录用户信息 + info.UserId = sysUser.UserId + info.DeptId = sysUser.DeptId + info.User = sysUser + // 用户权限组标识 + if config.IsSystemUser(sysUser.UserId) { + info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM} + } else { + perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId) + info.Permissions = parse.RemoveDuplicates(perms) + } + return info, nil +} + +// smtpAuth 校验SMTP用户 +func smtpAuth(source systemModelVo.SysLoginSourceSMTP, username, password string) error { + client, err := mail.NewClient(source.Host, + mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover), + mail.WithUsername(username), + mail.WithPort(source.Port), + mail.WithPassword(password), + mail.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}), + ) + if err != nil { + return fmt.Errorf("failed to create mail client %s", err) + } + // 连接到邮件SMTP服务器 + if err = client.DialWithContext(context.Background()); err != nil { + return err + } + defer client.Close() + return nil +} diff --git a/src/modules/auth/service/account_sysstem.go b/src/modules/auth/service/account_sysstem.go new file mode 100644 index 00000000..21b45238 --- /dev/null +++ b/src/modules/auth/service/account_sysstem.go @@ -0,0 +1,138 @@ +package service + +import ( + "fmt" + "time" + + "be.ems/src/framework/config" + "be.ems/src/framework/constants" + "be.ems/src/framework/database/redis" + "be.ems/src/framework/token" + "be.ems/src/framework/utils/crypto" + "be.ems/src/framework/utils/parse" +) + +// ValidateCaptcha 校验验证码 +func (s Account) ValidateCaptcha(code, uuid string) error { + // 验证码检查,从数据库配置获取验证码开关 true开启,false关闭 + captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled") + if !parse.Boolean(captchaEnabledStr) { + return nil + } + if code == "" || uuid == "" { + // 验证码信息错误 + return fmt.Errorf("captcha.err") + } + verifyKey := constants.CACHE_CAPTCHA_CODE + ":" + uuid + captcha, _ := redis.Get("", verifyKey) + if captcha == "" { + // 验证码已失效 + return fmt.Errorf("captcha.errValid") + } + _ = redis.Del("", verifyKey) + if captcha != code { + // 验证码错误 + return fmt.Errorf("captcha.err") + } + return nil +} + +// ByUsername 登录创建用户信息 +func (s Account) ByUsername(username, password string) (token.UserInfo, error) { + info := token.UserInfo{} + + // 检查密码重试次数 + retryKey, retryCount, lockTime, err := s.passwordRetryCount(username) + if err != nil { + return info, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(username, "System", "#") + if sysUser.UserName != username { + return info, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == constants.STATUS_YES { + return info, fmt.Errorf("login.errDelFlag") + } + if sysUser.StatusFlag == constants.STATUS_NO { + return info, fmt.Errorf("login.errStatus") + } + + // 检验用户密码 + compareBool := crypto.BcryptCompare(password, sysUser.Password) + if compareBool { + s.CleanLoginRecordCache(sysUser.UserName) // 清除错误记录次数 + } else { + _ = redis.Set("", retryKey, retryCount+1, lockTime) + return info, fmt.Errorf("login.errNameOrPasswd") + } + + // 登录用户信息 + info.UserId = sysUser.UserId + info.DeptId = sysUser.DeptId + info.User = sysUser + // 用户权限组标识 + if config.IsSystemUser(sysUser.UserId) { + info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM} + } else { + perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId) + info.Permissions = parse.RemoveDuplicates(perms) + } + return info, nil +} + +// CleanLoginRecordCache 清除错误记录次数 +func (s Account) CleanLoginRecordCache(userName string) bool { + cacheKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName) + hasKey, err := redis.Has("", cacheKey) + if hasKey > 0 && err == nil { + return redis.Del("", cacheKey) == nil + } + return false +} + +// passwordRetryCount 密码重试次数 +func (s Account) passwordRetryCount(userName string) (string, int64, time.Duration, error) { + // 从数据库配置获取登录次数和错误锁定时间 + maxRetryCountStr := s.sysConfigService.FindValueByKey("sys.user.maxRetryCount") + lockTimeStr := s.sysConfigService.FindValueByKey("sys.user.lockTime") + // 验证登录次数和错误锁定时间 + maxRetryCount := parse.Number(maxRetryCountStr) + lockTime := parse.Number(lockTimeStr) + + // 验证缓存记录次数 + retryKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName) + retryCount, err := redis.Get("", retryKey) + if retryCount == "" || err != nil { + retryCount = "0" + } + // 是否超过错误值 + retryCountInt64 := parse.Number(retryCount) + if retryCountInt64 >= int64(maxRetryCount) { + // msg := fmt.Sprintf("密码输入错误 %d 次,帐户锁定 %d 分钟", maxRetryCount, lockTime) + msg := fmt.Errorf("login.errRetryPasswd") // 密码输入错误多次,帐户已被锁定 + return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, fmt.Errorf("%s", msg) + } + return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil +} + +// PasswordCountOrExpireTime 首次登录或密码过期时间 +func (s Account) PasswordCountOrExpireTime(loginCount, passwordUpdateTime int64) (bool, error) { + forcePasswdChange := false + // 从数据库配置获取-首次登录密码修改 + fristPasswdChangeStr := s.sysConfigService.FindValueByKey("sys.user.fristPasswdChange") + if parse.Boolean(fristPasswdChangeStr) { + forcePasswdChange = loginCount < 1 || passwordUpdateTime == 0 + } + + // 非首次登录,判断密码是否过期 + if !forcePasswdChange { + alert, err := s.sysUserService.ValidatePasswordExpireTime(passwordUpdateTime) + if err != nil { + return alert, err + } + forcePasswdChange = alert + } + return forcePasswdChange, nil +} diff --git a/src/modules/auth/service/register.go b/src/modules/auth/service/register.go index 39903be2..9dca45c4 100644 --- a/src/modules/auth/service/register.go +++ b/src/modules/auth/service/register.go @@ -61,12 +61,14 @@ func (s Register) ByUserName(username, password string) (int64, error) { sysUser := systemModel.SysUser{ UserName: username, - NickName: username, // 昵称使用名称账号 - Password: password, // 原始密码 + NickName: username, // 昵称使用名称账号 + Password: password, // 原始密码 + UserType: "System", + UserSource: "#", Sex: "0", // 性别未选择 StatusFlag: constants.STATUS_YES, // 账号状态激活 - DeptId: 100, // 归属部门为根节点 - CreateBy: "register", // 创建来源 + DeptId: 101, // 归属部门为根节点 + CreateBy: "System", // 创建来源 } // 新增用户的角色管理 diff --git a/src/modules/oauth2/controller/oauth2_client.go b/src/modules/system/controller/sys_login_source.go similarity index 51% rename from src/modules/oauth2/controller/oauth2_client.go rename to src/modules/system/controller/sys_login_source.go index 30d0bbf5..2349af9b 100644 --- a/src/modules/oauth2/controller/oauth2_client.go +++ b/src/modules/system/controller/sys_login_source.go @@ -1,8 +1,8 @@ package controller import ( + "encoding/json" "fmt" - "strings" "github.com/gin-gonic/gin" @@ -10,54 +10,54 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/service" + "be.ems/src/modules/system/model" + "be.ems/src/modules/system/service" ) -// NewOauth2Client 实例化控制层 -var NewOauth2Client = &Oauth2ClientController{ - oauth2ClientService: service.NewOauth2ClientService, +// NewLoginSource 实例化控制层 +var NewSysLoginSource = &SysLoginSourceController{ + sysLoginSourceService: service.NewSysLoginSource, } -// Oauth2ClientController 客户端授权管理 控制层处理 +// SysLoginSourceController 认证源管理 控制层处理 // -// PATH /oauth2/client -type Oauth2ClientController struct { - oauth2ClientService *service.Oauth2ClientService // 用户授权第三方应用信息服务 +// PATH /sys/login-source +type SysLoginSourceController struct { + sysLoginSourceService *service.SysLoginSource // 认证源信息服务 } // List 列表 // // GET /list -func (s Oauth2ClientController) List(c *gin.Context) { +func (s SysLoginSourceController) List(c *gin.Context) { query := reqctx.QueryMap(c) - rows, total := s.oauth2ClientService.FindByPage(query) + rows, total := s.sysLoginSourceService.FindByPage(query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } // Info 信息 // -// GET /:clientId -func (s Oauth2ClientController) Info(c *gin.Context) { - clientId := c.Param("clientId") - if clientId == "" { - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: clientId is empty")) +// GET /:id +func (s SysLoginSourceController) Info(c *gin.Context) { + id := c.Param("id") + if id == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) return } - info := s.oauth2ClientService.FindByClientId(clientId) - if info.ClientId == clientId { + info := s.sysLoginSourceService.FindById(parse.Number(id)) + if info.Id == parse.Number(id) { c.JSON(200, resp.OkData(info)) return } - c.JSON(200, resp.ErrMsg("clientId does not exist")) + c.JSON(200, resp.ErrMsg("id does not exist")) } // Add 新增 // // POST / -func (s Oauth2ClientController) Add(c *gin.Context) { - var body model.Oauth2Client +func (s SysLoginSourceController) Add(c *gin.Context) { + var body model.SysLoginSource if err := c.ShouldBindBodyWithJSON(&body); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) @@ -67,23 +67,19 @@ func (s Oauth2ClientController) Add(c *gin.Context) { c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty")) return } - - // 本地IP地址不支持 - localHosts := []string{"127.0.0.1", "localhost", "::ffff:", "::1"} - localHost := false - for _, host := range localHosts { - if strings.Contains(body.IPWhite, host) { - localHost = true - break - } - } - if localHost { - c.JSON(200, resp.ErrMsg("no support local host")) + if len(body.Config) < 7 || !json.Valid([]byte(body.Config)) { + c.JSON(200, resp.ErrMsg("config json format error")) return } + configStr, err := s.sysLoginSourceService.CheckConfigJSON(body.Type, body.Config) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + body.Config = configStr body.CreateBy = reqctx.LoginUserToUserName(c) - insertId := s.oauth2ClientService.Insert(body) + insertId := s.sysLoginSourceService.Insert(body) if insertId > 0 { c.JSON(200, resp.OkData(insertId)) return @@ -94,8 +90,8 @@ func (s Oauth2ClientController) Add(c *gin.Context) { // Edit 更新 // // PUT / -func (s Oauth2ClientController) Edit(c *gin.Context) { - var body model.Oauth2Client +func (s SysLoginSourceController) Edit(c *gin.Context) { + var body model.SysLoginSource if err := c.ShouldBindBodyWithJSON(&body); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) @@ -105,33 +101,32 @@ func (s Oauth2ClientController) Edit(c *gin.Context) { c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) return } - - // 本地IP地址不支持 - localHosts := []string{"127.0.0.1", "localhost", "::ffff:", "::1"} - localHost := false - for _, host := range localHosts { - if strings.Contains(body.IPWhite, host) { - localHost = true - break - } - } - if localHost { - c.JSON(200, resp.ErrMsg("no support local host")) + if len(body.Config) < 7 || !json.Valid([]byte(body.Config)) { + c.JSON(200, resp.ErrMsg("config json format error")) return } + configStr, err := s.sysLoginSourceService.CheckConfigJSON(body.Type, body.Config) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + body.Config = configStr // 查询信息 - info := s.oauth2ClientService.FindById(body.Id) - if info.ClientId == "" || info.Id != body.Id { + info := s.sysLoginSourceService.FindById(body.Id) + if info.Id != body.Id { c.JSON(200, resp.ErrMsg("modification failed, data not exist")) return } - info.Title = body.Title - info.IPWhite = body.IPWhite + info.Type = body.Type + info.Name = body.Name + info.Icon = body.Icon + info.Config = body.Config + info.ActiveFlag = body.ActiveFlag info.Remark = body.Remark info.UpdateBy = reqctx.LoginUserToUserName(c) - rowsAffected := s.oauth2ClientService.Update(info) + rowsAffected := s.sysLoginSourceService.Update(info) if rowsAffected > 0 { c.JSON(200, resp.Ok(nil)) return @@ -142,7 +137,7 @@ func (s Oauth2ClientController) Edit(c *gin.Context) { // Remove 删除 // // DELETE /:id -func (s Oauth2ClientController) Remove(c *gin.Context) { +func (s SysLoginSourceController) Remove(c *gin.Context) { language := reqctx.AcceptLanguage(c) id := c.Param("id") if id == "" { @@ -158,7 +153,7 @@ func (s Oauth2ClientController) Remove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.oauth2ClientService.DeleteByIds(ids) + rows, err := s.sysLoginSourceService.DeleteByIds(ids) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/system/controller/sys_user.go b/src/modules/system/controller/sys_user.go index 3ea14fef..cd63404d 100644 --- a/src/modules/system/controller/sys_user.go +++ b/src/modules/system/controller/sys_user.go @@ -550,15 +550,19 @@ func (s *SysUserController) Export(c *gin.Context) { "C1": i18n.TKey(language, "user.export.nick"), "D1": i18n.TKey(language, "user.export.role"), "E1": i18n.TKey(language, "user.export.deptName"), - "F1": i18n.TKey(language, "user.export.loginIP"), - "G1": i18n.TKey(language, "user.export.loginDate"), - "H1": i18n.TKey(language, "user.export.status"), + "F1": i18n.TKey(language, "user.export.userType"), + "G1": i18n.TKey(language, "user.export.loginIP"), + "H1": i18n.TKey(language, "user.export.loginDate"), + "I1": i18n.TKey(language, "user.export.status"), // "F1": i18n.TKey(language, "user.export.sex"), // "E1": i18n.TKey(language, "user.export.phone"), // "D1": i18n.TKey(language, "user.export.email"), // "I1": i18n.TKey(language, "user.export.deptID"), // "K1": i18n.TKey(language, "user.export.deptLeader"), } + // 读取用户性别字典数据 + dictSysUserType := service.NewSysDictType.FindDataByType("sys_user_type") + // 读取用户性别字典数据 // dictSysUserSex := s.sysDictDataService.SelectDictDataByType("sys_user_sex") // 从第二行开始的数据 @@ -573,6 +577,14 @@ func (s *SysUserController) Export(c *gin.Context) { // break // } // } + // 用户类型 + userType := row.UserType + for _, v := range dictSysUserType { + if row.UserType == v.DataValue && row.UserSource != "#" { + userType = i18n.TKey(language, v.DataLabel) + " " + row.UserSource + break + } + } // 帐号状态 statusValue := i18n.TKey(language, "dictData.disable") if row.StatusFlag == "1" { @@ -581,7 +593,11 @@ func (s *SysUserController) Export(c *gin.Context) { // 用户角色, 默认导出首个 userRole := "" if len(row.Roles) > 0 { - userRole = i18n.TKey(language, row.Roles[0].RoleName) + arr := make([]string, 0) + for _, v := range row.Roles { + arr = append(arr, i18n.TKey(language, v.RoleName)) + } + userRole = strings.Join(arr, ",") } dataCells = append(dataCells, map[string]any{ "A" + idx: row.UserId, @@ -589,9 +605,10 @@ func (s *SysUserController) Export(c *gin.Context) { "C" + idx: row.NickName, "D" + idx: userRole, "E" + idx: row.Dept.DeptName, - "F" + idx: row.LoginIp, - "G" + idx: date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ), - "H" + idx: statusValue, + "F" + idx: userType, + "G" + idx: row.LoginIp, + "H" + idx: date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ), + "I" + idx: statusValue, // "E" + idx: row.PhoneNumber, // "F" + idx: sysUserSex, // "D" + idx: row.Email, @@ -725,7 +742,7 @@ func (s *SysUserController) Import(c *gin.Context) { } // 验证是否存在这个用户 - newSysUser := s.sysUserService.FindByUserName(row["B"]) + newSysUser := s.sysUserService.FindByUserName(row["B"], "System", "#") newSysUser.Password = initPassword newSysUser.UserName = row["B"] newSysUser.NickName = row["C"] diff --git a/src/modules/system/model/sys_login_source.go b/src/modules/system/model/sys_login_source.go new file mode 100644 index 00000000..6f62dedb --- /dev/null +++ b/src/modules/system/model/sys_login_source.go @@ -0,0 +1,22 @@ +package model + +// SysLoginSource 系统第三方认证源 sys_login_source +type SysLoginSource struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` // ID + UID string `gorm:"column:uid" json:"uid"` // UID 16位长度字符串 + Type string `gorm:"column:type" json:"type" binding:"required,oneof=LDAP SMTP OAuth2"` // 认证类型 LDAP SMTP OAuth2 + Name string `gorm:"column:name" json:"name" binding:"required"` // 认证名称 + Icon string `gorm:"column:icon" json:"icon"` // 图标 + ActiveFlag string `gorm:"column:active_flag" json:"activeFlag"` // 激活标记(0未激活 1激活) + SyncFlag string `gorm:"column:sync_flag" json:"syncFlag"` // 同步标记(0未同步 1同步) + Config string `gorm:"column:config" json:"config" binding:"required"` // 配置JSON字符串 + CreateBy string `gorm:"column:create_by" json:"createBy"` // 创建者 + CreateTime int64 `gorm:"column:create_time" json:"createTime"` // 创建时间 + UpdateBy string `gorm:"column:update_by" json:"updateBy"` // 更新者 + UpdateTime int64 `gorm:"column:update_time" json:"updateTime"` // 更新时间 + Remark string `gorm:"column:remark" json:"remark"` // 备注 +} + +func (*SysLoginSource) TableName() string { + return "sys_login_source" +} diff --git a/src/modules/system/model/sys_user.go b/src/modules/system/model/sys_user.go index e2594b0f..e90b66a3 100644 --- a/src/modules/system/model/sys_user.go +++ b/src/modules/system/model/sys_user.go @@ -11,6 +11,8 @@ type SysUser struct { Sex string `json:"sex" gorm:"column:sex"` // 用户性别(0未选择 1男 2女) Avatar string `json:"avatar" gorm:"column:avatar"` // 头像地址 Password string `json:"-" gorm:"column:password"` // 密码 + UserType string `json:"userType" gorm:"column:user_type"` // 用户类型(System系统用户) + UserSource string `json:"userSource" gorm:"column:user_source"` // 用户来源UID (系统#)) StatusFlag string `json:"statusFlag" gorm:"column:status_flag"` // 账号状态(0停用 1正常) DelFlag string `json:"-" gorm:"column:del_flag"` // 删除标记(0存在 1删除) PasswordUpdateTime int64 `json:"passwordUpdateTime" gorm:"column:password_update_time"` // 密码更新时间 diff --git a/src/modules/system/model/vo/login_source.go b/src/modules/system/model/vo/login_source.go new file mode 100644 index 00000000..5f401d6e --- /dev/null +++ b/src/modules/system/model/vo/login_source.go @@ -0,0 +1,28 @@ +package vo + +// SysLoginSourceLDAP LDAP认证源 +type SysLoginSourceLDAP struct { + URL string `json:"url"` // LDAP 服务器(ldap://192.168.9.58:11389) + BaseDN string `json:"baseDN"` // base DN(dc=example,dc=org) + UserFilter string `json:"userFilter"` // 用户过滤规则((&(objectClass=organizationalPerson)(uid=%s))) + BindDN string `json:"bindDN"` // 绑定 DN(cn=admin,dc=example,dc=org) + BindPassword string `json:"bindPassword"` // 绑定密码(adminpassword) +} + +// SysLoginSourceSMTP SMTP认证源 +type SysLoginSourceSMTP struct { + Host string `json:"host"` // SMTP 服务器(smtp.gmail.com) + Port int `json:"port"` // SMTP 端口(587) +} + +// SysLoginSourceOAuth2 OAuth2认证源 +type SysLoginSourceOAuth2 struct { + ClientID string `json:"clientID"` // 客户端ID + ClientSecret string `json:"clientSecret"` // 客户端密钥 + AuthURL string `json:"authURL"` // 认证URL + TokenURL string `json:"tokenURL"` // 令牌URL + Scopes []string `json:"scopes"` // 授权范围 + RedirectURL string `json:"redirectURL"` // 重定向URL + UserURL string `json:"userURL"` // 用户信息URL + AccountField string `json:"accountField"` // 账号字段从用户信息中获取 +} diff --git a/src/modules/system/repository/sys_login_source.go b/src/modules/system/repository/sys_login_source.go new file mode 100644 index 00000000..c9170f8b --- /dev/null +++ b/src/modules/system/repository/sys_login_source.go @@ -0,0 +1,150 @@ +package repository + +import ( + "fmt" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/system/model" +) + +// NewSysLoginSource 实例化数据层 +var NewSysLoginSource = &SysLoginSource{} + +// SysLoginSource 认证源数据层处理 +type SysLoginSource struct{} + +// SelectByPage 分页查询集合 +func (r SysLoginSource) SelectByPage(query map[string]string) ([]model.SysLoginSource, int64) { + tx := db.DB("").Model(&model.SysLoginSource{}) + // 查询条件拼接 + if v, ok := query["name"]; ok && v != "" { + tx = tx.Where("name like ?", v+"%") + } + if v, ok := query["type"]; ok && v != "" { + tx = tx.Where("type = ?", v) + } + if v, ok := query["beginTime"]; ok && v != "" { + if len(v) == 10 { + v = fmt.Sprintf("%s000", v) + } + tx = tx.Where("create_time >= ?", v) + } + if v, ok := query["endTime"]; ok && v != "" { + if len(v) == 10 { + v = fmt.Sprintf("%s999", v) + } + tx = tx.Where("create_time <= ?", v) + } + + // 查询结果 + var total int64 = 0 + rows := []model.SysLoginSource{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 查询数据分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error + if err != nil { + return rows, total + } + return rows, total +} + +// Select 查询集合 +func (r SysLoginSource) Select(param model.SysLoginSource) []model.SysLoginSource { + tx := db.DB("").Model(&model.SysLoginSource{}) + // 查询条件拼接 + if param.UID != "" { + tx = tx.Where("uid = ?", param.UID) + } + if param.Type != "" { + tx = tx.Where("type = ?", param.Type) + } + if param.Name != "" { + tx = tx.Where("name = ?", param.Name) + } + if param.ActiveFlag != "" { + tx = tx.Where("active_flag = ?", param.ActiveFlag) + } + + // 查询数据 + rows := []model.SysLoginSource{} + if err := tx.Find(&rows).Error; err != nil { + return rows + } + return rows +} + +// SelectByIds 通过ID查询信息 +func (r SysLoginSource) SelectByIds(ids []int64) []model.SysLoginSource { + rows := []model.SysLoginSource{} + if len(ids) <= 0 { + return rows + } + tx := db.DB("").Model(&model.SysLoginSource{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// Insert 新增信息 返回新增数据ID +func (r SysLoginSource) Insert(param model.SysLoginSource) int64 { + if param.CreateBy != "" { + ms := time.Now().UnixMilli() + param.UpdateBy = param.CreateBy + param.UpdateTime = ms + param.CreateTime = ms + } + // 执行插入 + if err := db.DB("").Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.Id +} + +// Update 修改信息 返回受影响行数 +func (r SysLoginSource) Update(param model.SysLoginSource) int64 { + if param.Id <= 0 { + return 0 + } + if param.UpdateBy != "" { + param.UpdateTime = time.Now().UnixMilli() + } + tx := db.DB("").Model(&model.SysLoginSource{}) + // 构建查询条件 + tx = tx.Where("id = ?", param.Id) + tx = tx.Omit("id", "create_by", "create_time") + // 执行更新 + if err := tx.Updates(param).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// DeleteByIds 批量删除信息 返回受影响行数 +func (r SysLoginSource) DeleteByIds(ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + tx := db.DB("").Where("id in ?", ids) + // 执行删除 + if err := tx.Delete(&model.SysLoginSource{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} diff --git a/src/modules/system/repository/sys_menu.go b/src/modules/system/repository/sys_menu.go index 3b84a319..146655dc 100644 --- a/src/modules/system/repository/sys_menu.go +++ b/src/modules/system/repository/sys_menu.go @@ -83,14 +83,15 @@ func (r SysMenu) Insert(sysMenu model.SysMenu) int64 { } // 根据菜单类型重置参数 - if sysMenu.MenuType == constants.MENU_TYPE_BUTTON { + switch sysMenu.MenuType { + case constants.MENU_TYPE_BUTTON: sysMenu.Component = "" sysMenu.FrameFlag = "1" sysMenu.CacheFlag = "1" sysMenu.VisibleFlag = "1" sysMenu.MenuPath = "" sysMenu.Icon = "#" - } else if sysMenu.MenuType == constants.MENU_TYPE_DIR { + case constants.MENU_TYPE_DIR: sysMenu.Component = "" sysMenu.FrameFlag = "1" sysMenu.CacheFlag = "1" @@ -118,14 +119,15 @@ func (r SysMenu) Update(sysMenu model.SysMenu) int64 { } // 根据菜单类型重置参数 - if sysMenu.MenuType == constants.MENU_TYPE_BUTTON { + switch sysMenu.MenuType { + case constants.MENU_TYPE_BUTTON: sysMenu.Component = "" sysMenu.FrameFlag = "1" sysMenu.CacheFlag = "1" sysMenu.VisibleFlag = "1" sysMenu.MenuPath = "" sysMenu.Icon = "#" - } else if sysMenu.MenuType == constants.MENU_TYPE_DIR { + case constants.MENU_TYPE_DIR: sysMenu.Component = "" sysMenu.FrameFlag = "1" sysMenu.CacheFlag = "1" diff --git a/src/modules/system/repository/sys_user.go b/src/modules/system/repository/sys_user.go index 987e28ae..962df1b2 100644 --- a/src/modules/system/repository/sys_user.go +++ b/src/modules/system/repository/sys_user.go @@ -31,6 +31,12 @@ func (r SysUser) SelectByPage(query map[string]string, dataScopeSQL string) ([]m if v, ok := query["phone"]; ok && v != "" { tx = tx.Where("phone like ?", fmt.Sprintf("%s%%", v)) } + if v, ok := query["userType"]; ok && v != "" { + tx = tx.Where("user_type = ?", v) + } + if v, ok := query["userSource"]; ok && v != "" { + tx = tx.Where("user_source = ?", v) + } if v, ok := query["statusFlag"]; ok && v != "" { tx = tx.Where("status_flag = ?", v) } @@ -198,6 +204,12 @@ func (r SysUser) CheckUnique(sysUser model.SysUser) int64 { if sysUser.Email != "" { tx = tx.Where("email = ?", sysUser.Email) } + if sysUser.UserType != "" { + tx = tx.Where("user_type = ?", sysUser.UserType) + } + if sysUser.UserSource != "" { + tx = tx.Where("user_source = ?", sysUser.UserSource) + } // 查询数据 var id int64 = 0 @@ -209,14 +221,20 @@ func (r SysUser) CheckUnique(sysUser model.SysUser) int64 { } // SelectByUserName 通过登录账号查询信息 -func (r SysUser) SelectByUserName(userName string) model.SysUser { +func (r SysUser) SelectByUserName(userName, userType, userSource string) model.SysUser { item := model.SysUser{} if userName == "" { return item } + if userType == "" { + userType = "System" + } + if userSource == "" { + userSource = "#" + } tx := db.DB("").Model(&model.SysUser{}) // 构建查询条件 - tx = tx.Where("user_name = ? and del_flag = '0'", userName) + tx = tx.Where("user_name = ? and user_type = ? and user_source = ? and del_flag = '0'", userName, userType, userSource) // 查询数据 if err := tx.Limit(1).Find(&item).Error; err != nil { logger.Errorf("query find err => %v", err.Error()) diff --git a/src/modules/system/service/sys_login_source.go b/src/modules/system/service/sys_login_source.go new file mode 100644 index 00000000..b6a9b949 --- /dev/null +++ b/src/modules/system/service/sys_login_source.go @@ -0,0 +1,95 @@ +package service + +import ( + "encoding/json" + "fmt" + + "be.ems/src/framework/utils/generate" + "be.ems/src/modules/system/model" + "be.ems/src/modules/system/model/vo" + "be.ems/src/modules/system/repository" +) + +// NewSysLoginSource 实例化服务层 +var NewSysLoginSource = &SysLoginSource{ + sysLoginSourceRepository: repository.NewSysLoginSource, +} + +// SysLoginSource 认证源 服务层处理 +type SysLoginSource struct { + sysLoginSourceRepository *repository.SysLoginSource // 认证源表 +} + +// FindByPage 分页查询 +func (s SysLoginSource) FindByPage(query map[string]string) ([]model.SysLoginSource, int64) { + return s.sysLoginSourceRepository.SelectByPage(query) +} + +// FindById 查询ID +func (s SysLoginSource) FindById(id int64) model.SysLoginSource { + rows := s.sysLoginSourceRepository.SelectByIds([]int64{id}) + if len(rows) > 0 { + return rows[0] + } + return model.SysLoginSource{} +} + +// Insert 新增 +func (s SysLoginSource) Insert(param model.SysLoginSource) int64 { + param.UID = generate.Code(8) + return s.sysLoginSourceRepository.Insert(param) +} + +// Update 更新 +func (s SysLoginSource) Update(param model.SysLoginSource) int64 { + return s.sysLoginSourceRepository.Update(param) +} + +// DeleteByIds 批量删除 +func (s SysLoginSource) DeleteByIds(ids []int64) (int64, error) { + // 检查是否存在 + arr := s.sysLoginSourceRepository.SelectByIds(ids) + if len(arr) <= 0 { + // return 0, fmt.Errorf("没有权限访问认证源数据!") + return 0, fmt.Errorf("no permission to access authentication source data") + } + if len(arr) == len(ids) { + return s.sysLoginSourceRepository.DeleteByIds(ids), nil + } + // return 0, fmt.Errorf("删除认证源信息失败!") + return 0, fmt.Errorf("failed to delete authentication source information") +} + +// FindByActive 查询激活 +func (s SysLoginSource) FindByActive(uid string) []model.SysLoginSource { + param := model.SysLoginSource{ + ActiveFlag: "1", + } + if uid != "" { + param.UID = uid + } + return s.sysLoginSourceRepository.Select(param) +} + +// CheckConfigJSON 检查配置JSON +func (s SysLoginSource) CheckConfigJSON(sType, sConfig string) (string, error) { + var source any + switch sType { + case "LDAP": + source = new(vo.SysLoginSourceLDAP) + case "SMTP": + source = new(vo.SysLoginSourceSMTP) + case "OAuth2": + source = new(vo.SysLoginSourceOAuth2) + default: + return "", fmt.Errorf("unsupported login source type: %s", sType) + } + if err := json.Unmarshal([]byte(sConfig), &source); err != nil { + return "", fmt.Errorf("config json format error for %s type: %s", sType, err.Error()) + } + configByte, err := json.Marshal(source) + if err != nil { + return "", fmt.Errorf("config json format error") + } + return string(configByte), nil +} diff --git a/src/modules/system/service/sys_user.go b/src/modules/system/service/sys_user.go index 1f734149..6cd2b33a 100644 --- a/src/modules/system/service/sys_user.go +++ b/src/modules/system/service/sys_user.go @@ -189,7 +189,9 @@ func (s SysUser) DeleteByIds(userIds []int64) (int64, error) { // CheckUniqueByUserName 检查用户名称是否唯一 func (s SysUser) CheckUniqueByUserName(userName string, userId int64) bool { uniqueId := s.sysUserRepository.CheckUnique(model.SysUser{ - UserName: userName, + UserName: userName, + UserType: "System", + UserSource: "#", }) if uniqueId == userId { return true @@ -200,7 +202,9 @@ func (s SysUser) CheckUniqueByUserName(userName string, userId int64) bool { // CheckUniqueByPhone 检查手机号码是否唯一 func (s SysUser) CheckUniqueByPhone(phone string, userId int64) bool { uniqueId := s.sysUserRepository.CheckUnique(model.SysUser{ - Phone: phone, + Phone: phone, + UserType: "System", + UserSource: "#", }) if uniqueId == userId { return true @@ -211,7 +215,9 @@ func (s SysUser) CheckUniqueByPhone(phone string, userId int64) bool { // CheckUniqueByEmail 检查Email是否唯一 func (s SysUser) CheckUniqueByEmail(email string, userId int64) bool { uniqueId := s.sysUserRepository.CheckUnique(model.SysUser{ - Email: email, + Email: email, + UserType: "System", + UserSource: "#", }) if uniqueId == userId { return true @@ -220,8 +226,10 @@ func (s SysUser) CheckUniqueByEmail(email string, userId int64) bool { } // FindByUserName 通过用户名查询用户信息 -func (s SysUser) FindByUserName(userName string) model.SysUser { - userinfo := s.sysUserRepository.SelectByUserName(userName) +// userType 系统sys +// userSource 系统# +func (s SysUser) FindByUserName(userName, userType, userSource string) model.SysUser { + userinfo := s.sysUserRepository.SelectByUserName(userName, userType, userSource) if userinfo.UserName != userName { return userinfo } diff --git a/src/modules/system/system.go b/src/modules/system/system.go index d4cca368..18e861c1 100644 --- a/src/modules/system/system.go +++ b/src/modules/system/system.go @@ -429,6 +429,35 @@ func Setup(router *gin.Engine) { controller.NewSysUser.Import, ) } + + // 第三方认证-配置认证源 + sysLoginSource := controller.NewSysLoginSource + sysLoginSourceGroup := router.Group("/system/login-source") + { + sysLoginSourceGroup.GET("/list", + middleware.AuthorizeUser(map[string][]string{"hasPerms": {"system:loginSource:list"}}), + sysLoginSource.List, + ) + sysLoginSourceGroup.GET("/:id", + middleware.AuthorizeUser(map[string][]string{"hasPerms": {"system:loginSource:query"}}), + sysLoginSource.Info, + ) + sysLoginSourceGroup.POST("", + middleware.AuthorizeUser(map[string][]string{"hasPerms": {"system:loginSource:add"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.sysLoginSource", middleware.BUSINESS_TYPE_INSERT)), + sysLoginSource.Add, + ) + sysLoginSourceGroup.PUT("", + middleware.AuthorizeUser(map[string][]string{"hasPerms": {"system:loginSource:edit"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.sysLoginSource", middleware.BUSINESS_TYPE_UPDATE)), + sysLoginSource.Edit, + ) + sysLoginSourceGroup.DELETE("/:id", + middleware.AuthorizeUser(map[string][]string{"hasPerms": {"system:loginSource:remove"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.sysLoginSource", middleware.BUSINESS_TYPE_DELETE)), + sysLoginSource.Remove, + ) + } } // InitLoad 初始参数 From 72e04a140d60d32221c3406db6b551b270710629 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:35:18 +0800 Subject: [PATCH 70/80] =?UTF-8?q?feat:=20=E5=AE=A2=E6=88=B7=E7=AB=AFoauth2?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.go | 4 +- src/modules/auth/auth.go | 58 ++++++ .../{oauth2 => auth}/controller/oauth2.go | 4 +- src/modules/auth/controller/oauth2_client.go | 168 ++++++++++++++++++ .../model/oauth2_body.go} | 7 + .../{oauth2 => auth}/model/oauth2_client.go | 0 .../model/oauth2_log_login.go | 0 .../repository/oauth2_client.go | 2 +- .../repository/oauth2_log_login.go | 7 +- .../{oauth2 => auth}/service/oauth2.go | 4 +- .../{oauth2 => auth}/service/oauth2_client.go | 8 +- .../service/oauth2_log_login.go | 4 +- .../{oauth2/open_api.go => oam/oauth2_api.go} | 6 +- src/modules/oauth2/model/code_query.go | 8 - src/modules/oauth2/oauth2.go | 74 -------- 15 files changed, 252 insertions(+), 102 deletions(-) rename src/modules/{oauth2 => auth}/controller/oauth2.go (98%) create mode 100644 src/modules/auth/controller/oauth2_client.go rename src/modules/{oauth2/model/token_body.go => auth/model/oauth2_body.go} (67%) rename src/modules/{oauth2 => auth}/model/oauth2_client.go (100%) rename src/modules/{oauth2 => auth}/model/oauth2_log_login.go (100%) rename src/modules/{oauth2 => auth}/repository/oauth2_client.go (99%) rename src/modules/{oauth2 => auth}/repository/oauth2_log_login.go (96%) rename src/modules/{oauth2 => auth}/service/oauth2.go (96%) rename src/modules/{oauth2 => auth}/service/oauth2_client.go (87%) rename src/modules/{oauth2 => auth}/service/oauth2_log_login.go (96%) rename src/modules/{oauth2/open_api.go => oam/oauth2_api.go} (85%) delete mode 100644 src/modules/oauth2/model/code_query.go delete mode 100644 src/modules/oauth2/oauth2.go diff --git a/src/app.go b/src/app.go index da30bf86..407f533a 100644 --- a/src/app.go +++ b/src/app.go @@ -17,7 +17,6 @@ import ( networkelement "be.ems/src/modules/network_element" "be.ems/src/modules/notification" "be.ems/src/modules/oam" - "be.ems/src/modules/oauth2" "be.ems/src/modules/system" "be.ems/src/modules/tool" "be.ems/src/modules/trace" @@ -84,10 +83,9 @@ func ModulesRoute(app *gin.Engine) { system.Setup(app) // 认证模块 auth.Setup(app) - // 开放客户端模块 - oauth2.Setup(app) // 网元OAM对接 oam.Setup(app) + oam.SetupOauth2(app) // 通用模块 common.Setup(app) diff --git a/src/modules/auth/auth.go b/src/modules/auth/auth.go index 801e916f..d177b4b4 100644 --- a/src/modules/auth/auth.go +++ b/src/modules/auth/auth.go @@ -116,4 +116,62 @@ func Setup(router *gin.Engine) { ) } + // 客户端授权管理 + oauth2Client := controller.NewOauth2Client + oauth2ClientGroup := router.Group("/oauth2/client") + { + oauth2ClientGroup.GET("/list", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + oauth2Client.List, + ) + oauth2ClientGroup.GET("/:clientId", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + oauth2Client.Info, + ) + oauth2ClientGroup.POST("", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_INSERT)), + oauth2Client.Add, + ) + oauth2ClientGroup.PUT("", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_UPDATE)), + oauth2Client.Edit, + ) + oauth2ClientGroup.DELETE("/:id", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_DELETE)), + oauth2Client.Remove, + ) + } + + // 授权认证 + oauth2 := controller.NewOauth2 + oauth2Group := router.Group("/oauth2") + { + oauth2Group.GET("/authorize", + middleware.RateLimit(middleware.LimitOption{ + Time: 60, + Count: 30, + Type: middleware.LIMIT_IP, + }), + oauth2.Authorize, + ) + oauth2Group.POST("/token", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + oauth2.Token, + ) + oauth2Group.POST("/refresh-token", + middleware.RateLimit(middleware.LimitOption{ + Time: 60, + Count: 5, + Type: middleware.LIMIT_IP, + }), + oauth2.RefreshToken, + ) + } } diff --git a/src/modules/oauth2/controller/oauth2.go b/src/modules/auth/controller/oauth2.go similarity index 98% rename from src/modules/oauth2/controller/oauth2.go rename to src/modules/auth/controller/oauth2.go index bb8fceb3..6da8add9 100644 --- a/src/modules/oauth2/controller/oauth2.go +++ b/src/modules/auth/controller/oauth2.go @@ -11,8 +11,8 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/token" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/service" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/service" ) // NewOauth2 实例化控制层 diff --git a/src/modules/auth/controller/oauth2_client.go b/src/modules/auth/controller/oauth2_client.go new file mode 100644 index 00000000..830c9b71 --- /dev/null +++ b/src/modules/auth/controller/oauth2_client.go @@ -0,0 +1,168 @@ +package controller + +import ( + "fmt" + "strings" + + "github.com/gin-gonic/gin" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/service" +) + +// NewOauth2Client 实例化控制层 +var NewOauth2Client = &Oauth2ClientController{ + oauth2ClientService: service.NewOauth2ClientService, +} + +// Oauth2ClientController 客户端授权管理 控制层处理 +// +// PATH /oauth2/client +type Oauth2ClientController struct { + oauth2ClientService *service.Oauth2ClientService // 用户授权第三方应用信息服务 +} + +// List 列表 +// +// GET /list +func (s Oauth2ClientController) List(c *gin.Context) { + query := reqctx.QueryMap(c) + rows, total := s.oauth2ClientService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} + +// Info 信息 +// +// GET /:clientId +func (s Oauth2ClientController) Info(c *gin.Context) { + clientId := c.Param("clientId") + if clientId == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: clientId is empty")) + return + } + + info := s.oauth2ClientService.FindByClientId(clientId) + if info.ClientId == clientId { + c.JSON(200, resp.OkData(info)) + return + } + c.JSON(200, resp.ErrMsg("clientId does not exist")) +} + +// Add 新增 +// +// POST / +func (s Oauth2ClientController) Add(c *gin.Context) { + var body model.Oauth2Client + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if body.Id > 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty")) + return + } + + // 本地IP地址不支持 + localHosts := []string{"127.0.0.1", "localhost", "::ffff:", "::1"} + localHost := false + for _, host := range localHosts { + if strings.Contains(body.IPWhite, host) { + localHost = true + break + } + } + if localHost { + c.JSON(200, resp.ErrMsg("no support local host")) + return + } + + body.CreateBy = reqctx.LoginUserToUserName(c) + insertId := s.oauth2ClientService.Insert(body) + if insertId > 0 { + c.JSON(200, resp.OkData(insertId)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// Edit 更新 +// +// PUT / +func (s Oauth2ClientController) Edit(c *gin.Context) { + var body model.Oauth2Client + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if body.Id <= 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + // 本地IP地址不支持 + localHosts := []string{"127.0.0.1", "localhost", "::ffff:", "::1"} + localHost := false + for _, host := range localHosts { + if strings.Contains(body.IPWhite, host) { + localHost = true + break + } + } + if localHost { + c.JSON(200, resp.ErrMsg("no support local host")) + return + } + + // 查询信息 + info := s.oauth2ClientService.FindById(body.Id) + if info.ClientId == "" || info.Id != body.Id { + c.JSON(200, resp.ErrMsg("modification failed, data not exist")) + return + } + + info.Title = body.Title + info.IPWhite = body.IPWhite + info.Remark = body.Remark + info.UpdateBy = reqctx.LoginUserToUserName(c) + rowsAffected := s.oauth2ClientService.Update(info) + if rowsAffected > 0 { + c.JSON(200, resp.Ok(nil)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// Remove 删除 +// +// DELETE /:id +func (s Oauth2ClientController) Remove(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + id := c.Param("id") + if id == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + // 处理字符转id数组后去重 + uniqueIDs := parse.RemoveDuplicatesToArray(id, ",") + // 转换成int64数组类型 + ids := make([]int64, 0) + for _, v := range uniqueIDs { + ids = append(ids, parse.Number(v)) + } + + rows, err := s.oauth2ClientService.DeleteByIds(ids) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, resp.OkMsg(msg)) +} diff --git a/src/modules/oauth2/model/token_body.go b/src/modules/auth/model/oauth2_body.go similarity index 67% rename from src/modules/oauth2/model/token_body.go rename to src/modules/auth/model/oauth2_body.go index 2f82ab8f..17a8e165 100644 --- a/src/modules/oauth2/model/token_body.go +++ b/src/modules/auth/model/oauth2_body.go @@ -8,3 +8,10 @@ type TokenBody struct { Code string `json:"code"` // 授权拿到的code值 RefreshToken string `json:"refreshToken"` // 刷新令牌 } + +// CodeQuery 重定向授权码参数 +type CodeQuery struct { + RedirectUrl string `form:"redirectUrl" binding:"required"` // 授权回调地址 + ClientId string `form:"clientId" binding:"required"` // 申请得到的客户端ID + State string `form:"state" binding:"required"` // 随机字符串,认证服务器会原封不动地返回这个值 +} diff --git a/src/modules/oauth2/model/oauth2_client.go b/src/modules/auth/model/oauth2_client.go similarity index 100% rename from src/modules/oauth2/model/oauth2_client.go rename to src/modules/auth/model/oauth2_client.go diff --git a/src/modules/oauth2/model/oauth2_log_login.go b/src/modules/auth/model/oauth2_log_login.go similarity index 100% rename from src/modules/oauth2/model/oauth2_log_login.go rename to src/modules/auth/model/oauth2_log_login.go diff --git a/src/modules/oauth2/repository/oauth2_client.go b/src/modules/auth/repository/oauth2_client.go similarity index 99% rename from src/modules/oauth2/repository/oauth2_client.go rename to src/modules/auth/repository/oauth2_client.go index 1c7253c4..503ea2c4 100644 --- a/src/modules/oauth2/repository/oauth2_client.go +++ b/src/modules/auth/repository/oauth2_client.go @@ -6,7 +6,7 @@ import ( "be.ems/src/framework/database/db" "be.ems/src/framework/logger" - "be.ems/src/modules/oauth2/model" + "be.ems/src/modules/auth/model" ) // NewOauth2Client 实例化数据层 diff --git a/src/modules/oauth2/repository/oauth2_log_login.go b/src/modules/auth/repository/oauth2_log_login.go similarity index 96% rename from src/modules/oauth2/repository/oauth2_log_login.go rename to src/modules/auth/repository/oauth2_log_login.go index f712b9d4..71dc09b7 100644 --- a/src/modules/oauth2/repository/oauth2_log_login.go +++ b/src/modules/auth/repository/oauth2_log_login.go @@ -7,7 +7,7 @@ import ( "be.ems/src/framework/database/db" "be.ems/src/framework/logger" - "be.ems/src/modules/oauth2/model" + "be.ems/src/modules/auth/model" ) // NewOauth2LogLogin 实例化数据层 @@ -69,9 +69,10 @@ func (r Oauth2LogLoginRepository) SelectByPage(query map[string]string) ([]model sortOrder := sortOrderArr[i] // 排序字段 sort := "id" - if sortBy == "loginIp" { + switch sortBy { + case "loginIp": sort = "login_ip" - } else if sortBy == "createTime" { + case "createTime": sort = "create_time" } // 排序方式 diff --git a/src/modules/oauth2/service/oauth2.go b/src/modules/auth/service/oauth2.go similarity index 96% rename from src/modules/oauth2/service/oauth2.go rename to src/modules/auth/service/oauth2.go index 3ca444c4..81b29c77 100644 --- a/src/modules/oauth2/service/oauth2.go +++ b/src/modules/auth/service/oauth2.go @@ -10,8 +10,8 @@ import ( "be.ems/src/framework/token" "be.ems/src/framework/utils/crypto" "be.ems/src/framework/utils/generate" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/repository" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/repository" ) // NewOauth2Service 实例化服务层 diff --git a/src/modules/oauth2/service/oauth2_client.go b/src/modules/auth/service/oauth2_client.go similarity index 87% rename from src/modules/oauth2/service/oauth2_client.go rename to src/modules/auth/service/oauth2_client.go index 6edc055f..de44d6c0 100644 --- a/src/modules/oauth2/service/oauth2_client.go +++ b/src/modules/auth/service/oauth2_client.go @@ -4,8 +4,8 @@ import ( "fmt" "be.ems/src/framework/utils/generate" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/repository" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/repository" ) // NewOauth2ClientService 实例化服务层 @@ -55,11 +55,11 @@ func (s Oauth2ClientService) DeleteByIds(ids []int64) (int64, error) { arr := s.oauth2ClientRepository.SelectByIds(ids) if len(arr) <= 0 { // return 0, fmt.Errorf("没有权限访问用户授权第三方应用数据!") - return 0, fmt.Errorf("No permission to access user-authorized third-party application data!") + return 0, fmt.Errorf("no permission to access user-authorized third-party application data") } if len(arr) == len(ids) { return s.oauth2ClientRepository.DeleteByIds(ids), nil } // return 0, fmt.Errorf("删除用户授权第三方应用信息失败!") - return 0, fmt.Errorf("Failed to delete user-authorized third-party application information!") + return 0, fmt.Errorf("failed to delete user-authorized third-party application information") } diff --git a/src/modules/oauth2/service/oauth2_log_login.go b/src/modules/auth/service/oauth2_log_login.go similarity index 96% rename from src/modules/oauth2/service/oauth2_log_login.go rename to src/modules/auth/service/oauth2_log_login.go index e400fa9c..cd30dc01 100644 --- a/src/modules/oauth2/service/oauth2_log_login.go +++ b/src/modules/auth/service/oauth2_log_login.go @@ -6,8 +6,8 @@ import ( "be.ems/src/framework/constants" "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/file" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/repository" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/repository" ) // NewOauth2LogLogin 实例化服务层 diff --git a/src/modules/oauth2/open_api.go b/src/modules/oam/oauth2_api.go similarity index 85% rename from src/modules/oauth2/open_api.go rename to src/modules/oam/oauth2_api.go index 84f96e03..f8022cff 100644 --- a/src/modules/oauth2/open_api.go +++ b/src/modules/oam/oauth2_api.go @@ -1,4 +1,4 @@ -package oauth2 +package oam import ( "github.com/gin-gonic/gin" @@ -8,8 +8,8 @@ import ( neController "be.ems/src/modules/network_element/controller" ) -// openAPI 客户端授权开放接口 -func openAPI(router *gin.Engine) { +// SetupOauth2 客户端授权开放接口 +func SetupOauth2(router *gin.Engine) { openApiGroup := router.Group("/open-api") // 监控 diff --git a/src/modules/oauth2/model/code_query.go b/src/modules/oauth2/model/code_query.go deleted file mode 100644 index 9c32a195..00000000 --- a/src/modules/oauth2/model/code_query.go +++ /dev/null @@ -1,8 +0,0 @@ -package model - -// CodeQuery 重定向授权码参数 -type CodeQuery struct { - RedirectUrl string `form:"redirectUrl" binding:"required"` // 授权回调地址 - ClientId string `form:"clientId" binding:"required"` // 申请得到的客户端ID - State string `form:"state" binding:"required"` // 随机字符串,认证服务器会原封不动地返回这个值 -} diff --git a/src/modules/oauth2/oauth2.go b/src/modules/oauth2/oauth2.go deleted file mode 100644 index 7cc1cbac..00000000 --- a/src/modules/oauth2/oauth2.go +++ /dev/null @@ -1,74 +0,0 @@ -package oauth2 - -import ( - "github.com/gin-gonic/gin" - - "be.ems/src/framework/logger" - "be.ems/src/framework/middleware" - "be.ems/src/modules/oauth2/controller" -) - -// Setup 模块路由注册 -func Setup(router *gin.Engine) { - logger.Infof("开始加载 ====> oauth2 模块路由") - - // 客户端授权管理 - oauth2ClientGroup := router.Group("/oauth2/client") - { - oauth2ClientGroup.GET("/list", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - controller.NewOauth2Client.List, - ) - oauth2ClientGroup.GET("/:clientId", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - controller.NewOauth2Client.Info, - ) - oauth2ClientGroup.POST("", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_INSERT)), - controller.NewOauth2Client.Add, - ) - oauth2ClientGroup.PUT("", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_UPDATE)), - controller.NewOauth2Client.Edit, - ) - oauth2ClientGroup.DELETE("/:id", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_DELETE)), - controller.NewOauth2Client.Remove, - ) - } - - // 授权认证 - oauth2Group := router.Group("/oauth2") - { - oauth2Group.GET("/authorize", - middleware.RateLimit(middleware.LimitOption{ - Time: 60, - Count: 30, - Type: middleware.LIMIT_IP, - }), - controller.NewOauth2.Authorize, - ) - oauth2Group.POST("/token", - middleware.RateLimit(middleware.LimitOption{ - Time: 180, - Count: 15, - Type: middleware.LIMIT_IP, - }), - controller.NewOauth2.Token, - ) - oauth2Group.POST("/refresh-token", - middleware.RateLimit(middleware.LimitOption{ - Time: 60, - Count: 5, - Type: middleware.LIMIT_IP, - }), - controller.NewOauth2.RefreshToken, - ) - } - - // ==== 授权认证的开放接口 ==== - openAPI(router) -} From fa8da36b9012a33103d897063396473f6df54554 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:36:57 +0800 Subject: [PATCH 71/80] =?UTF-8?q?style:=20=E8=AE=A4=E8=AF=81=E6=BA=90?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=93=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/model/{login_source_vo.go => login_source_body.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/modules/auth/model/{login_source_vo.go => login_source_body.go} (100%) diff --git a/src/modules/auth/model/login_source_vo.go b/src/modules/auth/model/login_source_body.go similarity index 100% rename from src/modules/auth/model/login_source_vo.go rename to src/modules/auth/model/login_source_body.go From e3008c8de57a260ae073f2801046b5b8e44a6afc Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:37:24 +0800 Subject: [PATCH 72/80] =?UTF-8?q?fix:=20=E6=93=8D=E4=BD=9C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=E4=BF=A1=E6=81=AFjson=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/middleware/operate_log.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/framework/middleware/operate_log.go b/src/framework/middleware/operate_log.go index 61346792..32b378f7 100644 --- a/src/framework/middleware/operate_log.go +++ b/src/framework/middleware/operate_log.go @@ -2,7 +2,6 @@ package middleware import ( "encoding/json" - "fmt" "reflect" "strings" "time" @@ -134,8 +133,15 @@ func OperateLog(options Options) gin.HandlerFunc { contentDisposition := c.Writer.Header().Get("Content-Disposition") contentType := c.Writer.Header().Get("Content-Type") content := contentType + contentDisposition - msg := fmt.Sprintf(`{"status":"%d","size":%d,"content-type":"%s"}`, status, c.Writer.Size(), content) - operaLog.OperaMsg = msg + msgByte, err := json.Marshal(map[string]any{ + "status": status, + "size": c.Writer.Size(), + "content-type": content, + }) + if err != nil { + operaLog.OperaMsg = "" + } + operaLog.OperaMsg = string(msgByte) } // 日志记录时间 From e1c14b69bf64f13b7daf34d2fc07ce79b0e8fe2d Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:38:30 +0800 Subject: [PATCH 73/80] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=89=A7=E8=A1=8C=E5=BC=82=E5=B8=B8=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=88=A4=E6=96=AD=E5=BF=BD=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 11 ++++++++++- src/framework/database/db/expand.go | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 498a7341..a75d47af 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,6 +12,15 @@ "program": "main.go", "console": "integratedTerminal", "args": ["--env", "local", "-c", "./local/omc.yaml"] - } + }, + { + "name": "调试更新数据库", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "main.go", + "console": "integratedTerminal", + "args": ["-c", "./local/omc.yaml", "--sqlPath", "./build/database/std/upgrade", "--sqlSource", "std"] + } ] } \ No newline at end of file diff --git a/src/framework/database/db/expand.go b/src/framework/database/db/expand.go index e17d3ddb..ec4af539 100644 --- a/src/framework/database/db/expand.go +++ b/src/framework/database/db/expand.go @@ -106,7 +106,7 @@ func processSQLFile(db *gorm.DB, filePath string) { } else if strings.Contains(errorStr, "duplicate entry") { // 忽略重复记录错误 // Error 1062 (23000): Duplicate entry 'value' for key 'key_name' - log.Println(errorStr) + log.Println(err.Error()) } else if strings.Contains(errorStr, "unknown column") { // 忽略未知字段错误 // Error 1054 (42S22): Unknown column 'field_name' in 'table' @@ -114,6 +114,10 @@ func processSQLFile(db *gorm.DB, filePath string) { // 忽略删除字段或索引错误 // Error 1091 (42000): Can't DROP COLUMN `field_name`; check that it exists // Error 1091 (42000): Can't DROP 'idx_ne_type_id'; check that column/key exists + } else if strings.Contains(errorStr, "doesn't match") { + // 忽略列数不匹配错误 + // Error 1136 (21S01): Column count doesn't match value count at row 1 + log.Println(err.Error()) } else { // 其他错误终止程序 log.Fatalln(errorStr) From 48254fae6d59af51ffbb720ac8afff830e7ef46c Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:46:21 +0800 Subject: [PATCH 74/80] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96ws=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=99=A8=E5=AE=9E=E4=BE=8B=E5=8C=96=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ws/ws.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/modules/ws/ws.go b/src/modules/ws/ws.go index af8147f4..8407c478 100644 --- a/src/modules/ws/ws.go +++ b/src/modules/ws/ws.go @@ -14,36 +14,33 @@ func Setup(router *gin.Engine) { logger.Infof("开始加载 ====> ws 模块路由") // WebSocket 协议 + ws := controller.NewWSController wsGroup := router.Group("/ws") { wsGroup.GET("", middleware.AuthorizeUser(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.ws", collectlogs.BUSINESS_TYPE_OTHER)), - controller.NewWSController.WS, + ws.WS, ) wsGroup.GET("/test", middleware.AuthorizeUser(nil), - controller.NewWSController.Test, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.ws", collectlogs.BUSINESS_TYPE_OTHER)), + ws.Test, ) wsGroup.GET("/ssh", middleware.AuthorizeUser(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.ws", collectlogs.BUSINESS_TYPE_OTHER)), - controller.NewWSController.SSH, + ws.SSH, ) wsGroup.GET("/telnet", middleware.AuthorizeUser(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.ws", collectlogs.BUSINESS_TYPE_OTHER)), - controller.NewWSController.Telnet, + ws.Telnet, ) wsGroup.GET("/redis", middleware.AuthorizeUser(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.ws", collectlogs.BUSINESS_TYPE_OTHER)), - controller.NewWSController.Redis, + ws.Redis, ) wsGroup.GET("/view", middleware.AuthorizeUser(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.ws", collectlogs.BUSINESS_TYPE_OTHER)), - controller.NewWSController.ShellView, + ws.ShellView, ) } } From 695d2e6c8f0eddd8eb09eac26eeec728fd472604 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:47:49 +0800 Subject: [PATCH 75/80] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- go.mod | 18 ++++++++----- go.sum | 79 ++++++++++++++++++++++++++---------------------------- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index c38e16c7..1562caa0 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,5 @@ debug/ main # Build Output -local/omc_db.sqlite +local/*.sqlite omc diff --git a/go.mod b/go.mod index 000c9eb6..de6fd42b 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,10 @@ require ( github.com/expr-lang/expr v1.17.5 github.com/gin-gonic/gin v1.10.1 github.com/glebarez/sqlite v1.11.0 + github.com/go-ldap/ldap/v3 v3.4.11 github.com/godoes/ginprom v0.3.7 github.com/golang-jwt/jwt/v5 v5.3.0 - github.com/gopacket/gopacket v1.3.1 + github.com/gopacket/gopacket v1.4.0 github.com/gorilla/websocket v1.5.3 github.com/linxGnu/gosmpp v0.3.1 github.com/matoous/go-nanoid/v2 v2.1.0 @@ -21,7 +22,7 @@ require ( github.com/prometheus-community/pro-bing v0.7.0 github.com/redis/go-redis/v9 v9.11.0 github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v4 v4.25.6 + github.com/shirou/gopsutil/v4 v4.25.7 github.com/spf13/pflag v1.0.7 github.com/spf13/viper v1.20.1 github.com/swaggo/files v1.0.1 @@ -31,7 +32,8 @@ require ( github.com/wneessen/go-mail v0.6.2 github.com/xuri/excelize/v2 v2.9.0 golang.org/x/crypto v0.40.0 - golang.org/x/text v0.27.0 + golang.org/x/oauth2 v0.30.0 + golang.org/x/text v0.28.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.6.0 gorm.io/gorm v1.30.0 @@ -39,6 +41,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.2.0 // indirect @@ -53,6 +56,7 @@ require ( github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect @@ -62,7 +66,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -108,11 +112,11 @@ require ( golang.org/x/arch v0.16.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/image v0.26.0 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect google.golang.org/protobuf v1.36.6 // indirect modernc.org/libc v1.62.1 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/go.sum b/go.sum index 816253b8..1292a6bd 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,11 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= 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/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= 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= @@ -22,11 +21,9 @@ 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= @@ -58,6 +55,10 @@ github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU= +github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -79,8 +80,8 @@ github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godoes/ginprom v0.3.7 h1:HlKZhp2qS23YPpBWrP1K1+XZQFVruC6leUqkm/1ImFE= @@ -89,7 +90,6 @@ github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9v github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= 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= @@ -98,21 +98,32 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17k github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gopacket/gopacket v1.3.1 h1:ZppWyLrOJNZPe5XkdjLbtuTkfQoxQ0xyMJzQCqtqaPU= -github.com/gopacket/gopacket v1.3.1/go.mod h1:3I13qcqSpB2R9fFQg866OOgzylYkZxLTmkvcXhvf6qg= +github.com/gopacket/gopacket v1.4.0 h1:cr1OlFpzksCkZHNO0eLjaSSOrMQnpPXg0j6qHIY3y2U= +github.com/gopacket/gopacket v1.4.0/go.mod h1:EpvsxINeehp5qj4YMKMLf2/dekdhKn2IIAO/ZOifS7o= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 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= @@ -139,7 +150,6 @@ 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= @@ -153,7 +163,6 @@ 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= @@ -193,12 +202,10 @@ 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/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= 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= @@ -237,14 +244,12 @@ 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= @@ -254,7 +259,6 @@ 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= @@ -278,8 +282,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -289,9 +293,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= 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= @@ -321,7 +326,6 @@ 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= @@ -343,24 +347,22 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= 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= @@ -368,11 +370,8 @@ 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= @@ -396,5 +395,3 @@ 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= From 4629c8b7d679c50c0fb41af2b23db2bcf1b55f6f Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 17:05:48 +0800 Subject: [PATCH 76/80] =?UTF-8?q?fix:=20kpi=E6=8E=A5=E6=94=B6neinfo?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=B1=80=E9=83=A8=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/oam/service/kpi.go | 37 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/modules/oam/service/kpi.go b/src/modules/oam/service/kpi.go index d5e82ad6..c9f567bb 100644 --- a/src/modules/oam/service/kpi.go +++ b/src/modules/oam/service/kpi.go @@ -32,7 +32,6 @@ type KPI struct { wsService *wsService.WSSend kpiReportService *neDataService.KpiReport kpiCReportService *neDataService.KpiCReport - neInfo neModel.NeInfo } // Resolve 接收处理 @@ -41,8 +40,8 @@ func (s *KPI) Resolve(k oam.KPI) error { return fmt.Errorf("kpi data is nil") } // 是否存在网元 - s.neInfo = s.neInfoService.FindByRmuid(k.NeUid) - if s.neInfo.NeType == "" || s.neInfo.RmUID != k.NeUid { + neInfo := s.neInfoService.FindByRmuid(k.NeUid) + if neInfo.NeType == "" || neInfo.RmUID != k.NeUid { return fmt.Errorf("resolve kpi network element does not exist %s", k.NeUid) } @@ -51,17 +50,17 @@ func (s *KPI) Resolve(k oam.KPI) error { curSeconds := curTime.Hour()*3600 + curTime.Minute()*60 + curTime.Second() index := int64(curSeconds) / k.Granularity - if err := s.saveKPIData(k, index); err != nil { + if err := s.saveKPIData(neInfo, k, index); err != nil { return err } - if err := s.saveKPIDataC(k, index); err != nil { + if err := s.saveKPIDataC(neInfo, k, index); err != nil { return err } return nil } // saveKPIData 存储KPI数据并推送到ws订阅组 -func (s *KPI) saveKPIData(k oam.KPI, index int64) error { +func (s KPI) saveKPIData(neInfo neModel.NeInfo, k oam.KPI, index int64) error { // 时间数据处理 recordTime := time.Now() if k.RecordTime > 1e12 { @@ -75,7 +74,7 @@ func (s *KPI) saveKPIData(k oam.KPI, index int64) error { recordStartTime := date.ParseDateToStr(startTime, "15:04:05") // kpi data数据json - kpiTitles := s.kpiReportService.FindTitle(s.neInfo.NeType) + kpiTitles := s.kpiReportService.FindTitle(neInfo.NeType) KpiValues := make([]map[string]any, 0) for _, kt := range kpiTitles { item := map[string]any{ @@ -99,9 +98,9 @@ func (s *KPI) saveKPIData(k oam.KPI, index int64) error { // KPI 信息 kpiData := neDataModel.KpiReport{ - NeType: s.neInfo.NeType, - NeName: s.neInfo.NeName, - RmUid: s.neInfo.RmUID, + NeType: neInfo.NeType, + NeName: neInfo.NeName, + RmUid: neInfo.RmUID, Date: recordDate, StartTime: recordStartTime, EndTime: recordEndTime, @@ -130,18 +129,18 @@ func (s *KPI) saveKPIData(k oam.KPI, index int64) error { } // 推送到ws订阅组 - s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, s.neInfo.NeType, s.neInfo.NeId), data) + s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, neInfo.NeType, neInfo.NeId), data) // 更新UPF总流量 - if s.neInfo.NeType == "UPF" { + if neInfo.NeType == "UPF" { upValue := parse.Number(data["UPF.03"]) downValue := parse.Number(data["UPF.06"]) - s.kpiReportService.UPFTodayFlowUpdate(s.neInfo.RmUID, upValue, downValue) + s.kpiReportService.UPFTodayFlowUpdate(neInfo.RmUID, upValue, downValue) } return nil } // saveKPIDataC 存储自定义KPI数据并推送到ws订阅组 -func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { +func (s KPI) saveKPIDataC(neInfo neModel.NeInfo, k oam.KPI, index int64) error { // 时间数据处理 recordTime := time.Now() if k.RecordTime > 1e12 { @@ -155,7 +154,7 @@ func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { recordStartTime := date.ParseDateToStr(startTime, "15:04:05") // kpi data数据json - kpiCTitles := s.kpiCReportService.FindTitle(s.neInfo.NeType) + kpiCTitles := s.kpiCReportService.FindTitle(neInfo.NeType) KpiValues := make([]map[string]any, 0) // 自定义指标的表达式环境变量 KpiExprEnv := make(map[string]any, 0) @@ -206,9 +205,9 @@ func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { // KPI 信息 kpiCData := neDataModel.KpiCReport{ - NeType: s.neInfo.NeType, - NeName: s.neInfo.NeName, - RmUid: s.neInfo.RmUID, + NeType: neInfo.NeType, + NeName: neInfo.NeName, + RmUid: neInfo.RmUID, Date: recordDate, StartTime: recordStartTime, EndTime: recordEndTime, @@ -237,6 +236,6 @@ func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error { } // 推送到ws订阅组 - s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, s.neInfo.NeType, s.neInfo.NeId), data) + s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, neInfo.NeType, neInfo.NeId), data) return nil } From a1eefe9660bfa1445f9512b80e7e8ff9df103ad9 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 14 Aug 2025 10:43:30 +0800 Subject: [PATCH 77/80] =?UTF-8?q?feat:=20UE/CDR=E6=9F=A5=E8=AF=A2=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6imsi=E6=94=AF=E6=8C=81=E6=A8=A1=E7=B3=8A=E5=8C=B9?= =?UTF-8?q?=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/repository/alarm.go | 3 ++- src/modules/network_data/repository/cdr_event.go | 14 +++++++------- src/modules/network_data/repository/ue_event.go | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/modules/network_data/repository/alarm.go b/src/modules/network_data/repository/alarm.go index 745662b7..aa21d678 100644 --- a/src/modules/network_data/repository/alarm.go +++ b/src/modules/network_data/repository/alarm.go @@ -1,6 +1,7 @@ package repository import ( + "fmt" "strings" "time" @@ -32,7 +33,7 @@ func (r Alarm) SelectByPage(query model.AlarmQuery) ([]model.Alarm, int64) { tx = tx.Where("pv_flag = ?", query.PvFlag) } if query.AlarmCode != "" { - tx = tx.Where("alarm_code = ?", query.AlarmCode) + tx = tx.Where("alarm_code like ?", fmt.Sprintf("%%%s%%", query.AlarmCode)) } if query.AlarmType != "" { tx = tx.Where("alarm_type in (?)", strings.Split(query.AlarmType, ",")) diff --git a/src/modules/network_data/repository/cdr_event.go b/src/modules/network_data/repository/cdr_event.go index 0123ea0b..d115e3d1 100644 --- a/src/modules/network_data/repository/cdr_event.go +++ b/src/modules/network_data/repository/cdr_event.go @@ -42,10 +42,10 @@ func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model. switch neType { case "SMSC": if v, ok := query["callerParty"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') like ?", fmt.Sprintf("%%%s%%", v)) } if v, ok := query["calledParty"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') like ?", fmt.Sprintf("%%%s%%", v)) } if v, ok := query["recordType"]; ok && v != "" { recordTypes := strings.Split(v, ",") @@ -60,24 +60,24 @@ func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model. tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", v) } if v, ok := query["subscriberID"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') like ?", fmt.Sprintf("%%%s%%", v)) } if v, ok := query["dnn"]; ok && v != "" { tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", v) } case "SGWC": if v, ok := query["imsi"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') like ?", fmt.Sprintf("%%%s%%", v)) } if v, ok := query["msisdn"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') like ?", fmt.Sprintf("%%%s%%", v)) } case "IMS": if v, ok := query["callerParty"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') like ?", fmt.Sprintf("%%%s%%", v)) } if v, ok := query["calledParty"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", v) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') like ?", fmt.Sprintf("%%%s%%", v)) } } diff --git a/src/modules/network_data/repository/ue_event.go b/src/modules/network_data/repository/ue_event.go index e026e7eb..c2eb2579 100644 --- a/src/modules/network_data/repository/ue_event.go +++ b/src/modules/network_data/repository/ue_event.go @@ -42,7 +42,7 @@ func (r UEEvent) SelectByPage(neType string, query map[string]string) ([]model.U tx = tx.Where("event_type in ?", eventTypes) } if v, ok := query["imsi"]; ok && v != "" { - tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') = ?", v) + tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') like ?", fmt.Sprintf("%%%s%%", v)) } // 查询结果 From a9be1dcf6c59508b400b216ef302831f367cf2d8 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 14 Aug 2025 10:45:22 +0800 Subject: [PATCH 78/80] =?UTF-8?q?fix:=20=E5=88=A0=E9=99=A4=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E6=BA=90=E5=B0=86=E5=85=B3=E8=81=94=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=A7=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/system/repository/sys_login_source.go | 14 ++++++++++++++ src/modules/system/service/sys_login_source.go | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/modules/system/repository/sys_login_source.go b/src/modules/system/repository/sys_login_source.go index c9170f8b..3bde7b91 100644 --- a/src/modules/system/repository/sys_login_source.go +++ b/src/modules/system/repository/sys_login_source.go @@ -148,3 +148,17 @@ func (r SysLoginSource) DeleteByIds(ids []int64) int64 { } return tx.RowsAffected } + +// DeleteByUserSource 通过用户源删除用户 返回受影响行数 +func (r SysLoginSource) DeleteByUserSource(uid string) int64 { + if uid == "" || uid == "#" { + return 0 + } + tx := db.DB("").Where("user_source = ?", uid) + // 执行删除 + if err := tx.Delete(&model.SysUser{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} diff --git a/src/modules/system/service/sys_login_source.go b/src/modules/system/service/sys_login_source.go index b6a9b949..61a28a4e 100644 --- a/src/modules/system/service/sys_login_source.go +++ b/src/modules/system/service/sys_login_source.go @@ -54,6 +54,9 @@ func (s SysLoginSource) DeleteByIds(ids []int64) (int64, error) { return 0, fmt.Errorf("no permission to access authentication source data") } if len(arr) == len(ids) { + for _, v := range arr { + s.sysLoginSourceRepository.DeleteByUserSource(v.UID) + } return s.sysLoginSourceRepository.DeleteByIds(ids), nil } // return 0, fmt.Errorf("删除认证源信息失败!") From 06209878a3af75ffdd643f781bc7bf3dc13e2174 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 15 Aug 2025 18:50:11 +0800 Subject: [PATCH 79/80] =?UTF-8?q?style:=20=E7=94=A8=E6=88=B7=E7=B1=BB?= =?UTF-8?q?=E5=9E=8Bsys=E6=9B=B4=E6=96=B0=E4=B8=BASystem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/std/upgrade/upg_sys_user.sql | 2 +- src/modules/network_element/controller/action.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build/database/std/upgrade/upg_sys_user.sql b/build/database/std/upgrade/upg_sys_user.sql index 35e4a953..d8baa5e8 100644 --- a/build/database/std/upgrade/upg_sys_user.sql +++ b/build/database/std/upgrade/upg_sys_user.sql @@ -56,6 +56,6 @@ INSERT IGNORE INTO `sys_user` VALUES (2, 100, 'admin', 'admin', '', '', '0', '', INSERT IGNORE INTO `sys_user` VALUES (3, 100, 'manager', 'manager', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); INSERT IGNORE INTO `sys_user` VALUES (4, 100, 'monitor', 'monitor', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', 'System', '#', '1', '0', 0, 0, '127.0.0.1', 0, 'system', 0, '', 0, ''); UPDATE `sys_user` SET `status_flag` = '1', `user_type` = 'System', `user_source` = '#' WHERE `user_id` in (1,2,3,4); - +UPDATE `sys_user` SET `user_type` = 'System', `user_source` = '#' WHERE `user_type` = 'sys'; -- Dump completed on 2025-02-14 15:26:56 diff --git a/src/modules/network_element/controller/action.go b/src/modules/network_element/controller/action.go index fce0b524..aee4d221 100644 --- a/src/modules/network_element/controller/action.go +++ b/src/modules/network_element/controller/action.go @@ -426,9 +426,10 @@ func (s *NeActionController) Service(c *gin.Context) { neTypeLower := strings.ToLower(neInfo.NeType) cmdStr := fmt.Sprintf("sudo systemctl %s %s", body.Action, neTypeLower) - if neTypeLower == "omc" { + switch neTypeLower { + case "omc": cmdStr = fmt.Sprintf("nohup sh -c \"sudo systemctl stop omc && sleep 5s && sudo systemctl %s omc\" > /dev/null 2>&1 &", body.Action) - } else if neTypeLower == "ims" { + case "ims": if body.Action == "restart" { cmdStr = "ims-stop || true && ims-start" } else { From d0d539e4d07d8a9399c30a55581dc5eea3f4dfb0 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 15 Aug 2025 18:53:42 +0800 Subject: [PATCH 80/80] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2508.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2761ca88..0c1c8114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # 版本发布日志 +## 2.2508.2-20250815 + +- 修复 删除认证源将关联用户信息移除,用户类型sys更新为System +- 优化 UE/CDR查询条件imsi支持模糊匹配 +- 优化 kpi接收neinfo信息局部赋值,ws控制器实例化方式 +- 优化 数据库导入执行异常错误判断忽略 +- 修复 操作日志记录信息json序列化字符串避免结构异常导致无法解析 +- 新增 第三方登录认证和管理 +- 修复 cdr/ue查询时间字段改用记录时间,传入时间解析时区UTC0导致无法正常查询 +- 修复 告警日志查询补充告警状态字段,告警状态字典值修正为枚举字符串 + ## 2.2508.1-20250808 - 修复 MML类型object_type初始值mml更新General,MML日志记录功能接口