merge: 合并OMC分支

This commit is contained in:
TsMask
2024-07-10 14:18:48 +08:00
parent 17c0011c6b
commit 625ed57a50
260 changed files with 9167 additions and 14857 deletions

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"io"
"net/http"
"time"
"nms_cxy/lib/dborm"
"nms_cxy/lib/global"
@@ -14,13 +15,197 @@ import (
)
var (
UriCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrEvent"
UriCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrFile"
UriIMSCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent"
UriIMSCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile"
UriSMFCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/smf/objectType/cdrEvent"
UriSMFCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/smf/objectType/cdrFile"
CustomUriCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrEvent"
CustomUriCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrFile"
CustomUriIMSCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent"
CustomUriIMSCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile"
CustomUriSMFCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent"
CustomUriSMFCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile"
)
// SMF CDR
type CdrSubscriptionID struct {
SubscriptionIDType string `json:"subscriptionIDType"`
SubscriptionIDData string `json:"subscriptionIDData"`
}
type CdrNetWorkFuctionInfomation struct {
NetworkFunctionality string `json:"networkFunctionality"`
NetworkFunctionName string `json:"networkFunctionName,omitempty"`
NetworkFunctionIPv4Address string `json:"networkFunctionIPv4Address,omitempty"`
NetworkFunctionIPv6Address string `json:"networkFunctionIPv6Address,omitempty"`
}
type SMFTrigger string
const (
TimeThresholdReached SMFTrigger = "timeThresholdReached"
VolumeThresholdReached SMFTrigger = "volumeThresholdReached"
UnitThresholdReached SMFTrigger = "unitThresholdReached"
TimeQuotaExhausted SMFTrigger = "timeQuotaExhausted"
VolumeQuotaExhausted SMFTrigger = "volumeQuotaExhausted"
UnitQuotaExhausted SMFTrigger = "unitQuotaExhausted"
ExpiryOfQuotaValidityTime SMFTrigger = "expiryOfQuotaValidityTime"
ExpiryOfQuotaHoldingTime SMFTrigger = "expiryOfQuotaHoldingTime"
EndOfPDUSession SMFTrigger = "endOfPDUSession"
)
type CdrSMFTrigger struct {
SMFTrigger SMFTrigger `json:"sMFTrigger"`
}
type CdrQuotaManagementIndicator string
// List of QuotaManagementIndicator
const (
Cdr_QMI_ONLINE_CHARGING CdrQuotaManagementIndicator = "ONLINE_CHARGING"
Cdr_QMI_OFFLINE_CHARGING CdrQuotaManagementIndicator = "OFFLINE_CHARGING"
Cdr_QMI_QUOTA_MANAGEMENT_SUSPENDED CdrQuotaManagementIndicator = "QUOTA_MANAGEMENT_SUSPENDED"
)
type CdrUsedUnitContainer struct {
ServiceIdentifier *int32 `json:"serviceIdentifier,omitempty"`
QuotaManagementIndicatorExt CdrQuotaManagementIndicator `json:"quotaManagementIndicatorExt,omitempty"`
Triggers []SMFTrigger `json:"triggers,omitempty"`
TriggerTimestamp *time.Time `json:"triggerTimestamp,omitempty"`
Time *uint32 `json:"time,omitempty"`
DataTotalVolume *uint64 `json:"dataTotalVolume,omitempty"`
DataVolumeUplink *uint64 `json:"dataVolumeUplink,omitempty"`
DataVolumeDownlink *uint64 `json:"dataVolumeDownlink,omitempty"`
ServiceSpecificUnits *uint64 `json:"serviceSpecificUnits,omitempty"`
EventTimeStamp *time.Time `json:"eventTimeStamp,omitempty"`
LocalSequenceNumber int32 `json:"localSequenceNumber"`
//PDUContainerInformation *PduContainerInformation `json:"pDUContainerInformation,omitempty"`
//NSPAContainerInformation *NspaContainerInformation `json:"nSPAContainerInformation,omitempty"`
}
type CdrMultipleUnitUsage struct {
RatingGroup uint32 `json:"ratingGroup" yaml:"ratingGroup" bson:"ratingGroup" mapstructure:"RatingGroup"`
UsedUnitContainer []CdrUsedUnitContainer `json:"usedUnitContainer,omitempty" yaml:"usedUnitContainer" bson:"usedUnitContainer" mapstructure:"UsedUnitContainer"`
//UPFID string `json:"uPFID,omitempty" yaml:"uPFID" bson:"uPFID" mapstructure:"UPFID"`
}
type CdrSubscriberEquipmentNumber struct {
SubscriberEquipmentNumberType string `json:"subscriberEquipmentNumberType"`
SubscriberEquipmentNumberData string `json:"subscriberEquipmentNumberData"`
}
type CdrNetworkSliceInstanceID struct {
SST int32 `json:"sST"`
SD string `json:"sD,omitempty"`
}
type CdrPduAddress struct {
PDUIPv4Address string `json:"pDUIPv4Address,omitempty"`
PDUIPv6AddresswithPrefix string `json:"pDUIPv6AddresswithPrefix,omitempty"`
IPV4dynamicAddressFlag bool `json:"iPV4dynamicAddressFlag,omitempty"`
IPV6dynamicPrefixFlag bool `json:"iPv6dynamicPrefixFlag,omitempty"`
}
type CdrArp struct {
PriorityLevel int32 `json:"priorityLevel"`
PreemptionCapability string `json:"preemptionCapability"`
PreemptionVulnerability string `json:"preemptionVulnerability"`
}
type CdrAuthorizedQosInformation struct {
FiveQi int `json:"fiveQi"`
ARP *CdrArp `json:"aRP,omitempty"`
PriorityLevel *int32 `json:"priorityLevel,omitempty"`
AverWindow *int32 `json:"averWindow,omitempty"`
MaxDataBurstVol *int32 `json:"maxDataBurstVol,omitempty"`
}
type CdrSubscribedDefaultQos struct {
FiveQi int32 `json:"fiveQi,omitempty"`
ARP CdrArp `json:"aRP,omitempty"`
PriorityLevel *int32 `json:"priorityLevel,omitempty"`
}
type CdrSessionAmbr struct {
Uplink string `json:"uplink"`
Downlink string `json:"downlink"`
}
type CdrPDUSessionChargingInformation struct {
PDUSessionChargingID int32 `json:"pDUSessionChargingID"`
UserIdentifier string `json:"userIdentifier,omitempty"` // isdn
UserEquipmentInfo *CdrSubscriberEquipmentNumber `json:"userEquipmentInfo,omitempty"` // imei/imeisv
//UserLocationInfomation *UserLocation `json:"userLocationinfo,omitempty"`
UserRoamerInOut string `json:"userRoamerInOut,omitempty"`
PDUSessionId int32 `json:"pDUSessionId"`
NetworkSliceInstanceID *CdrNetworkSliceInstanceID `json:"networkSliceInstanceID,omitempty"`
//PDUType PduSessionType `json:"pDUType,omitempty"`
SSCMode string `json:"sSCMode,omitempty"`
DNNID string `json:"dNNID"`
SUPIPLMNIdentifier string `json:"sUPIPLMNIdentifier,omitempty"`
//ServingNetworkFunctionID *ServingNetworkFunctionId `json:"servingNetworkFunctionID,omitempty"`
//RATType RatType `json:"rATType,omitempty"`
DataNetworkNameIdentifier string `json:"dataNetworkNameIdentifier,omitempty"`
PDUAddress CdrPduAddress `json:"pDUAddress,omitempty"`
AuthorizedQoSInformation *CdrAuthorizedQosInformation `json:"authorizedQoSInformation,omitempty"`
UETimeZone string `json:"uETimeZone,omitempty"`
PDUSessionstartTime *time.Time `json:"pDUSessionstartTime,omitempty"`
PDUSessionstopTime *time.Time `json:"pDUSessionstopTime,omitempty"`
Diagnostics *int `json:"diagnostics,omitempty"`
ChargingCharacteristics string `json:"chargingCharacteristics,omitempty"`
ChChSelectionMode string `json:"chChSelectionMode,omitempty"`
ThreeGPPPSDataOffStatus string `json:"threeGPPPSDataOffStatus,omitempty"`
//RANSecondaryRATUsageReport *RanSecondaryRatUsageReport `json:"rANSecondaryRATUsageReport,omitempty"`
SubscribedQoSInformation *CdrSubscribedDefaultQos `json:"subscribedQoSInformation,omitempty"`
AuthorizedSessionAMBR *CdrSessionAmbr `json:"authorizedSessionAMBR,omitempty"`
SubscribedSessionAMBR *CdrSessionAmbr `json:"subscribedSessionAMBR,omitempty"`
ServingCNPLMNID string `json:"servingCNPLMNID,omitempty"`
DnnSelectionMode string `json:"dnnSelectionMode,omitempty"`
HomeProvidedChargingID int32 `json:"homeProvidedChargingID,omitempty"`
//MAPDUNon3GPPUserLocationInfo *UserLocation `json:"mAPDUNon3GPPUserLocationInfo,omitempty" yaml:"mAPDUNon3GPPUserLocationInfo" bson:"mAPDUNon3GPPUserLocationInfo" mapstructure:"MAPDUNon3GPPUserLocationInfo"`
//PresenceReportingAreaInformation map[string]PresenceInfo `json:"presenceReportingAreaInformation,omitempty" yaml:"presenceReportingAreaInformation" bson:"presenceReportingAreaInformation" mapstructure:"PresenceReportingAreaInformation"`
}
type CauseForRecordClosing string
const (
NormalRelease CauseForRecordClosing = "normalRelease"
PartialRecord CauseForRecordClosing = "partialRecord"
AbnormalRelease CauseForRecordClosing = "abnormalRelease"
CAMELInitCallRelease CauseForRecordClosing = "cAMELInitCallRelease"
VolumeLimit CauseForRecordClosing = "volumeLimit"
TimeLimit CauseForRecordClosing = "timeLimit"
ServingNodeChange CauseForRecordClosing = "servingNodeChange"
MaxChangeCond CauseForRecordClosing = "maxChangeCond"
ManagementIntervention CauseForRecordClosing = "managementIntervention"
IntraSGSNIntersystemChange CauseForRecordClosing = "intraSGSNIntersystemChange"
RATChange CauseForRecordClosing = "rATChange"
MSTimeZoneChange CauseForRecordClosing = "mSTimeZoneChange"
SGSNPLMNIDChange CauseForRecordClosing = "sGSNPLMNIDChange "
SGWChange CauseForRecordClosing = "sGWChange"
APNAMBRChange CauseForRecordClosing = "aPNAMBRChange"
)
type ChargingRecord struct {
RecordType string `json:"recordType"`
ChargingID int `json:"chargingID"`
RecordingNetworkFunctionID string `json:"recordingNetworkFunctionID"` // UUID
SubscriberIdentifier CdrSubscriptionID `json:"subscriberIdentifier,omitempty"`
NFunctionConsumerInformation CdrNetWorkFuctionInfomation `json:"nFunctionConsumerInformation"`
Triggers []CdrSMFTrigger `json:"triggers,omitempty"`
ListOfMultipleUnitUsage []CdrMultipleUnitUsage `json:"listOfMultipleUnitUsage,omitempty"`
RecordOpeningTime string `json:"recordOpeningTime"`
Duration int `json:"duration"`
RecordSequenceNumber int `json:"recordSequenceNumber,omitempty"`
CauseForRecClosing CauseForRecordClosing `json:"causeForRecClosing"`
Diagnostics *int `json:"diagnostics,omitempty"`
LocalRecordSequenceNumber int `json:"localRecordSequenceNumber,omitempty"`
PDUSessionChargingInformation CdrPDUSessionChargingInformation `json:"pDUSessionChargingInformation,omitempty"`
InvocationTimestamp string `json:"invocationTimestamp,omitempty"`
}
type CDREvent struct {
NeType string `json:"neType" xorm:"ne_type"`
NeName string `json:"neName" xorm:"ne_name"`
@@ -29,8 +214,8 @@ type CDREvent struct {
CDR map[string]any `json:"CDR" xorm:"cdr_json"`
}
func PostCDREventFromNF(w http.ResponseWriter, r *http.Request) {
log.Info("PostCDREventFromNF processing... ")
func PostCDREventFromIMS(w http.ResponseWriter, r *http.Request) {
log.Info("PostCDREventFromIMS processing... ")
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
@@ -49,9 +234,9 @@ func PostCDREventFromNF(w http.ResponseWriter, r *http.Request) {
}
log.Trace("cdrEvent:", cdrEvent)
affected, err := dborm.XormInsertTableOne("cdr_event", cdrEvent)
affected, err := dborm.XormInsertTableOne("cdr_event_ims", cdrEvent)
if err != nil && affected <= 0 {
log.Error("Failed to insert cdr_event:", err)
log.Error("Failed to insert cdr_event_ims:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
@@ -65,3 +250,36 @@ func PostCDREventFromNF(w http.ResponseWriter, r *http.Request) {
services.ResponseStatusOK204NoContent(w)
}
func PostCDREventFromSMF(w http.ResponseWriter, r *http.Request) {
log.Info("PostCDREventFromSMF processing... ")
// 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
}
cdrEvent := new(CDREvent)
err = json.Unmarshal(body, &cdrEvent)
if cdrEvent.NeType == "" || err != nil {
log.Error("Failed to Unmarshal cdrEvent:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Trace("cdrEvent:", cdrEvent)
affected, err := dborm.XormInsertTableOne("cdr_event_smf", cdrEvent)
if err != nil && affected <= 0 {
log.Error("Failed to insert cdr_event_smf:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 推送到ws订阅组
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_SMF_CDR, cdrEvent)
services.ResponseStatusOK204NoContent(w)
}

View File

@@ -7,12 +7,14 @@ import (
"os"
"os/exec"
"strings"
"time"
"nms_cxy/lib/core/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/log"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
neModel "nms_cxy/src/modules/network_element/model"
neService "nms_cxy/src/modules/network_element/service"
"github.com/gorilla/mux"
)
@@ -154,21 +156,21 @@ func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) {
services.ResponseStatusOK204NoContent(w)
}
type MMLRequest struct {
MML []string `json:"mml"`
}
// type MMLRequest struct {
// MML []string `json:"mml"`
// }
var TIME_DELAY_AFTER_WRITE time.Duration = 200
var TIME_DEAD_LINE time.Duration = 10
// var TIME_DELAY_AFTER_WRITE time.Duration = 200
// var TIME_DEAD_LINE time.Duration = 10
func init() {
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)
}
}
// func init() {
// 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)
// }
// }
func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) {
log.Info("UploadLicenseFileData processing... ")
@@ -274,12 +276,13 @@ func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) {
}
// backup system.ini to system.ini.bak
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
cpCmd := fmt.Sprintf("sudo cp -f %s/system.ini %s/system.ini.bak", neLicensePath, neLicensePath)
cpCmd := fmt.Sprintf("sudo test -f %s/system.ini && cp -f %s/system.ini %s/system.ini.bak||echo 0",
neLicensePath, neLicensePath, neLicensePath)
cmd = exec.Command("ssh", sshHost, cpCmd)
out, err = cmd.CombinedOutput()
log.Debugf("Exec output: %v", string(out))
if err != nil {
log.Error("Faile to execute cp command:", err)
log.Errorf("Faile to execute cp command:%v, cmd:%s", err, cpCmd)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
@@ -503,22 +506,54 @@ func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) {
}
}
*/
neLicense := dborm.NeLicense{
NeType: neTypeUpper,
NeID: neId,
Status: "ACTIVE",
Path: licensePath,
FileName: licenseFileName,
Comment: comment,
// neLicense := dborm.NeLicense{
// NeType: neTypeUpper,
// NeID: neId,
// Status: "ACTIVE",
// Path: licensePath,
// FileName: licenseFileName,
// Comment: comment,
// }
// log.Debug("neLicense:", neLicense)
// _, err = dborm.XormInsertTableOne("ne_license", neLicense)
// if err != nil {
// log.Error("Faile to XormInsertTableOne:", err)
// services.ResponseInternalServerError500ProcessError(w, err)
// }
neLicense := neModel.NeLicense{
NeType: neTypeUpper,
NeId: neId,
Status: "0",
LicensePath: neFilePath,
Remark: comment,
}
log.Debug("neLicense:", neLicense)
_, err = dborm.XormInsertTableOne("ne_license", neLicense)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
// 检查是否存在授权记录
neLicense2 := neService.NewNeLicenseImpl.SelectByNeTypeAndNeID(neTypeUpper, neId)
if neLicense2.NeId != neId {
// 读取授权码
code, _ := neService.NewNeLicenseImpl.ReadLicenseInfo(neLicense)
neLicense.ActivationRequestCode = code
neLicense.CreateBy = ctx.LoginUserToUserName(r)
insertId := neService.NewNeLicenseImpl.Insert(neLicense)
if insertId != "" {
services.ResponseStatusOK204NoContent(w)
return
}
} else {
neLicense2.UpdateBy = ctx.LoginUserToUserName(r)
upRows := neService.NewNeLicenseImpl.Update(neLicense2)
if upRows > 0 {
services.ResponseStatusOK204NoContent(w)
return
}
}
services.ResponseStatusOK204NoContent(w)
services.ResponseInternalServerError500ProcessError(w, err)
}

View File

@@ -142,7 +142,8 @@ func PostNeInfo(w http.ResponseWriter, r *http.Request) {
services.ResponseInternalServerError500ProcessError(w, err)
return
}
neInfo.UpdateTime = time.Now().Format(time.DateTime)
//neInfo.UpdateTime = time.Now().Format(time.DateTime)
neInfo.UpdateTime = time.Now()
log.Debug("NE info:", neInfo)
//if !config.GetYamlConfig().OMC.Chk2Ne {
@@ -166,7 +167,7 @@ func PostNeInfo(w http.ResponseWriter, r *http.Request) {
} 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", config.DefaultUriPrefix, strings.ToLower(neInfo.NeType))
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)
@@ -252,7 +253,7 @@ func PutNeInfo(w http.ResponseWriter, r *http.Request) {
neInfo := new(dborm.NeInfo)
_ = json.Unmarshal(body, neInfo)
neInfo.NeType = strings.ToUpper(neType)
neInfo.UpdateTime = time.Now().Format(time.DateTime)
neInfo.UpdateTime = time.Now()
log.Debug("NE info:", neInfo)
//if !config.GetYamlConfig().OMC.Chk2Ne {
@@ -276,7 +277,7 @@ func PutNeInfo(w http.ResponseWriter, r *http.Request) {
} 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", config.DefaultUriPrefix, neTypeLower)
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)
@@ -858,15 +859,20 @@ func PostNeServiceAction(w http.ResponseWriter, r *http.Request) {
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
switch neTypeLower {
case "omc":
actionCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh %s", config.GetYamlConfig().NE.OmcDir, 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 ssh %s omc:%v", action, err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 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 restagent", 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":

View File

@@ -3,7 +3,7 @@ package cm
import (
"strings"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/ctx"
"nms_cxy/lib/global"
"nms_cxy/lib/log"
"nms_cxy/lib/services"
@@ -13,6 +13,7 @@ import (
"fmt"
"io"
"net/http"
neService "nms_cxy/src/modules/network_element/service"
"github.com/go-resty/resty/v2"
@@ -41,7 +42,7 @@ func GetParamConfigFromNF(w http.ResponseWriter, r *http.Request) {
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId)
var response services.DataResponse
if neInfo.NeId == neId {
if neInfo.NeId == neId && neInfo.NeId != "" {
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF:", requestURI2NF)
@@ -77,7 +78,7 @@ func PostParamConfigToNF(w http.ResponseWriter, r *http.Request) {
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
if neInfo.NeId != neId || neInfo.NeId == "" {
log.Error("neId is empty")
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
@@ -129,7 +130,7 @@ func PutParamConfigToNF(w http.ResponseWriter, r *http.Request) {
neId := ctx.GetQuery(r, "ne_id")
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
if neInfo.NeId != neId || neInfo.NeId == "" {
log.Error("neId is empty")
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
@@ -182,7 +183,7 @@ func DeleteParamConfigToNF(w http.ResponseWriter, r *http.Request) {
neId := ctx.GetQuery(r, "ne_id")
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
if neInfo.NeId != neId || neInfo.NeId == "" {
log.Error("neId is empty")
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return

View File

@@ -20,9 +20,9 @@ import (
)
const (
SoftwareStatusUploaded = "Uploaded"
SoftwareStatusInactive = "Inactive"
SoftwareStatusActive = "Active"
SoftwareStatusUploaded = "3"
SoftwareStatusInactive = "3"
SoftwareStatusActive = "1"
DigestsSignOkString = "digests signatures OK"
SoftwareVerifiedOk = "Verified OK"
)
@@ -213,6 +213,17 @@ func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) {
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)
@@ -314,7 +325,7 @@ func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) {
result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath)
log.Debug("result:", result.String())
if !strings.Contains(result.String(), SoftwareVerifiedOk) {
err := global.ErrCMNotMatchSignFile
err = global.ErrCMNotMatchSignFile
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
@@ -408,7 +419,7 @@ func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) {
return
}
fileName := (*neSoftware)[0]["file_name"]
fileName := (*neSoftware)[0]["name"]
path := (*neSoftware)[0]["path"]
md5Sum := (*neSoftware)[0]["md5_sum"]
@@ -462,7 +473,7 @@ func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) {
return
}
fileName := (*neSoftware)[0]["file_name"]
fileName := (*neSoftware)[0]["name"]
path := (*neSoftware)[0]["path"]
filePath := fmt.Sprintf("%s/%s", path, fileName)
err = os.Remove(filePath)
@@ -549,7 +560,7 @@ func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) {
return
}
fileName := (*neSoftware)[0]["file_name"]
fileName := (*neSoftware)[0]["name"]
path := (*neSoftware)[0]["path"]
srcFile := fmt.Sprintf("%s/%s", path, fileName)
@@ -600,7 +611,7 @@ func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) {
Version: (*neSoftware)[0]["version"],
FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
PreVersion: (*neVersion)[0]["version"],
PreFile: (*neVersion)[0]["file_path"],
PreFile: (*neVersion)[0]["path"],
Status: SoftwareStatusInactive,
}
@@ -684,21 +695,29 @@ func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) {
log.Trace("neVersion:", neVersion)
if !config.GetYamlConfig().OMC.TestMode {
filePath := (*neVersion)[0]["file_path"]
filePath := (*neVersion)[0]["path"]
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
srcFile := fmt.Sprintf("%s/actpkg.sh", config.GetYamlConfig().OMC.BinDir)
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("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
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",
runCmd = fmt.Sprintf("sudo %s/actpkg.sh '%s' %s",
config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper)
if neTypeLower == "omc" {
idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
@@ -886,6 +905,14 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
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,
@@ -898,7 +925,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
return
}
runCmd := fmt.Sprintf("sudo %s/rbkpkg.sh '%s' %s",
runCmd = fmt.Sprintf("sudo %s/rbkpkg.sh '%s' %s",
config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper)
if neTypeLower == "omc" {
idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
@@ -908,7 +935,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
PreVersion: "-",
PreFile: "-",
NewVersion: (*neVersion)[0]["version"],
NewFile: (*neVersion)[0]["file_path"],
NewFile: (*neVersion)[0]["path"],
Status: SoftwareStatusActive,
}
@@ -919,7 +946,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
return
}
services.ResponseStatusOK204NoContent(w)
RunSSHCmd(sshHost, runCmd)
go RunSSHCmd(sshHost, runCmd)
return
}
err = RunSSHCmd(sshHost, runCmd)
@@ -1010,7 +1037,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
PreVersion: "-",
PreFile: "-",
NewVersion: (*neVersion)[0]["version"],
NewFile: (*neVersion)[0]["file_path"],
NewFile: (*neVersion)[0]["path"],
Status: SoftwareStatusActive,
}

View File

@@ -9,7 +9,7 @@ import (
"strings"
"time"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/global"
"nms_cxy/lib/log"
@@ -77,18 +77,20 @@ type DatabaseClient struct {
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error {
// DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
// dbUser, dbPassword, dbHost, dbPort, dbName)
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:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
@@ -99,6 +101,8 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) 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.SetLogger(&log.Elogger)
DbClient.XEngine.ShowSQL(true)
@@ -188,13 +192,13 @@ func ExtDatabaseExecSQL(w http.ResponseWriter, r *http.Request) {
log.Debug("ExtDatabaseExecSQL processing... ")
var sql []string
var err error
// var err error
_, err = services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
// _, err = services.CheckExtValidRequest(w, r)
// if err != nil {
// log.Error("Request error:", err)
// return
// }
//vars := mux.Vars(r)
//tblName := vars["objectTypeValue"]
@@ -249,11 +253,11 @@ 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
}
// token, err := services.CheckExtValidRequest(w, r)
// if err != nil {
// log.Error("Request error:", err)
// return
// }
pack := "dbrest"
vars := mux.Vars(r)
@@ -261,7 +265,7 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
dbname := vars["elementTypeValue"]
tbname := vars["objectTypeValue"]
log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)
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 {
@@ -295,12 +299,11 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
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 {
if !IsQuerySQL(s) {
services.ResponseNotAcceptable406QuerySQLError(w)
return
}
@@ -310,7 +313,7 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
querySQL = querySQL + " " + ls
}
log.Debug("querySQL:", querySQL)
rows, err = DbClient.XEngine.QueryInterface(querySQL)
rows, err := DbClient.XEngine.QueryInterface(querySQL)
if err != nil {
log.Error("SQL failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
@@ -332,11 +335,11 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
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
}
// 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 {
@@ -351,7 +354,7 @@ func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) {
tbname := vars["objectTypeValue"]
pack := "dbrest"
log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)
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 {
@@ -396,11 +399,11 @@ func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) {
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
}
// token, err := services.CheckExtValidRequest(w, r)
// if err != nil {
// log.Error("Request error:", err)
// return
// }
vars := mux.Vars(r)
module := ""
@@ -408,7 +411,7 @@ func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
tbname := vars["objectTypeValue"]
pack := "dbrest"
log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)
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 {
@@ -460,11 +463,11 @@ func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
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
}
// token, err := services.CheckExtValidRequest(w, r)
// if err != nil {
// log.Error("Request error:", err)
// return
// }
vars := mux.Vars(r)
module := ""
@@ -472,7 +475,7 @@ func ExtDatabaseDeleteData(w http.ResponseWriter, r *http.Request) {
tbname := vars["objectTypeValue"]
pack := "dbreset"
log.Debugf("token:%s, method:%s, module:%, dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack)
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 {
@@ -548,7 +551,7 @@ func DatabaseGetData(w http.ResponseWriter, r *http.Request) {
if s != "" {
// err = XEngine.SQL(s).Find(&rows)
if IsQuerySQL(s) == false {
if !IsQuerySQL(s) {
services.ResponseNotAcceptable406QuerySQLError(w)
return
}
@@ -560,8 +563,8 @@ func DatabaseGetData(w http.ResponseWriter, r *http.Request) {
log.Debug("querySQL:", querySQL)
rows, err = DbClient.XEngine.QueryInterface(querySQL)
if err != nil {
log.Error("SQL failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
log.Error("QueryInterface failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
tableName := GetTableName(s)

View File

@@ -2,27 +2,36 @@ package event
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
"nms_cxy/lib/core/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/global"
"nms_cxy/lib/log"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
wsService "nms_cxy/src/modules/ws/service"
"github.com/gin-gonic/gin"
)
var (
UriUEEvent = "/upload-ue/v1/:eventType"
// 走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"
)
type UEEvent struct {
NeType string `json:"neType" xorm:"ne_type"`
NeName string `json:"neName" xorm:"ne_name"`
RmUID string `json:"rmUID" xorm:"rm_uid"`
Timestamp int `json:"timestamp" xorm:"timestamp"`
Timestamp int64 `json:"timestamp" xorm:"timestamp"`
EventType string `json:"eventType" xorm:"event_type"`
EventJson map[string]any `json:"eventJSON" xorm:"event_json"`
}
@@ -52,13 +61,13 @@ func PostUEEventFromAMF(c *gin.Context) {
return
}
ueEvent.NeType = "AMF"
ueEvent.Timestamp = int(time.Now().Unix())
ueEvent.Timestamp = time.Now().Unix()
ueEvent.EventType = eventType
log.Trace("ueEvent:", ueEvent)
log.Trace("ueEvent AMF:", ueEvent)
affected, err := dborm.XormInsertTableOne("ue_event", ueEvent)
affected, err := dborm.XormInsertTableOne("ue_event_amf", ueEvent)
if err != nil && affected <= 0 {
log.Error("Failed to insert ue_event:", err)
log.Error("Failed to insert ue_event_amf:", err)
services.ResponseInternalServerError500ProcessError(c.Writer, err)
return
}
@@ -68,3 +77,30 @@ func PostUEEventFromAMF(c *gin.Context) {
services.ResponseStatusOK204NoContent(c.Writer)
}
func PostUEEvent(w http.ResponseWriter, r *http.Request) {
log.Info("PostUEEvent processing... ")
neType := ctx.GetParam(r, "elementTypeValue")
var ueEvent UEEvent
if err := ctx.ShouldBindJSON(r, &ueEvent); err != nil {
services.ResponseInternalServerError500ProcessError(w, err)
return
}
ueEvent.NeType = strings.ToUpper(neType)
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
affected, err := dborm.XormInsertTableOne(tableName, ueEvent)
if err != nil && affected <= 0 {
log.Error("Failed to insert "+tableName, err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 推送到ws订阅组
if ueEvent.NeType == "MME" {
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_MME_UE, ueEvent)
}
services.ResponseStatusOK204NoContent(w)
}

View File

@@ -5,7 +5,7 @@ import (
"net/http"
"path/filepath"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/file"
"nms_cxy/lib/log"

View File

@@ -15,9 +15,6 @@ import (
"nms_cxy/lib/log"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
"nms_cxy/src/framework/utils/date"
neDataModel "nms_cxy/src/modules/network_data/model"
nmsCXYService "nms_cxy/src/modules/nms_cxy/service"
"xorm.io/xorm"
@@ -155,9 +152,9 @@ type DatabaseClient struct {
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
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
@@ -165,8 +162,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
@@ -177,6 +173,8 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) 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)
}
@@ -287,9 +285,6 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
//
pushKafka(alarmData)
} else {
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time").
@@ -299,9 +294,6 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
//
pushKafka(alarmData)
}
log.Trace("alarmData:", alarmData)
var currentSeq string
@@ -444,11 +436,20 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
SetAlarmAckInfo(valueJson, &alarmData)
}
log.Debug("alarmData:", alarmData)
affected, err := session.Insert(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
if alarmData.OrigSeverity == "Event" && config.GetYamlConfig().Alarm.SplitEventAlarm {
affected, err := xEngine.Table("alarm_event").InsertOne(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_event:", err)
services.ResponseInternalServerError500ProcessError(w, err)
continue
}
} else {
affected, err := session.Insert(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
}
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
@@ -460,21 +461,18 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
alarmLog.EventTime = eventTime
log.Trace("alarmLog:", alarmLog)
affected, err = session.Insert(alarmLog)
affected, err := session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
session.Commit()
//
pushKafka(alarmData)
}
if config.GetYamlConfig().Alarm.ForwardAlarm {
if err = AlarmEmailForward(&alarmData); err != nil {
log.Error("Failed to AlarmEmailForward:", err)
}
if err = AlarmForwardBySMSC(&alarmData); err != nil {
log.Error("Failed to AlarmForwardBySMSC:", err)
if err = AlarmSMSForward(&alarmData); err != nil {
log.Error("Failed to AlarmSMSForward:", err)
}
}
}
@@ -482,25 +480,26 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
services.ResponseStatusOK200Null(w)
}
// pushKafka 告警推送kafka
func pushKafka(alarmData Alarm) {
neAlarm := neDataModel.Alarm{
AlarmSeq: fmt.Sprint(alarmData.AlarmSeq),
AlarmTitle: alarmData.AlarmTitle,
AlarmStatus: fmt.Sprint(alarmData.AlarmStatus),
AlarmType: alarmData.AlarmType,
OrigSeverity: alarmData.OrigSeverity,
EventTime: date.ParseStrToDate(alarmData.EventTime, date.YYYY_MM_DD_HH_MM_SS),
ID: alarmData.AlarmId,
AlarmCode: fmt.Sprint(alarmData.AlarmCode),
SpecificProblem: alarmData.SpecificProblem,
ObjectUid: alarmData.ObjectUid,
NeName: alarmData.NeName,
AlarmId: alarmData.ObjectUid,
ObjectName: alarmData.ObjectName,
AddInfo: alarmData.AddInfo,
}
nmsCXYService.NewAlarmImpl.KafkaPush(neAlarm)
type AlarmEvent 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"`
SpecificProblem string `json:"specificProblem"`
SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"`
AddInfo string `json:"addInfo"`
}
// process alarm get from NFs
@@ -768,8 +767,8 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) {
if err = AlarmEmailForward(&alarmData); err != nil {
log.Error("Failed to AlarmEmailForward:", err)
}
if err = AlarmForwardBySMSC(&alarmData); err != nil {
log.Error("Failed to AlarmForwardBySMSC:", err)
if err = AlarmSMSForward(&alarmData); err != nil {
log.Error("Failed to AlarmSMSForward:", err)
}
}
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"net/url"
"strings"
"time"
"nms_cxy/lib/dborm"
@@ -16,7 +17,24 @@ import (
"github.com/linxGnu/gosmpp/pdu"
)
func AlarmForwardBySMS(alarmData *Alarm) error {
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
@@ -30,91 +48,74 @@ func AlarmForwardBySMS(alarmData *Alarm) error {
toUsers, err := dborm.XormGetAlarmForward("SMS")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
return "", err
} else if toUsers == nil {
err := errors.New("not found forward phone number")
log.Error(err)
return err
return "", err
}
userList := strings.Join(*toUsers, ",")
// 短信相关参数
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
}
for _, toUser := range *toUsers {
// 短信相关参数
params := url.Values{}
params.Set("PhoneNumbers", toUser)
params.Set("SignName", SMSFforwardconfig.SignName)
params.Set("TemplateCode", SMSFforwardconfig.TemplateCode)
params.Set("TemplateParam", `{"message":"alarm"}`)
// 添加请求头部
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "APPCODE "+accessKeySecret)
// 构建请求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 err
}
// 添加请求头部
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "APPCODE "+accessKeySecret)
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: toUser,
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
operResult := fmt.Sprintf("Failed to send request:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
}
continue
}
defer resp.Body.Close()
// 解析响应
if resp.StatusCode == http.StatusOK {
operResult := "SMS sent successfully!"
log.Info(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
} else {
operResult := fmt.Sprintf("Failed to send SMS, StatusCode=%d", resp.StatusCode)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
}
// 发送请求
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:
err := fmt.Errorf("Failed to send SMS: %s(Code=%d)", resp.Status, resp.StatusCode)
log.Error(err)
return userList, err
}
return nil
}
func AlarmForwardBySMPP(alarmData *Alarm) error {
func AlarmForwardBySMPP(alarmData *Alarm) (string, error) {
log.Info("AlarmForwardBySMPP processing... ")
toUsers, err := dborm.XormGetAlarmForward("SMS")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return "", err
} else if toUsers == nil {
err := errors.New("not found forward phone number")
log.Error(err)
return "", err
}
userList := strings.Join(*toUsers, ",")
auth := gosmpp.Auth{
SMSC: config.GetYamlConfig().Alarm.SMSC.Addr,
SystemID: config.GetYamlConfig().Alarm.SMSC.UserName,
SystemID: config.GetYamlConfig().Alarm.SMSC.SystemID,
Password: config.GetYamlConfig().Alarm.SMSC.Password,
SystemType: "",
SystemType: config.GetYamlConfig().Alarm.SMSC.SystemType,
}
// conn, err := gosmpp.NonTLSDialer(auth.SMSC)
@@ -142,49 +143,50 @@ func AlarmForwardBySMPP(alarmData *Alarm) error {
},
}, -1)
if err != nil {
log.Error(err)
return err
log.Error("Failed to create SMPP new session:", err)
return userList, err
}
defer func() {
_ = trans.Close()
}()
toUsers, err := dborm.XormGetAlarmForward("SMS")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
} else if toUsers == nil {
err := errors.New("not found forward phone number")
log.Error(err)
return err
}
// sending SMS(s)
for _, toUser := range *toUsers {
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: toUser,
}
message := alarmData.AlarmTitle + "from" + alarmData.NeType + alarmData.NeId + "at" + alarmData.EventTime
if err = trans.Transceiver().Submit(newSubmitSM(toUser, message)); err != nil {
operResult := fmt.Sprintf("Failed to submit short message:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
} else {
operResult := "SMS sent successfully!"
log.Trace(operResult)
forwardLog.OperResult = operResult
}
// var results []string
// for _, toUser := range *toUsers {
message := "Alarm Notification: " + alarmData.AlarmTitle + " from " + alarmData.NeType + " " + alarmData.NeId + " at " + alarmData.EventTime
if err = trans.Transceiver().Submit(newSubmitSM(userList, message)); err != nil {
// result := fmt.Sprintf("Failed to submit %s hort message:%s", toUser, err.Error())
// results = append(results, result)
log.Error("Failed to submit hort message:", err)
return userList, err
}
// }
return userList, nil
}
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
func writeLog(alarmData *Alarm, toUser, forwardBy string, err error) error {
var result string
if err == nil {
result = "SMS sent successfully"
} else {
result = err.Error()
}
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
Interface: forwardBy,
ToUser: toUser,
OperResult: result,
}
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
return err
}
return nil
}

View File

@@ -1,61 +0,0 @@
package fm
import (
"fmt"
"strings"
"nms_cxy/lib/log"
"nms_cxy/omc/config"
"github.com/chzyer/readline"
"github.com/go-gsm/ucp"
)
func AlarmForwardBySMSC(alarmData *Alarm) error {
opt := &ucp.Options{
Addr: config.GetYamlConfig().Alarm.SMSC.Addr,
User: config.GetYamlConfig().Alarm.SMSC.UserName,
Password: config.GetYamlConfig().Alarm.SMSC.Password,
AccessCode: "",
}
client := ucp.New(opt)
if err := client.Connect(); err != nil {
log.Error("Failed to connect:", err)
return err
}
defer client.Close()
reader, _ := readline.New(">>> ")
defer reader.Close()
for {
fmt.Print(">>> ")
lines, _ := reader.Readline()
fields := strings.Fields(lines)
if len(fields) == 1 {
// exit CLI
if fields[0] == "exit" {
return nil
}
// display help message
if fields[0] == "help" {
log.Trace("\n\tSend a 'message' to 'receiver' with a 'sender' mask\n\t>>> sender receiver message\n\n\tExit the cli\n\t>>> exit\n")
}
}
// sender receiver message...
if len(fields) >= 3 {
sender := fields[0]
receiver := fields[1]
message := strings.Join(fields[2:], " ")
ids, err := client.Send(sender, receiver, message)
if err != nil {
log.Error(err)
} else {
log.Debug("%v", ids)
}
}
}
}

View File

@@ -45,7 +45,7 @@ type ApiResponse struct {
ResultMessage interface{}
}
var globalSession = session.NewSessManager("omc")
var globalSession = session.NewSessManager("restagent")
func init() {
conf := config.GetYamlConfig()

View File

@@ -50,9 +50,9 @@ var DbClient DatabaseClient
// conf.Database.Host, conf.Database.Port, conf.Database.Name)
// }
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
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
@@ -60,8 +60,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
@@ -72,6 +71,8 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) 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)
}
@@ -83,18 +84,18 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err
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
}
// 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("token:%s, method:%s, module:%s dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack)
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)

View File

@@ -1,314 +0,0 @@
package maintenance
import (
"encoding/json"
"fmt"
"net/http"
"os"
"os/exec"
"path"
"runtime"
"time"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/log"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
)
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理
// 对于虚拟化部署OMC系统能够对虚机内存、虚机CPU、虚拟存储空间、文件系统资源、数据库空间等指标进行监控提供界面截图
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图
// (3) OMC能够方便的查询数据库连接情况并可手工干预数据库的连接能方便的终结非法的数据库连接
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据要求OMC能够保存至少3个月提供界面截图
// (7) 用户可以按照需求自定义报表模板并生成OMC系统维护数据报表提供界面截图
// (8) OMC具备自身告警管理功能对于传统OMC系统服务器单电源告警存储硬盘告警、OMC系统软件故障等
// 对于虚拟化OMC系统如虚机告警、虚拟硬盘告警等提供界面截图 。
var (
// parameter config management
Uri = config.UriPrefix + "/maintenance/{apiVersion}/zz"
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理
UriPref = config.UriPrefix + "/maintenance/{apiVersion}/pref"
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据要求OMC能够保存至少3个月提供界面截图
UriPrefLog = config.UriPrefix + "/maintenance/{apiVersion}/prefLog"
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图
UriConfig = config.UriPrefix + "/maintenance/{apiVersion}/config"
// (3) OMC能够方便的查询数据库连接情况并可手工干预数据库的连接能方便的终结非法的数据库连接
UriSqlClient = config.UriPrefix + "/maintenance/{apiVersion}/sqlClient"
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
UriTop = config.UriPrefix + "/maintenance/{apiVersion}/top"
)
func init() {
// 定時收集 TODO
prefLogSave("")
}
func List(w http.ResponseWriter, r *http.Request) {
fmt.Println("zz List")
services.ResponseStatusOK200Null(w)
}
// 性能指標
func prefInfo(dirName string) map[string]any {
data := make(map[string]any)
// 显示文件資源目录
dirPath := "D://"
if runtime.GOOS == "linux" {
dirPath = "/home"
}
// 訪問下級
if dirName != "" {
dirPath = path.Join(dirPath, dirName)
}
dir_list, e := os.ReadDir(dirPath)
if e != nil {
log.Error(e)
}
list := make([]map[string]any, 0)
for _, v := range dir_list {
o, err := v.Info()
if err != nil {
continue
}
list = append(list, map[string]any{
"name": o.Name(),
"size": o.Size(),
"mode": o.Mode().String(),
"modTime": o.ModTime().Format("2006-01-02 15:04:05"),
"isDir": o.IsDir(),
})
}
data["dirList"] = list
// 文件資源使用率
u, _ := disk.Usage(dirPath)
usedGB := int(u.Used) / (1024 * 1024 * 1024 * 1)
data["dirUse"] = fmt.Sprintf("%d", usedGB)
// CPU使用率
percent, err := cpu.Percent(time.Second, false)
if err != nil {
log.Error(err)
}
data["cpuUse"] = fmt.Sprintf("%.2f", percent[0])
// 内存使用率
memInfo, err := mem.VirtualMemory()
if err != nil {
log.Error(err)
}
data["memUse"] = memInfo.UsedPercent
// 獲取數據庫占用空間
if dborm.DbClient.XEngine != nil {
conf := config.GetYamlConfig()
result, err := dborm.DbClient.XEngine.QueryString(`SELECT
CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size,
CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size,
CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free,
CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size
FROM information_schema.tables WHERE TABLE_SCHEMA = ?;
`, conf.Database.Name)
if err == nil {
data["dbInfo"] = result[0]
} else {
data["dbInfo"] = map[string]string{}
}
}
return data
}
// 性能指標存入數據庫
func prefLogSave(dirName string) {
if dborm.DbClient.XEngine != nil {
data := prefInfo(dirName)
dirListByte, err := json.Marshal(data["dirList"])
if err != nil {
log.Error(err)
}
dbInfoByte, err := json.Marshal(data["dbInfo"])
if err != nil {
log.Error(err)
}
rse, err := dborm.DbClient.XEngine.Exec(`INSERT INTO sys_perf_data
(id, create_time, dir_used, dir_list, db_info, mem_used, cpu_used)
VALUES(NULL, NOW(), ?, ?, ?, ?, ?);
`, data["dirUse"], string(dirListByte), string(dbInfoByte), data["memUse"], data["cpuUse"])
if err != nil {
log.Error(err)
}
fmt.Println(rse.LastInsertId())
}
}
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/pref?dir=true
func Pref(w http.ResponseWriter, r *http.Request) {
// 知道下級文件資源目录
dirName := r.URL.Query().Get("dirName")
data := prefInfo(dirName)
services.ResponseWithJson(w, http.StatusOK, data)
}
// POST http://192.168.21.183:3040/api/rest/maintenance/v1/config
func Config(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs struct {
Key string `json:"key"`
Value string `json:"value"`
}
err := ctx.ShouldBindJSON(r, &bodyArgs)
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// 進行值更新
if dborm.DbClient.XEngine != nil {
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
rse, err := dborm.DbClient.XEngine.Exec("UPDATE sys_config SET value = ? where id = ?", "true", 100)
if err != nil {
fmt.Println(err)
}
fmt.Println(rse)
}
services.ResponseStatusOK200Null(w)
}
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=close
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=connet
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=user
func SqlClient(w http.ResponseWriter, r *http.Request) {
// 关闭
isClose := r.URL.Query().Get("type")
if isClose == "close" && dborm.DbClient.XEngine != nil {
dborm.DbClient.XEngine.Close()
}
// 重连
isConnet := r.URL.Query().Get("type")
if isConnet == "connet" && dborm.DbClient.XEngine == nil {
conf := config.GetYamlConfig()
err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
conf.Database.Host, conf.Database.Port, conf.Database.Name)
if err != nil {
fmt.Println("dborm.initDbClient err:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
}
// 查询实例
isUser := r.URL.Query().Get("type")
if isUser == "user" && dborm.DbClient.XEngine != nil {
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
rse, err := dborm.DbClient.XEngine.Exec("KILL CONNECTION CONNECTION_ID()")
if err != nil {
fmt.Println(err)
}
fmt.Println(rse)
}
// 进行连接测试
err := dborm.DbClient.XEngine.Ping()
if err != nil {
fmt.Println(err)
}
services.ResponseStatusOK200Null(w)
}
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/top?grep=
func Top(w http.ResponseWriter, r *http.Request) {
// 過濾命令
grep := r.URL.Query().Get("grep")
// 命令拼接
var cmd *exec.Cmd
switch runtime.GOOS {
case "linux":
command := "ps -ef "
if grep != "" {
command += grep
}
cmd = exec.Command(command)
case "windows":
command := "wmic process list brief "
if grep != "" {
command += grep
}
cmd = exec.Command("cmd", "/C", command)
}
out, err := cmd.CombinedOutput()
fmt.Println(string(out))
if err != nil {
fmt.Println(err)
}
services.ResponseWithJson(w, http.StatusOK, string(out))
}
// PATCH http://192.168.21.183:3040/api/rest/maintenance/v1/top?ops=&name=
func TopOps(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs struct {
Ops string `json:"ops"`
Pid string `json:"pid"`
}
err := ctx.ShouldBindJSON(r, &bodyArgs)
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// 命令拼接
var cmd *exec.Cmd
switch runtime.GOOS {
case "linux":
switch bodyArgs.Ops {
case "kill":
cmd = exec.Command("kill", "-9", bodyArgs.Pid)
}
case "windows":
switch bodyArgs.Ops {
case "kill":
cmd = exec.Command("cmd", "/C", "taskkill", "-PID", bodyArgs.Pid, "-F")
}
}
out, err := cmd.CombinedOutput()
fmt.Println(string(out))
if err != nil {
fmt.Println(err)
}
services.ResponseWithJson(w, http.StatusOK, string(out))
}

View File

@@ -52,16 +52,24 @@ var (
CustomUriOmMmlInt = config.UriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}"
)
var TIME_DELAY_AFTER_WRITE time.Duration = 200
var TIME_DEAD_LINE time.Duration = 10
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 init() {
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) {
@@ -79,8 +87,7 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) {
return
}
var buf [20 * 1024]byte
//buf := make([]byte, 0)
buf := make([]byte, BUFFER_SIZE)
var n int
var mmlResult []string
port2 := 5002
@@ -91,6 +98,7 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) {
if neInfo != nil {
hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, port2)
conn, err := net.Dial("tcp", hostMML)
//conn, err := net.Dial("tcp", hostMML)
if err != nil {
errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err)
log.Error(errMsg)
@@ -112,6 +120,15 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) {
// 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", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password)
_, err = conn.Write([]byte(loginStr))
@@ -173,7 +190,7 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) {
//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 := re1.ReplaceAllString(string(buf[0:n]), "")
result = re2.ReplaceAllString(result, "")
mmlResult = append(mmlResult, result)
}
@@ -187,11 +204,11 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) {
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
}
// 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
@@ -215,8 +232,7 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) {
}
log.Debug("neType:", neType, "neId", neId)
log.Debugf("token:%s, method:%s, managementType:%s dbname:%s, tbname:%s pack:%s",
token, r.Method, module, neType, neId[0], pack)
log.Debugf("method:%s, managementType:%s dbname:%s, tbname:%s pack:%s", r.Method, module, neType, neId[0], pack)
var buf [20 * 1024]byte
//buf := make([]byte, 0)
@@ -251,7 +267,7 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) {
}
neInfo := new(dborm.NeInfo)
neInfo, err = dborm.XormGetNeInfo(neType, neId[0])
neInfo, err := dborm.XormGetNeInfo(neType, neId[0])
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
@@ -632,11 +648,11 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) {
func PostMMLToOMC(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMMLToOMC processing... ")
token, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Failed to CheckMmlValidRequest:", err)
return
}
// token, err := services.CheckExtValidRequest(w, r)
// if err != nil {
// log.Error("Failed to CheckMmlValidRequest:", err)
// return
// }
params := r.URL.Query()
neId := params["ne_id"]
@@ -647,7 +663,7 @@ func PostMMLToOMC(w http.ResponseWriter, r *http.Request) {
}
neInfo := new(dborm.NeInfo)
neInfo, err = dborm.XormGetNeInfo("OMC", neId[0])
neInfo, err := dborm.XormGetNeInfo("OMC", neId[0])
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
@@ -671,7 +687,7 @@ func PostMMLToOMC(w http.ResponseWriter, r *http.Request) {
MmlHome: config.GetYamlConfig().MML.MmlHome,
Limit: 50,
User: "",
SessionToken: token, // 旧token
SessionToken: "", // 旧token
Authorization: r.Header.Get(tokenConst.HEADER_KEY), // 请求Token
HttpUri: hostUri,
UserAgent: config.GetDefaultUserAgent(),

View File

@@ -1,55 +0,0 @@
package monitor
import "time"
type MonitorBase struct {
ID uint `xorm:"id" json:"id"`
CreatedAt time.Time `xorm:"created_at" json:"createdAt"`
UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"`
Cpu float64 `xorm:"cpu" json:"cpu"`
LoadUsage float64 `xorm:"load_usage" json:"loadUsage"`
CpuLoad1 float64 `xorm:"cpu_load1" json:"cpuLoad1"`
CpuLoad5 float64 `xorm:"cpu_load5" json:"cpuLoad5"`
CpuLoad15 float64 `xorm:"cpu_load15" json:"cpuLoad15"`
Memory float64 `xorm:"memory" json:"memory"`
DbSize uint `xorm:"db_size" json:"dbSize"`
}
type MonitorIO struct {
ID uint `xorm:"id" json:"id"`
CreatedAt time.Time `xorm:"created_at" json:"createdAt"`
UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"`
Name string `xorm:"name" json:"name"`
Read uint64 `xorm:"read" json:"read"`
Write uint64 `xorm:"write" json:"write"`
Count uint64 `xorm:"count" json:"count"`
Time uint64 `xorm:"time" json:"time"`
}
type MonitorNetwork struct {
ID uint `xorm:"id" json:"id"`
CreatedAt time.Time `xorm:"created_at" json:"createdAt"`
UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"`
Name string `xorm:"name" json:"name"`
Up float64 `xorm:"up" json:"up"`
Down float64 `xorm:"down" json:"down"`
}
type MonitorSearch struct {
Param string `json:"param" validate:"required,oneof=all cpu memory load io network"`
Info string `json:"info"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
}
type MonitorData struct {
Param string `json:"param" validate:"required,oneof=cpu memory load io network"`
Date []time.Time `json:"date"`
Value []interface{} `json:"value"`
}

View File

@@ -1,163 +0,0 @@
package monitor
import (
"net/http"
"sort"
"strings"
"time"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/net"
)
// 点击【主机 - 监控】菜单进入监控报表直观的了解服务器的运行状态包含【平均负载】、【CPU性能监控】、【内存使用监控】、【磁盘IO监控】、【网络IO监控】
// 可以查看昨天今天最近7天最近30天自定义时间的监控指标情况。
// 默认监控是开启的,可以在【面板设置 - 监控】页面中根据需求对监控进行开启和关闭。
// 监控数据默认保存30天可以自行修改也可手动清理该日志。
var (
// IP地址
UriIPAddr = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/ipaddr"
// 可选网络
UriNetOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/netoptions"
// 可选磁盘
UriIoOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/iooptions"
// 加载
UriLoad = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/load"
// IP地址
UriIPAddrOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/ipaddr"
// 可选网络
UriNetOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/netoptions"
// 可选磁盘
UriIoOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/iooptions"
// 加载
UriLoadOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/load"
)
// IPAddr IP地址
func IPAddr(w http.ResponseWriter, r *http.Request) {
ipAddrs := []map[string]string{}
interfaces, err := net.Interfaces()
if err == nil {
for _, iface := range interfaces {
addrs := map[string]string{}
for _, v := range iface.Addrs {
prefix := strings.Split(v.Addr, "/")[0]
if strings.Contains(prefix, "::") {
addrs["IPv6"] = prefix
}
if strings.Contains(prefix, ".") {
addrs["IPv4"] = prefix
}
}
ipAddrs = append(ipAddrs, addrs)
}
}
services.ResponseWithJson(w, 200, ipAddrs)
}
// Netoptions 可选网络
func Netoptions(w http.ResponseWriter, r *http.Request) {
netStat, _ := net.IOCounters(true)
var options []string
options = append(options, "all")
for _, net := range netStat {
options = append(options, net.Name)
}
sort.Strings(options)
services.ResponseWithJson(w, 200, options)
}
// Iooptions 可选磁盘
func Iooptions(w http.ResponseWriter, r *http.Request) {
diskStat, _ := disk.IOCounters()
var options []string
options = append(options, "all")
for _, net := range diskStat {
options = append(options, net.Name)
}
sort.Strings(options)
services.ResponseWithJson(w, 200, options)
}
// LoadMonitor 载入监控
func LoadMonitor(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs MonitorSearch
err := ctx.ShouldBindJSON(r, &bodyArgs)
if err != nil || dborm.DbClient.XEngine == nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
loc := time.Now().Location()
bodyArgs.StartTime = bodyArgs.StartTime.In(loc)
bodyArgs.EndTime = bodyArgs.EndTime.In(loc)
var backdatas []MonitorData
if bodyArgs.Param == "all" || bodyArgs.Param == "cpu" || bodyArgs.Param == "memory" || bodyArgs.Param == "load" {
var bases []MonitorBase
err := dborm.DbClient.XEngine.Table("monitor_base").
Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime).
Desc("created_at").
Find(&bases)
if err != nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
var itemData MonitorData
itemData.Param = "base"
for _, base := range bases {
itemData.Date = append(itemData.Date, base.CreatedAt)
itemData.Value = append(itemData.Value, base)
}
backdatas = append(backdatas, itemData)
}
if bodyArgs.Param == "all" || bodyArgs.Param == "io" {
var bases []MonitorIO
err := dborm.DbClient.XEngine.Table("monitor_io").
Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime).
Desc("created_at").
Find(&bases)
if err != nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
var itemData MonitorData
itemData.Param = "io"
for _, base := range bases {
itemData.Date = append(itemData.Date, base.CreatedAt)
itemData.Value = append(itemData.Value, base)
}
backdatas = append(backdatas, itemData)
}
if bodyArgs.Param == "all" || bodyArgs.Param == "network" {
var bases []MonitorNetwork
err := dborm.DbClient.XEngine.Table("monitor_network").
Where("name = ? AND created_at > ? AND created_at < ?", bodyArgs.Info, bodyArgs.StartTime, bodyArgs.EndTime).
Desc("created_at").
Find(&bases)
if err != nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
var itemData MonitorData
itemData.Param = "network"
for _, base := range bases {
itemData.Date = append(itemData.Date, base.CreatedAt)
itemData.Value = append(itemData.Value, base)
}
backdatas = append(backdatas, itemData)
}
services.ResponseWithJson(w, 200, backdatas)
}

View File

@@ -1,234 +0,0 @@
package monitor
import (
"encoding/json"
"fmt"
"strconv"
"time"
"nms_cxy/lib/dborm"
"nms_cxy/lib/log"
"nms_cxy/omc/config"
"github.com/robfig/cron/v3"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
)
type MonitorService struct{}
type IMonitorService interface {
Run()
}
func NewIMonitorService() IMonitorService {
return &MonitorService{}
}
func (m *MonitorService) Run() {
// monitorStatus, _ := dborm.XormGetConfig("SystemMonitor", "MonitorStatus")
// if monitorStatus["value"] == "disable" {
// return
// }
var itemModel MonitorBase
itemModel.CreatedAt = time.Now()
itemModel.UpdatedAt = time.Now()
totalPercent, _ := cpu.Percent(3*time.Second, false)
if len(totalPercent) == 1 {
itemModel.Cpu = totalPercent[0]
}
cpuCount, _ := cpu.Counts(false)
loadInfo, _ := load.Avg()
itemModel.CpuLoad1 = loadInfo.Load1
itemModel.CpuLoad5 = loadInfo.Load5
itemModel.CpuLoad15 = loadInfo.Load15
itemModel.LoadUsage = loadInfo.Load1 / (float64(cpuCount*2) * 0.75) * 100
memoryInfo, _ := mem.VirtualMemory()
itemModel.Memory = memoryInfo.UsedPercent
var dataSize int
conf := config.GetYamlConfig()
result, err := dborm.DbClient.XEngine.QueryString("SELECT SUM(data_length) AS data_size FROM information_schema.tables WHERE TABLE_SCHEMA = ?;", conf.Database.Name)
if err != nil {
dataSize = 0
} else {
v, _ := strconv.Atoi(result[0]["data_size"])
dataSize = v
}
itemModel.DbSize = uint(dataSize)
_, errx := dborm.DbClient.XEngine.Table("monitor_base").Insert(itemModel)
if errx != nil {
log.Errorf("Insert basic monitoring data failed, err: %v", err)
}
go loadDiskIO()
go loadNetIO()
// 删除保留的记录
// monitorStoreDays, _ := dborm.XormGetConfig("SystemMonitor", "MonitorStoreDays")
// if monitorStoreDays["value"] != "" {
// return
// }
// storeDays, err := strconv.Atoi(MonitorStoreDays.Value)
// if err != nil {
// timeForDelete := time.Now().AddDate(0, 0, -storeDays)
// DelMonitorBase(timeForDelete)
// DelMonitorIO(timeForDelete)
// DelMonitorNet(timeForDelete)
// }
}
func loadDiskIO() {
ioStat, _ := disk.IOCounters()
time.Sleep(60 * time.Second)
ioStat2, _ := disk.IOCounters()
var ioList []MonitorIO
for _, io2 := range ioStat2 {
for _, io1 := range ioStat {
if io2.Name == io1.Name {
var itemIO MonitorIO
itemIO.CreatedAt = time.Now()
itemIO.UpdatedAt = time.Now()
itemIO.Name = io1.Name
if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes {
itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / 60)
}
if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes {
itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / 60)
}
if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount {
itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / 60)
}
writeCount := uint64(0)
if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount {
writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / 60)
}
if writeCount > itemIO.Count {
itemIO.Count = writeCount
}
if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime {
itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / 60)
}
writeTime := uint64(0)
if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime {
writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / 60)
}
if writeTime > itemIO.Time {
itemIO.Time = writeTime
}
ioList = append(ioList, itemIO)
break
}
}
}
_, err := dborm.DbClient.XEngine.Table("monitor_io").Insert(ioList)
if err != nil {
log.Errorf("Insert io monitoring data failed, err: %v", err)
}
}
func loadNetIO() {
netStat, _ := net.IOCounters(true)
netStatAll, _ := net.IOCounters(false)
time.Sleep(60 * time.Second)
netStat2, _ := net.IOCounters(true)
var netList []MonitorNetwork
for _, net2 := range netStat2 {
for _, net1 := range netStat {
if net2.Name == net1.Name {
var itemNet MonitorNetwork
itemNet.CreatedAt = time.Now()
itemNet.UpdatedAt = time.Now()
itemNet.Name = net1.Name
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60
}
netList = append(netList, itemNet)
break
}
}
}
netStatAll2, _ := net.IOCounters(false)
for _, net2 := range netStatAll2 {
for _, net1 := range netStatAll {
if net2.Name == net1.Name {
var itemNet MonitorNetwork
itemNet.Name = net1.Name
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60
}
netList = append(netList, itemNet)
break
}
}
}
_, err := dborm.DbClient.XEngine.Table("monitor_network").Insert(netList)
if err != nil {
log.Errorf("Insert network monitoring data failed, err: %v", err)
}
}
var c *cron.Cron
var monitorCronID int
func init() {
c = cron.New()
c.Start()
monitorCronID = 0
}
// StartMonitor 开始监控任务 removeBefore删除上次任务间隔interval分钟
func StartMonitor(removeBefore bool, interval string) error {
if removeBefore {
c.Remove(cron.EntryID(monitorCronID))
}
// 读取配置
if interval == "" {
v, err := dborm.XormGetConfig("SystemMonitor", "sampleTime")
if err != nil {
return err
}
data := make(map[string]any)
err = json.Unmarshal([]byte(v["value_json"].(string)), &data)
if err != nil {
log.Error("json StartMonitor:%s", err.Error())
return err
}
interval = data["sampleTime"].(string)
}
imservice := NewIMonitorService()
monitorID, err := c.AddJob(fmt.Sprintf("@every %sm", interval), imservice)
if err != nil {
return err
}
imservice.Run()
monitorCronID = int(monitorID)
return nil
}

View File

@@ -1,94 +0,0 @@
package psnet
import (
"fmt"
"net"
"net/http"
"time"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/log"
"nms_cxy/lib/services"
"nms_cxy/lib/wsinfo"
"nms_cxy/omc/config"
"github.com/gorilla/websocket"
"github.com/shirou/gopsutil/process"
)
var (
// websockte通信
UriWs = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/ws"
// 停止进程
UriStop = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/stop"
// 检查ip端口请求
UriPing = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/ping"
)
// 进程管理
var wsUpgrade = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// ProcessWs
func ProcessWs(w http.ResponseWriter, r *http.Request) {
ws, err := wsUpgrade.Upgrade(w, r, nil)
if err != nil {
return
}
wsClient := wsinfo.NewWsClient("processClient", ws)
go wsClient.Read()
go wsClient.Write()
}
// 停止进程 {"PID":30040}
func StopProcess(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs struct {
PID int32 `json:"PID" validate:"required"`
}
err := ctx.ShouldBindJSON(r, &bodyArgs)
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
proc, err := process.NewProcess(bodyArgs.PID)
if err != nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
if err := proc.Kill(); err != nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
services.ResponseStatusOK200Null(w)
}
// 检查ip端口请求
func Ping(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs struct {
Host string `json:"host" validate:"required"`
Port string `json:"port" validate:"required"`
}
err := ctx.ShouldBindJSON(r, &bodyArgs)
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", bodyArgs.Host, bodyArgs.Port), 3*time.Second)
if err != nil {
services.ResponseErrorWithJson(w, 400, err.Error())
return
}
defer conn.Close()
services.ResponseStatusOK200Null(w)
}

View File

@@ -36,7 +36,7 @@ type ApiResponse struct {
ResultMessage interface{}
}
var globalSession = session.NewSessManager("omc")
var globalSession = session.NewSessManager("restagent")
var (
MAX_RMUID_NUM int

View File

@@ -8,6 +8,7 @@ import (
"math"
"net/http"
"strconv"
"strings"
"time"
"nms_cxy/lib/dborm"
@@ -65,6 +66,26 @@ type GoldKpi struct {
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 int8 `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}"
@@ -98,9 +119,9 @@ type DatabaseClient struct {
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
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
@@ -108,8 +129,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
@@ -120,11 +140,28 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) 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
// exist, err := xEngine.IsTableExist("kpi_report")
// if err != nil {
// log.Error("Failed to IsTableExist:", err)
// return err
// }
// if exist {
// // 复制表结构到新表
// sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` AS SELECT * FROM kpi_report WHERE 1=0", "kpi_report_amf")
// _, err := xEngine.Exec(sql)
// if err != nil {
// log.Error("Failed to Exec:", err)
// return err
// }
// }
return nil
}
@@ -155,7 +192,7 @@ func GetDateTimeFromTimeString(fmtString string, timeString string) string {
return t.Format(global.DateTime)
}
// process alarm post message from NFs
// process KPI report post message from NFs
func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostKPIReportFromNF processing... ")
@@ -167,6 +204,91 @@ func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) {
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 int8 = 60
if seconds != 0 && seconds <= math.MaxInt8 && seconds >= math.MinInt8 {
granularity = int8(seconds)
}
// 黄金指标事件对象
kpiEvent := map[string]any{
// kip_id ...
"neType": kpiReport.Task.NE.NeType,
"neName": kpiReport.Task.NE.NEName,
"startIndex": kpiIndex,
"timeGroup": startTime,
}
// 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()
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)
}
// insert kpi_report table, no session
tableName := "kpi_report_" + strings.ToLower(kpiReport.Task.NE.NeType)
affected, err := xEngine.Table(tableName).Insert(kpiData)
if err != nil && affected <= 0 {
log.Errorf("Failed to insert %s:%v", tableName, err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 推送到ws订阅组
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI, kpiEvent)
if kpiReport.Task.NE.NeType == "UPF" {
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI_UPF, kpiEvent)
}
services.ResponseStatusOK204NoContent(w)
}
// post kpi report from NEs, insert insto gold_kpi table, discard...
func PostGoldKPIFromNF(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 {
@@ -205,12 +327,32 @@ func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) {
"startIndex": goldKpi.Index,
"timeGroup": goldKpi.StartTime,
}
// insert into new kpi_report_xxx table
kpiData := new(KpiData)
kpiData.Date = goldKpi.Date
kpiData.Index = goldKpi.Index
//st, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.StartTime, time.Local)
//et, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.EndTime, time.Local)
kpiData.StartTime = goldKpi.StartTime
kpiData.EndTime = goldKpi.EndTime
kpiData.Granularity = goldKpi.Granularity
kpiData.NEName = goldKpi.NEName
kpiData.NEType = goldKpi.NEType
kpiData.RmUid = goldKpi.RmUid
kpiVal := new(KPIVal)
kpiData.CreatedAt = time.Now().UnixMilli()
for _, k := range kpiReport.Task.NE.KPIs {
kpiEvent[k.KPIID] = k.Value // kip_id
goldKpi.KpiId = k.KPIID
goldKpi.Value = k.Value
goldKpi.Error = k.Err
log.Trace("goldKpi:", goldKpi)
kpiVal.KPIID = k.KPIID
kpiVal.Value = int64(k.Value)
kpiVal.Err = k.Err
kpiData.KPIValues = append(kpiData.KPIValues, *kpiVal)
//log.Trace("goldKpi:", goldKpi)
// 启动事务
err := session.Begin()
@@ -244,13 +386,22 @@ func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) {
}
}
// insert kpi_report table, no session
tableName := "kpi_report_" + strings.ToLower(kpiReport.Task.NE.NeType)
affected, err := xEngine.Table(tableName).Insert(kpiData)
if err != nil && affected <= 0 {
log.Errorf("Failed to insert %s:%v", tableName, err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 推送到ws订阅组
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI, kpiEvent)
if goldKpi.NEType == "UPF" {
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI_UPF, kpiEvent)
}
services.ResponseStatusOK200Null(w)
services.ResponseStatusOK204NoContent(w)
}
type MeasureTask struct {
@@ -903,9 +1054,9 @@ func PostMeasurementFromNF(w http.ResponseWriter, r *http.Request) {
layout := time.RFC3339
measurement.Date = GetDateFromTimeString(layout, measurement.StartTime)
measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime)
affected, err := session.Table("northbound_pm").Insert(measurement)
affected, err := session.Table("nbi_pm").Insert(measurement)
if err != nil && affected <= 0 {
log.Error("Failed to insert northbound_pm:", err)
log.Error("Failed to insert nbi_pm:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
@@ -986,9 +1137,9 @@ func GetMeasurementFromNF(w http.ResponseWriter, r *http.Request) {
layout := time.RFC3339
measurement.Date = GetDateFromTimeString(layout, measurement.StartTime)
measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime)
affected, err := session.Table("northbound_pm").Insert(measurement)
affected, err := session.Table("nbi_pm").Insert(measurement)
if err != nil && affected <= 0 {
log.Error("Failed to insert northbound_pm:", err)
log.Error("Failed to insert nbi_pm:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}

View File

@@ -2,56 +2,24 @@ package security
import (
"encoding/json"
"fmt"
"image/color"
"io"
"net/http"
"strconv"
"strings"
"time"
"nms_cxy/features/security/service"
sysConfigService "nms_cxy/features/sys_config/service"
"nms_cxy/lib/core/account"
"nms_cxy/lib/core/cache"
"nms_cxy/lib/core/constants/cachekey"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/dborm"
"nms_cxy/lib/global"
"nms_cxy/lib/log"
"nms_cxy/lib/oauth"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
srcConfig "nms_cxy/src/framework/config"
"nms_cxy/src/framework/i18n"
"nms_cxy/src/framework/redis"
"github.com/mojocn/base64Captcha"
)
var (
UriOauthToken2 = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token2"
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"
// 系统登录
UriLogin = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/login"
CustomUriLogin = config.UriPrefix + "/securityManagement/{apiVersion}/login"
// 获取验证码
UriCaptchaImage = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/captchaImage"
CustomUriCaptchaImage = config.UriPrefix + "/securityManagement/{apiVersion}/captchaImage"
// 登录用户信息
UriUserInfo = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
CustomUriUserInfo = config.UriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
// 登录用户路由信息
UriRouters = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getRouters"
CustomUriRouters = config.UriPrefix + "/securityManagement/{apiVersion}/getRouters"
)
func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
@@ -136,14 +104,8 @@ func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
}
if user != nil {
// 缓存用户信息
account.CacheLoginUser(user)
redis.SetByExpire("", "session_token", token, time.Second*1800)
// 角色权限集合,管理员拥有所有权限
userId := fmt.Sprint(user.Id)
isAdmin := srcConfig.IsAdmin(userId)
roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin)
services.ResponseStatusOK200LoginWhitRP(w, token, user, roles, perms)
empty := []string{}
services.ResponseStatusOK200LoginWhitRP(w, token, user, empty, empty)
return
}
services.ResponseBadRequest400IncorrectLogin(w)
@@ -225,212 +187,3 @@ func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
}
services.ResponseStatusOK200Null(w)
}
// 系统登录
//
// POST /login
func LoginOMC(w http.ResponseWriter, r *http.Request) {
log.Info("LoginOMC processing... ")
var body struct {
Username string `json:"username" binding:"required"` // Username 用户名
Password string `json:"password" binding:"required"` // Password 用户密码
Code string `json:"code"` // Code 验证码
UUID string `json:"uuid"` // UUID 验证码唯一标识
}
err := ctx.ShouldBindJSON(r, &body)
if err != nil {
log.Error("Invalid Json Format")
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// response 400-5
if body.Username == "" || body.Password == "" {
log.Error("Wrong parameter value")
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 校验验证码
// 从数据库配置获取验证码开关 true开启false关闭
captchaEnabledStr := sysConfigService.NewServiceSysConfig.SelectConfigValueByKey("sys.account.captchaEnabled")
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
if err != nil {
captchaEnabled = false
}
if captchaEnabled {
if body.Code == "" || body.UUID == "" {
log.Error("Authentication failed, mismatch captcha")
ctx.JSON(w, 400, result.CodeMsg(400, "Verification code information error"))
return
}
verifyKey := cachekey.CAPTCHA_CODE_KEY + body.UUID
captcha, ok := cache.GetLocalTTL(verifyKey)
if captcha == nil || !ok {
log.Error("Authentication failed, captcha emtry")
ctx.JSON(w, 400, result.CodeMsg(400, "The verification code has expired"))
return
}
cache.DeleteLocalTTL(verifyKey)
if captcha.(string) != body.Code {
log.Error("Authentication failed, not match captcha")
ctx.JSON(w, 400, result.CodeMsg(400, "Verification code error"))
return
}
}
validUser, user, err := dborm.XormCheckLoginUser(body.Username, body.Password, config.GetYamlConfig().Auth.Crypt)
if !validUser || err != nil {
// response 400-4
log.Error("Authentication failed, mismatch user or password")
ctx.JSON(w, 400, result.CodeMsg(400, err.Error()))
return
}
token := oauth.GenRandToken("omc") // Generate new token to session ID
sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
affected, err := dborm.XormInsertSession(body.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
}
if user != nil {
// 缓存用户信息
account.CacheLoginUser(user)
redis.SetByExpire("", "session_token", token, time.Second*1800)
ctx.JSON(w, 200, result.OkData(map[string]any{
"accessToken": token,
}))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 获取验证码
//
// GET /captchaImage
func CaptchaImage(w http.ResponseWriter, r *http.Request) {
configService := sysConfigService.NewServiceSysConfig
// 从数据库配置获取验证码开关 true开启false关闭
captchaEnabledStr := configService.SelectConfigValueByKey("sys.account.captchaEnabled")
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
if err != nil {
captchaEnabled = false
}
if !captchaEnabled {
ctx.JSON(w, 200, result.Ok(map[string]any{
"captchaEnabled": captchaEnabled,
}))
return
}
// 生成唯一标识
verifyKey := ""
data := map[string]any{
"captchaEnabled": captchaEnabled,
"uuid": "",
"img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
}
// char 字符验证
driverCaptcha := &base64Captcha.DriverString{
//Height png height in pixel.
Height: 40,
// Width Captcha png width in pixel.
Width: 120,
//NoiseCount text noise count.
NoiseCount: 4,
//Length random string length.
Length: 4,
//Source is a unicode which is the rand string from.
Source: "023456789abcdefghjkmnprstuvwxyz",
//ShowLineOptions := OptionShowHollowLine | OptionShowSlimeLine | OptionShowSineLine .
ShowLineOptions: base64Captcha.OptionShowHollowLine,
//BgColor captcha image background color (optional)
BgColor: &color.RGBA{
R: 250,
G: 250,
B: 250,
A: 255, // 不透明
},
}
// 验证码生成
id, question, answer := driverCaptcha.GenerateIdQuestionAnswer()
// 验证码表达式解析输出
item, err := driverCaptcha.DrawCaptcha(question)
if err != nil {
log.Infof("Generate Id Question Answer %s : %v", question, err)
} else {
data["uuid"] = id
data["img"] = item.EncodeB64string()
verifyKey = cachekey.CAPTCHA_CODE_KEY + id
cache.SetLocalTTL(verifyKey, answer, 120*time.Second)
}
// 本地开发下返回验证码结果,方便接口调试
// text, ok := cache.GetLocalTTL(verifyKey)
// if ok {
// data["text"] = text.(string)
// }
ctx.JSON(w, 200, result.Ok(data))
}
// 登录用户信息
func UserInfo(w http.ResponseWriter, r *http.Request) {
loginUser, err := ctx.LoginUser(r)
if err != nil {
ctx.JSON(w, 200, result.OkData(err.Error()))
}
// 角色权限集合,管理员拥有所有权限
userId := fmt.Sprint(loginUser.UserID)
isAdmin := srcConfig.IsAdmin(userId)
roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin)
ctx.JSON(w, 200, result.OkData(map[string]any{
"user": loginUser.User,
"roles": roles,
"permissions": perms,
}))
}
// 登录用户路由信息
func Routers(w http.ResponseWriter, r *http.Request) {
userID := ctx.LoginUserToUserID(r)
// 前端路由,管理员拥有所有
isAdmin := srcConfig.IsAdmin(userID)
buildMenus := service.NewServiceAccount.RouteMenus(userID, isAdmin)
ctx.JSON(w, 200, result.OkData(buildMenus))
}
// 鉴权登录接口
var UriOauthToken = "/api/rest/securityManagement/{apiVersion}/oauth/token"
// 鉴权登录接口
func OauthToken(w http.ResponseWriter, r *http.Request) {
language := ctx.AcceptLanguage(r)
var querys struct {
Group string `form:"group" binding:"required"`
Type string `form:"type" binding:"omitempty,oneof=node edge combo"`
}
if err := ctx.ShouldBindQuery(r, &querys); err != nil {
ctx.JSON(w, 400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
apiVersion := ctx.Param(r, "apiVersion")
if apiVersion == "v1" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
}

View File

@@ -1,56 +0,0 @@
package service
import (
menuService "nms_cxy/features/sys_menu/service"
roleService "nms_cxy/features/sys_role/service"
userService "nms_cxy/features/sys_user/service"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/vo"
)
// 实例化服务层 ServiceAccount 结构体
var NewServiceAccount = &ServiceAccount{
sysUserService: userService.NewServiceSysUser,
sysRoleService: roleService.NewServiceSysRole,
sysMenuService: menuService.NewServiceSysMenu,
}
// 账号身份操作服务 服务层处理
type ServiceAccount struct {
// 用户信息服务
sysUserService *userService.ServiceSysUser
// 角色服务
sysRoleService *roleService.ServiceSysRole
// 菜单服务
sysMenuService *menuService.ServiceSysMenu
}
// RoleAndMenuPerms 角色和菜单数据权限
func (s *ServiceAccount) RoleAndMenuPerms(userId string, isAdmin bool) ([]string, []string) {
if isAdmin {
return []string{"admin"}, []string{"*:*:*"}
} else {
// 角色key
roleGroup := []string{}
roles := s.sysRoleService.SelectRoleListByUserId(userId)
for _, role := range roles {
roleGroup = append(roleGroup, role.RoleKey)
}
// 菜单权限key
perms := s.sysMenuService.SelectMenuPermsByUserId(userId)
return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms)
}
}
// RouteMenus 前端路由所需要的菜单
func (s *ServiceAccount) RouteMenus(userId string, isAdmin bool) []vo.Router {
var buildMenus []vo.Router
if isAdmin {
menus := s.sysMenuService.SelectMenuTreeByUserId("*")
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
} else {
menus := s.sysMenuService.SelectMenuTreeByUserId(userId)
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
}
return buildMenus
}

View File

@@ -510,7 +510,7 @@ func GetOneSysinfoFromNF(w http.ResponseWriter, r *http.Request) {
if systemState.OsInfo != "" {
osInfo = systemState.OsInfo
}
dbInfo := "adb v1.0.1"
dbInfo := "kvdb v1.0.1"
if systemState.OsInfo != "" {
dbInfo = systemState.DbInfo
}
@@ -656,7 +656,7 @@ func GetAllSysinfoFromNF(w http.ResponseWriter, r *http.Request) {
if systemState.OsInfo != "" {
osInfo = systemState.OsInfo
}
dbInfo := "adb v1.0.1"
dbInfo := "kvdb v1.0.1"
if systemState.OsInfo != "" {
dbInfo = systemState.DbInfo
}
@@ -857,7 +857,8 @@ func GetStateFromNFOld(w http.ResponseWriter, r *http.Request) {
case "all":
// query all NFs
// create rest client
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
restHostPort := config.GetOMCHostUrl()
getNeInfoPattern := fmt.Sprintf(config.DefaultUriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info",
config.GetYamlConfig().Database.Name)
getNeInfoURI := restHostPort + getNeInfoPattern + "?WHERE=status+in+('0','3')"
@@ -878,7 +879,7 @@ func GetStateFromNFOld(w http.ResponseWriter, r *http.Request) {
neList, _ = dborm.XormParseResult(resp.Body())
default:
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
restHostPort := config.GetOMCHostUrl()
getNeInfoPattern := fmt.Sprintf(config.DefaultUriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info",
config.GetYamlConfig().Database.Name)
getNeInfoURI := restHostPort + getNeInfoPattern

View File

@@ -1,230 +0,0 @@
package sysconfig
import (
"fmt"
"net/http"
"strings"
"nms_cxy/features/sys_config/model"
"nms_cxy/features/sys_config/service"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/midware"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
)
// 参数配置信息接口添加到路由
func Routers() []services.RouterItem {
// 实例化控制层 SysConfigApi 结构体
var apis = &SysConfigApi{
sysConfigService: service.NewServiceSysConfig,
}
rs := [...]services.RouterItem{
{
Method: "GET",
Pattern: "/configs",
Handler: apis.List,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/config/{configId}",
Handler: apis.Info,
Middleware: midware.Authorize(nil),
},
{
Method: "POST",
Pattern: "/config",
Handler: apis.Add,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/config",
Handler: apis.Edit,
Middleware: midware.Authorize(nil),
},
{
Method: "DELETE",
Pattern: "/config/{configIds}",
Handler: apis.Remove,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/config/refreshCache",
Handler: apis.RefreshCache,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/config/configKey/{configKey}",
Handler: apis.ConfigKey,
Middleware: midware.Authorize(nil),
},
// 添加更多的 Router 对象...
}
// 生成两组前缀路由
rsPrefix := []services.RouterItem{}
for _, v := range rs {
path := "/configManage/{apiVersion}" + v.Pattern
// 固定前缀
v.Pattern = config.DefaultUriPrefix + path
rsPrefix = append(rsPrefix, v)
// 可配置
v.Pattern = config.UriPrefix + path
rsPrefix = append(rsPrefix, v)
}
return rsPrefix
}
// 参数配置信息
//
// PATH /configManage
type SysConfigApi struct {
// 参数配置服务
sysConfigService *service.ServiceSysConfig
}
// 参数配置列表
//
// GET /list
func (s *SysConfigApi) List(w http.ResponseWriter, r *http.Request) {
querys := ctx.QueryMap(r)
data := s.sysConfigService.SelectConfigPage(querys)
ctx.JSON(w, 200, result.Ok(data))
}
// 参数配置信息
//
// GET /:configId
func (s *SysConfigApi) Info(w http.ResponseWriter, r *http.Request) {
configId := ctx.Param(r, "configId")
if configId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
data := s.sysConfigService.SelectConfigById(configId)
if data.ConfigID == configId {
ctx.JSON(w, 200, result.OkData(data))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 参数配置新增
//
// POST /
func (s *SysConfigApi) Add(w http.ResponseWriter, r *http.Request) {
var body model.SysConfig
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.ConfigID != "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查属性值唯一
uniqueConfigKey := s.sysConfigService.CheckUniqueConfigKey(body.ConfigKey, "")
if !uniqueConfigKey {
msg := fmt.Sprintf("[%s] Parameter key name already exists", body.ConfigKey)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.CreateBy = ctx.LoginUserToUserName(r)
insertId := s.sysConfigService.InsertConfig(body)
if insertId != "" {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 参数配置修改
//
// PUT /
func (s *SysConfigApi) Edit(w http.ResponseWriter, r *http.Request) {
var body model.SysConfig
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.ConfigID == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查属性值唯一
uniqueConfigKey := s.sysConfigService.CheckUniqueConfigKey(body.ConfigKey, body.ConfigID)
if !uniqueConfigKey {
msg := fmt.Sprintf("[%s] Parameter key name already exists", body.ConfigKey)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查是否存在
config := s.sysConfigService.SelectConfigById(body.ConfigID)
if config.ConfigID != body.ConfigID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access parameter configuration data!"))
return
}
body.UpdateBy = ctx.LoginUserToUserName(r)
rows := s.sysConfigService.UpdateConfig(body)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 参数配置删除
//
// DELETE /:configIds
func (s *SysConfigApi) Remove(w http.ResponseWriter, r *http.Request) {
configIds := ctx.Param(r, "configIds")
if configIds == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 处理字符转id数组后去重
ids := strings.Split(configIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
ctx.JSON(w, 200, result.Err(nil))
return
}
rows, err := s.sysConfigService.DeleteConfigByIds(uniqueIDs)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
msg := fmt.Sprintf("删除成功:%d", rows)
ctx.JSON(w, 200, result.OkMsg(msg))
}
// 参数配置刷新缓存
//
// PUT /refreshCache
func (s *SysConfigApi) RefreshCache(w http.ResponseWriter, r *http.Request) {
s.sysConfigService.ResetConfigCache()
ctx.JSON(w, 200, result.Ok(nil))
}
// 参数配置根据参数键名
//
// GET /configKey/:configKey
func (s *SysConfigApi) ConfigKey(w http.ResponseWriter, r *http.Request) {
configKey := ctx.Param(r, "configKey")
if configKey == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
key := s.sysConfigService.SelectConfigValueByKey(configKey)
if key != "" {
ctx.JSON(w, 200, result.OkData(key))
return
}
ctx.JSON(w, 200, result.Err(nil))
}

View File

@@ -1,25 +0,0 @@
package model
// 参数配置对象 sys_config
type SysConfig struct {
// 参数主键
ConfigID string `json:"configId"`
// 参数名称
ConfigName string `json:"configName" binding:"required"`
// 参数键名
ConfigKey string `json:"configKey" binding:"required"`
// 参数键值
ConfigValue string `json:"configValue" binding:"required"`
// 系统内置Y是 N否
ConfigType string `json:"configType"`
// 创建者
CreateBy string `json:"createBy"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 更新者
UpdateBy string `json:"updateBy"`
// 更新时间
UpdateTime int64 `json:"updateTime"`
// 备注
Remark string `json:"remark"`
}

View File

@@ -1,336 +0,0 @@
package service
import (
"fmt"
"strings"
"time"
"nms_cxy/features/sys_config/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/date"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysConfig 结构体
var NewRepoSysConfig = &RepoSysConfig{
selectSql: `select
config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark
from sys_config`,
resultMap: map[string]string{
"config_id": "ConfigID",
"config_name": "ConfigName",
"config_key": "ConfigKey",
"config_value": "ConfigValue",
"config_type": "ConfigType",
"remark": "Remark",
"create_by": "CreateBy",
"create_time": "CreateTime",
"update_by": "UpdateBy",
"update_time": "UpdateTime",
},
}
// RepoSysConfig 参数配置表 数据层处理
type RepoSysConfig struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoSysConfig) convertResultRows(rows []map[string]any) []model.SysConfig {
arr := make([]model.SysConfig, 0)
for _, row := range rows {
sysConfig := model.SysConfig{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&sysConfig, keyMapper, value)
}
}
arr = append(arr, sysConfig)
}
return arr
}
// SelectDictDataPage 分页查询参数配置列表数据
func (r *RepoSysConfig) SelectConfigPage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["configName"]; ok && v != "" {
conditions = append(conditions, "config_name like concat(?, '%')")
params = append(params, v)
}
if v, ok := query["configType"]; ok && v != "" {
conditions = append(conditions, "config_type = ?")
params = append(params, v)
}
if v, ok := query["configKey"]; ok && v != "" {
conditions = append(conditions, "config_key like concat(?, '%')")
params = append(params, v)
}
beginTime, ok := query["beginTime"]
if !ok {
beginTime, ok = query["params[beginTime]"]
}
if ok && beginTime != "" {
conditions = append(conditions, "create_time >= ?")
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
params = append(params, beginDate.UnixMilli())
}
endTime, ok := query["endTime"]
if !ok {
endTime, ok = query["params[endTime]"]
}
if ok && endTime != "" {
conditions = append(conditions, "create_time <= ?")
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
params = append(params, endDate.UnixMilli())
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from sys_config"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return map[string]any{
"total": total,
"rows": []model.SysConfig{},
}
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 查询数据
querySql := r.selectSql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
rows := r.convertResultRows(results)
return map[string]any{
"total": total,
"rows": rows,
}
}
// SelectConfigList 查询参数配置列表
func (r *RepoSysConfig) SelectConfigList(sysConfig model.SysConfig) []model.SysConfig {
// 查询条件拼接
var conditions []string
var params []any
if sysConfig.ConfigName != "" {
conditions = append(conditions, "config_name like concat(?, '%')")
params = append(params, sysConfig.ConfigName)
}
if sysConfig.ConfigType != "" {
conditions = append(conditions, "config_type = ?")
params = append(params, sysConfig.ConfigType)
}
if sysConfig.ConfigKey != "" {
conditions = append(conditions, "config_key like concat(?, '%')")
params = append(params, sysConfig.ConfigKey)
}
if sysConfig.CreateTime > 0 {
conditions = append(conditions, "create_time >= ?")
params = append(params, sysConfig.CreateTime)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := r.selectSql + whereSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysConfig{}
}
// 转换实体
return r.convertResultRows(results)
}
// SelectConfigValueByKey 通过参数键名查询参数键值
func (r *RepoSysConfig) SelectConfigValueByKey(configKey string) string {
querySql := "select config_value as 'str' from sys_config where config_key = ?"
results, err := datasource.RawDB("", querySql, []any{configKey})
if err != nil {
log.Errorf("query err => %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}
// SelectConfigByIds 通过配置ID查询参数配置信息
func (r *RepoSysConfig) SelectConfigByIds(configIds []string) []model.SysConfig {
placeholder := datasource.KeyPlaceholderByQuery(len(configIds))
querySql := r.selectSql + " where config_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(configIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysConfig{}
}
// 转换实体
return r.convertResultRows(results)
}
// CheckUniqueConfig 校验配置参数是否唯一
func (r *RepoSysConfig) CheckUniqueConfig(sysConfig model.SysConfig) string {
// 查询条件拼接
var conditions []string
var params []any
if sysConfig.ConfigKey != "" {
conditions = append(conditions, "config_key = ?")
params = append(params, sysConfig.ConfigKey)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select config_id as 'str' from sys_config " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}
// InsertConfig 新增参数配置
func (r *RepoSysConfig) InsertConfig(sysConfig model.SysConfig) string {
// 参数拼接
params := make(map[string]any)
if sysConfig.ConfigName != "" {
params["config_name"] = sysConfig.ConfigName
}
if sysConfig.ConfigKey != "" {
params["config_key"] = sysConfig.ConfigKey
}
if sysConfig.ConfigValue != "" {
params["config_value"] = sysConfig.ConfigValue
}
if sysConfig.ConfigType != "" {
params["config_type"] = sysConfig.ConfigType
}
if sysConfig.Remark != "" {
params["remark"] = sysConfig.Remark
}
if sysConfig.CreateBy != "" {
params["create_by"] = sysConfig.CreateBy
params["create_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
sql := "insert into sys_config (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
// 执行插入
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
return fmt.Sprint(insertId)
}
// UpdateConfig 修改参数配置
func (r *RepoSysConfig) UpdateConfig(sysConfig model.SysConfig) int64 {
// 参数拼接
params := make(map[string]any)
if sysConfig.ConfigName != "" {
params["config_name"] = sysConfig.ConfigName
}
if sysConfig.ConfigKey != "" {
params["config_key"] = sysConfig.ConfigKey
}
if sysConfig.ConfigValue != "" {
params["config_value"] = sysConfig.ConfigValue
}
if sysConfig.ConfigType != "" {
params["config_type"] = sysConfig.ConfigType
}
if sysConfig.Remark != "" {
params["remark"] = sysConfig.Remark
}
if sysConfig.UpdateBy != "" {
params["update_by"] = sysConfig.UpdateBy
params["update_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, values := datasource.KeyValueByUpdate(params)
sql := "update sys_config set " + strings.Join(keys, ",") + " where config_id = ?"
// 执行更新
values = append(values, sysConfig.ConfigID)
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}
// DeleteConfigByIds 批量删除参数配置信息
func (r *RepoSysConfig) DeleteConfigByIds(configIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(configIds))
sql := "delete from sys_config where config_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(configIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}

View File

@@ -1,155 +0,0 @@
package service
import (
"errors"
"nms_cxy/features/sys_config/model"
"nms_cxy/lib/core/cache"
"nms_cxy/lib/core/constants/cachekey"
)
// 实例化服务层 ServiceSysConfig 结构体
var NewServiceSysConfig = &ServiceSysConfig{
sysConfigRepository: NewRepoSysConfig,
}
// ServiceSysConfig 参数配置 服务层处理
type ServiceSysConfig struct {
// 参数配置表
sysConfigRepository *RepoSysConfig
}
// SelectDictDataPage 分页查询参数配置列表数据
func (r *ServiceSysConfig) SelectConfigPage(query map[string]any) map[string]any {
return r.sysConfigRepository.SelectConfigPage(query)
}
// SelectConfigList 查询参数配置列表
func (r *ServiceSysConfig) SelectConfigList(sysConfig model.SysConfig) []model.SysConfig {
return r.sysConfigRepository.SelectConfigList(sysConfig)
}
// SelectConfigValueByKey 通过参数键名查询参数键值
func (r *ServiceSysConfig) SelectConfigValueByKey(configKey string) string {
cacheKey := r.getCacheKey(configKey)
// 从缓存中读取
cacheValue, ok := cache.GetLocal(cacheKey)
if cacheValue != nil && ok {
return cacheValue.(string)
}
// 无缓存时读取数据放入缓存中
configValue := r.sysConfigRepository.SelectConfigValueByKey(configKey)
if configValue != "" {
cache.SetLocal(cacheKey, configValue)
return configValue
}
return ""
}
// SelectConfigById 通过配置ID查询参数配置信息
func (r *ServiceSysConfig) SelectConfigById(configId string) model.SysConfig {
if configId == "" {
return model.SysConfig{}
}
configs := r.sysConfigRepository.SelectConfigByIds([]string{configId})
if len(configs) > 0 {
return configs[0]
}
return model.SysConfig{}
}
// CheckUniqueConfigKey 校验参数键名是否唯一
func (r *ServiceSysConfig) CheckUniqueConfigKey(configKey, configId string) bool {
uniqueId := r.sysConfigRepository.CheckUniqueConfig(model.SysConfig{
ConfigKey: configKey,
})
if uniqueId == configId {
return true
}
return uniqueId == ""
}
// InsertConfig 新增参数配置
func (r *ServiceSysConfig) InsertConfig(sysConfig model.SysConfig) string {
configId := r.sysConfigRepository.InsertConfig(sysConfig)
if configId != "" {
r.loadingConfigCache(sysConfig.ConfigKey)
}
return configId
}
// UpdateConfig 修改参数配置
func (r *ServiceSysConfig) UpdateConfig(sysConfig model.SysConfig) int64 {
rows := r.sysConfigRepository.UpdateConfig(sysConfig)
if rows > 0 {
r.loadingConfigCache(sysConfig.ConfigKey)
}
return rows
}
// DeleteConfigByIds 批量删除参数配置信息
func (r *ServiceSysConfig) DeleteConfigByIds(configIds []string) (int64, error) {
// 检查是否存在
configs := r.sysConfigRepository.SelectConfigByIds(configIds)
if len(configs) <= 0 {
return 0, errors.New("does not have permission to access parameter configuration data")
}
for _, config := range configs {
// 检查是否为内置参数
if config.ConfigType == "Y" {
return 0, errors.New(config.ConfigID + " Configuration parameters are built-in parameters and their deletion is prohibited!")
}
// 清除缓存
r.clearConfigCache(config.ConfigKey)
}
if len(configs) == len(configIds) {
rows := r.sysConfigRepository.DeleteConfigByIds(configIds)
return rows, nil
}
return 0, errors.New("failed to delete parameter configuration information")
}
// ResetConfigCache 重置参数缓存数据
func (r *ServiceSysConfig) ResetConfigCache() {
r.clearConfigCache("*")
r.loadingConfigCache("*")
}
// getCacheKey 组装缓存key
func (r *ServiceSysConfig) getCacheKey(configKey string) string {
return cachekey.SYS_CONFIG_KEY + configKey
}
// loadingConfigCache 加载参数缓存数据
func (r *ServiceSysConfig) loadingConfigCache(configKey string) {
// 查询全部参数
if configKey == "*" {
sysConfigs := r.SelectConfigList(model.SysConfig{})
for _, v := range sysConfigs {
key := r.getCacheKey(v.ConfigKey)
cache.DeleteLocal(key)
cache.SetLocal(key, v.ConfigValue)
}
return
}
// 指定参数
if configKey != "" {
cacheValue := r.sysConfigRepository.SelectConfigValueByKey(configKey)
if cacheValue != "" {
key := r.getCacheKey(configKey)
cache.DeleteLocal(key)
cache.SetLocal(key, cacheValue)
}
return
}
}
// clearConfigCache 清空参数缓存数据
func (r *ServiceSysConfig) clearConfigCache(configKey string) bool {
key := r.getCacheKey(configKey)
keys := cache.GetLocalKeys(key)
for _, v := range keys {
cache.DeleteLocal(v)
}
return len(keys) > 0
}

View File

@@ -1,247 +0,0 @@
package sysdictdata
import (
"fmt"
"net/http"
"strings"
"nms_cxy/features/sys_dict_data/model"
sysDictDataService "nms_cxy/features/sys_dict_data/service"
sysDictTypeService "nms_cxy/features/sys_dict_type/service"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/midware"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
)
// 字典类型对应的字典数据信息接口添加到路由
func Routers() []services.RouterItem {
// 实例化控制层 SysDictDataApi 结构体
var apis = &SysDictDataApi{
sysDictDataService: sysDictDataService.NewServiceSysDictData,
sysDictTypeService: sysDictTypeService.NewServiceSysDictType,
}
rs := [...]services.RouterItem{
{
Method: "GET",
Pattern: "/dictDatas",
Handler: apis.List,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/dictData/{dictCode}",
Handler: apis.Info,
Middleware: midware.Authorize(nil),
},
{
Method: "POST",
Pattern: "/dictData",
Handler: apis.Add,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/dictData",
Handler: apis.Edit,
Middleware: midware.Authorize(nil),
},
{
Method: "DELETE",
Pattern: "/dictData/{dictCodes}",
Handler: apis.Remove,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/dictData/type/{dictType}",
Handler: apis.DictType,
Middleware: midware.Authorize(nil),
},
// 添加更多的 Router 对象...
}
// 生成两组前缀路由
rsPrefix := []services.RouterItem{}
for _, v := range rs {
path := "/dictDataManage/{apiVersion}" + v.Pattern
// 固定前缀
v.Pattern = config.DefaultUriPrefix + path
rsPrefix = append(rsPrefix, v)
// 可配置
v.Pattern = config.UriPrefix + path
rsPrefix = append(rsPrefix, v)
}
return rsPrefix
}
// 字典类型对应的字典数据信息
//
// PATH /dictDataManage
type SysDictDataApi struct {
// 字典数据服务
sysDictDataService *sysDictDataService.ServiceSysDictData
// 字典类型服务
sysDictTypeService *sysDictTypeService.ServiceSysDictType
}
// 字典数据列表
//
// GET /list
func (s *SysDictDataApi) List(w http.ResponseWriter, r *http.Request) {
querys := ctx.QueryMap(r)
data := s.sysDictDataService.SelectDictDataPage(querys)
ctx.JSON(w, 200, result.Ok(data))
}
// 字典数据详情
//
// GET /:dictCode
func (s *SysDictDataApi) Info(w http.ResponseWriter, r *http.Request) {
dictCode := ctx.Param(r, "dictCode")
if dictCode == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
data := s.sysDictDataService.SelectDictDataByCode(dictCode)
if data.DictCode == dictCode {
ctx.JSON(w, 200, result.OkData(data))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 字典数据新增
//
// POST /
func (s *SysDictDataApi) Add(w http.ResponseWriter, r *http.Request) {
var body model.SysDictData
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.DictCode != "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查字典类型是否存在
sysDictType := s.sysDictTypeService.SelectDictTypeByType(body.DictType)
if sysDictType.DictType != body.DictType {
ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary type data!"))
return
}
// 检查字典标签唯一
uniqueDictLabel := s.sysDictDataService.CheckUniqueDictLabel(body.DictType, body.DictLabel, "")
if !uniqueDictLabel {
msg := fmt.Sprintf("[%s] The subscript signature of this dictionary type already exists", body.DictLabel)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查字典键值唯一
uniqueDictValue := s.sysDictDataService.CheckUniqueDictValue(body.DictType, body.DictValue, "")
if !uniqueDictValue {
msg := fmt.Sprintf("[%s] The label value under this dictionary type already exists", body.DictValue)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.CreateBy = ctx.LoginUserToUserName(r)
insertId := s.sysDictDataService.InsertDictData(body)
if insertId != "" {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 字典类型修改
//
// PUT /
func (s *SysDictDataApi) Edit(w http.ResponseWriter, r *http.Request) {
var body model.SysDictData
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.DictCode == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查字典类型是否存在
sysDictType := s.sysDictTypeService.SelectDictTypeByType(body.DictType)
if sysDictType.DictType != body.DictType {
ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary type data!"))
return
}
// 检查字典编码是否存在
SysDictDataApi := s.sysDictDataService.SelectDictDataByCode(body.DictCode)
if SysDictDataApi.DictCode != body.DictCode {
ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary encoding data!"))
return
}
// 检查字典标签唯一
uniqueDictLabel := s.sysDictDataService.CheckUniqueDictLabel(body.DictType, body.DictLabel, body.DictCode)
if !uniqueDictLabel {
msg := fmt.Sprintf("Data modification failed for [%s], the dictionary type subscript signature already exists", body.DictLabel)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查字典键值唯一
uniqueDictValue := s.sysDictDataService.CheckUniqueDictValue(body.DictType, body.DictValue, body.DictCode)
if !uniqueDictValue {
msg := fmt.Sprintf("Data modification failed for [%s], label value already exists under this dictionary type", body.DictValue)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.UpdateBy = ctx.LoginUserToUserName(r)
rows := s.sysDictDataService.UpdateDictData(body)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 字典数据删除
//
// DELETE /:dictCodes
func (s *SysDictDataApi) Remove(w http.ResponseWriter, r *http.Request) {
dictCodes := ctx.Param(r, "dictCodes")
if dictCodes == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 处理字符转id数组后去重
ids := strings.Split(dictCodes, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
ctx.JSON(w, 200, result.Err(nil))
return
}
rows, err := s.sysDictDataService.DeleteDictDataByCodes(uniqueIDs)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
msg := fmt.Sprintf("Successfully deleted: %d", rows)
ctx.JSON(w, 200, result.OkMsg(msg))
}
// 字典数据列表(指定字典类型)
//
// GET /type/:dictType
func (s *SysDictDataApi) DictType(w http.ResponseWriter, r *http.Request) {
dictType := ctx.Param(r, "dictType")
if dictType == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
data := s.sysDictDataService.SelectDictDataByType(dictType)
ctx.JSON(w, 200, result.OkData(data))
}

View File

@@ -1,31 +0,0 @@
package model
// SysDictData 字典数据对象 sys_dict_data
type SysDictData struct {
// 字典编码
DictCode string `json:"dictCode"`
// 字典排序
DictSort int `json:"dictSort"`
// 字典标签
DictLabel string `json:"dictLabel" binding:"required"`
// 字典键值
DictValue string `json:"dictValue" binding:"required"`
// 字典类型
DictType string `json:"dictType" binding:"required"`
// 样式属性(样式扩展)
TagClass string `json:"tagClass"`
// 标签类型(预设颜色)
TagType string `json:"tagType"`
// 状态0停用 1正常
Status string `json:"status"`
// 创建者
CreateBy string `json:"createBy"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 更新者
UpdateBy string `json:"updateBy"`
// 更新时间
UpdateTime int64 `json:"updateTime"`
// 备注
Remark string `json:"remark"`
}

View File

@@ -1,369 +0,0 @@
package repo
import (
"fmt"
"strings"
"time"
"nms_cxy/features/sys_dict_data/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysDictData 结构体
var NewRepoSysDictData = &RepoSysDictData{
selectSql: `select
dict_code, dict_sort, dict_label, dict_value, dict_type, tag_class, tag_type, status, create_by, create_time, remark
from sys_dict_data`,
resultMap: map[string]string{
"dict_code": "DictCode",
"dict_sort": "DictSort",
"dict_label": "DictLabel",
"dict_value": "DictValue",
"dict_type": "DictType",
"tag_class": "TagClass",
"tag_type": "TagType",
"status": "Status",
"remark": "Remark",
"create_by": "CreateBy",
"create_time": "CreateTime",
"update_by": "UpdateBy",
"update_time": "UpdateTime",
},
}
// RepoSysDictData 字典类型数据表 数据层处理
type RepoSysDictData struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoSysDictData) convertResultRows(rows []map[string]any) []model.SysDictData {
arr := make([]model.SysDictData, 0)
for _, row := range rows {
sysDictData := model.SysDictData{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&sysDictData, keyMapper, value)
}
}
arr = append(arr, sysDictData)
}
return arr
}
// SelectDictDataPage 根据条件分页查询字典数据
func (r *RepoSysDictData) SelectDictDataPage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["dictType"]; ok && v != "" {
conditions = append(conditions, "dict_type = ?")
params = append(params, v)
}
if v, ok := query["dictLabel"]; ok && v != "" {
conditions = append(conditions, "dict_label like concat(?, '%')")
params = append(params, v)
}
if v, ok := query["status"]; ok && v != "" {
conditions = append(conditions, "status = ?")
params = append(params, v)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from sys_dict_data"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return map[string]any{
"total": total,
"rows": []model.SysDictData{},
}
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " order by dict_sort asc limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 查询数据
querySql := r.selectSql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
rows := r.convertResultRows(results)
return map[string]any{
"total": total,
"rows": rows,
}
}
// SelectDictDataList 根据条件查询字典数据
func (r *RepoSysDictData) SelectDictDataList(sysDictData model.SysDictData) []model.SysDictData {
// 查询条件拼接
var conditions []string
var params []any
if sysDictData.DictLabel != "" {
conditions = append(conditions, "dict_label like concat(?, '%')")
params = append(params, sysDictData.DictLabel)
}
if sysDictData.DictType != "" {
conditions = append(conditions, "dict_type = ?")
params = append(params, sysDictData.DictType)
}
if sysDictData.Status != "" {
conditions = append(conditions, "status = ?")
params = append(params, sysDictData.Status)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
orderSql := " order by dict_sort asc "
querySql := r.selectSql + whereSql + orderSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysDictData{}
}
// 转换实体
return r.convertResultRows(results)
}
// SelectDictDataByCodes 根据字典数据编码查询信息
func (r *RepoSysDictData) SelectDictDataByCodes(dictCodes []string) []model.SysDictData {
placeholder := datasource.KeyPlaceholderByQuery(len(dictCodes))
querySql := r.selectSql + " where dict_code in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(dictCodes)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysDictData{}
}
// 转换实体
return r.convertResultRows(results)
}
// CountDictDataByType 查询字典数据
func (r *RepoSysDictData) CountDictDataByType(dictType string) int64 {
querySql := "select count(1) as 'total' from sys_dict_data where dict_type = ?"
results, err := datasource.RawDB("", querySql, []any{dictType})
if err != nil {
log.Errorf("query err => %v", err)
return 0
}
if len(results) > 0 {
return parse.Number(results[0]["total"])
}
return 0
}
// CheckUniqueDictData 校验字典数据是否唯一
func (r *RepoSysDictData) CheckUniqueDictData(sysDictData model.SysDictData) string {
// 查询条件拼接
var conditions []string
var params []any
if sysDictData.DictType != "" {
conditions = append(conditions, "dict_type = ?")
params = append(params, sysDictData.DictType)
}
if sysDictData.DictLabel != "" {
conditions = append(conditions, "dict_label = ?")
params = append(params, sysDictData.DictLabel)
}
if sysDictData.DictValue != "" {
conditions = append(conditions, "dict_value = ?")
params = append(params, sysDictData.DictValue)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select dict_code as 'str' from sys_dict_data " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}
// DeleteDictDataByCodes 批量删除字典数据信息
func (r *RepoSysDictData) DeleteDictDataByCodes(dictCodes []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(dictCodes))
sql := "delete from sys_dict_data where dict_code in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(dictCodes)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// InsertDictData 新增字典数据信息
func (r *RepoSysDictData) InsertDictData(sysDictData model.SysDictData) string {
// 参数拼接
params := make(map[string]any)
if sysDictData.DictSort > 0 {
params["dict_sort"] = sysDictData.DictSort
}
if sysDictData.DictLabel != "" {
params["dict_label"] = sysDictData.DictLabel
}
if sysDictData.DictValue != "" {
params["dict_value"] = sysDictData.DictValue
}
if sysDictData.DictType != "" {
params["dict_type"] = sysDictData.DictType
}
if sysDictData.TagClass != "" {
params["tag_class"] = sysDictData.TagClass
}
if sysDictData.TagType != "" {
params["tag_type"] = sysDictData.TagType
}
if sysDictData.Status != "" {
params["status"] = sysDictData.Status
}
if sysDictData.Remark != "" {
params["remark"] = sysDictData.Remark
}
if sysDictData.CreateBy != "" {
params["create_by"] = sysDictData.CreateBy
params["create_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
sql := "insert into sys_dict_data (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
// 执行插入
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
return fmt.Sprint(insertId)
}
// UpdateDictData 修改字典数据信息
func (r *RepoSysDictData) UpdateDictData(sysDictData model.SysDictData) int64 {
// 参数拼接
params := make(map[string]any)
if sysDictData.DictSort > 0 {
params["dict_sort"] = sysDictData.DictSort
}
if sysDictData.DictLabel != "" {
params["dict_label"] = sysDictData.DictLabel
}
if sysDictData.DictValue != "" {
params["dict_value"] = sysDictData.DictValue
}
if sysDictData.DictType != "" {
params["dict_type"] = sysDictData.DictType
}
if sysDictData.TagClass != "" {
params["tag_class"] = sysDictData.TagClass
}
if sysDictData.TagType != "" {
params["tag_type"] = sysDictData.TagType
}
if sysDictData.Status != "" {
params["status"] = sysDictData.Status
}
if sysDictData.Remark != "" {
params["remark"] = sysDictData.Remark
}
if sysDictData.UpdateBy != "" {
params["update_by"] = sysDictData.UpdateBy
params["update_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, values := datasource.KeyValueByUpdate(params)
sql := "update sys_dict_data set " + strings.Join(keys, ",") + " where dict_code = ?"
// 执行更新
values = append(values, sysDictData.DictCode)
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}
// UpdateDictDataType 同步修改字典类型
func (r *RepoSysDictData) UpdateDictDataType(oldDictType string, newDictType string) int64 {
// 参数拼接
params := make([]any, 0)
if oldDictType == "" || newDictType == "" {
return 0
}
params = append(params, newDictType)
params = append(params, oldDictType)
// 构建执行语句
sql := "update sys_dict_data set dict_type = ? where dict_type = ?"
// 执行更新
results, err := datasource.ExecDB("", sql, params)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}

View File

@@ -1,111 +0,0 @@
package service
import (
"errors"
"nms_cxy/features/sys_dict_data/model"
"nms_cxy/features/sys_dict_data/repo"
sysDictTypeService "nms_cxy/features/sys_dict_type/service"
)
// 实例化服务层 ServiceSysDictData 结构体
var NewServiceSysDictData = &ServiceSysDictData{
sysDictDataRepository: *repo.NewRepoSysDictData,
sysDictTypeService: *sysDictTypeService.NewServiceSysDictType,
}
// ServiceSysDictData 字典类型数据 服务层处理
type ServiceSysDictData struct {
// 字典数据服务
sysDictDataRepository repo.RepoSysDictData
// 字典类型服务
sysDictTypeService sysDictTypeService.ServiceSysDictType
}
// SelectDictDataPage 根据条件分页查询字典数据
func (r *ServiceSysDictData) SelectDictDataPage(query map[string]any) map[string]any {
return r.sysDictDataRepository.SelectDictDataPage(query)
}
// SelectDictDataList 根据条件查询字典数据
func (r *ServiceSysDictData) SelectDictDataList(sysDictData model.SysDictData) []model.SysDictData {
return r.sysDictDataRepository.SelectDictDataList(sysDictData)
}
// SelectDictDataByCode 根据字典数据编码查询信息
func (r *ServiceSysDictData) SelectDictDataByCode(dictCode string) model.SysDictData {
if dictCode == "" {
return model.SysDictData{}
}
dictCodes := r.sysDictDataRepository.SelectDictDataByCodes([]string{dictCode})
if len(dictCodes) > 0 {
return dictCodes[0]
}
return model.SysDictData{}
}
// SelectDictDataByType 根据字典类型查询信息
func (r *ServiceSysDictData) SelectDictDataByType(dictType string) []model.SysDictData {
return r.sysDictTypeService.DictDataCache(dictType)
}
// CheckUniqueDictLabel 校验字典标签是否唯一
func (r *ServiceSysDictData) CheckUniqueDictLabel(dictType, dictLabel, dictCode string) bool {
uniqueId := r.sysDictDataRepository.CheckUniqueDictData(model.SysDictData{
DictType: dictType,
DictLabel: dictLabel,
})
if uniqueId == dictCode {
return true
}
return uniqueId == ""
}
// CheckUniqueDictValue 校验字典键值是否唯一
func (r *ServiceSysDictData) CheckUniqueDictValue(dictType, dictValue, dictCode string) bool {
uniqueId := r.sysDictDataRepository.CheckUniqueDictData(model.SysDictData{
DictType: dictType,
DictValue: dictValue,
})
if uniqueId == dictCode {
return true
}
return uniqueId == ""
}
// DeleteDictDataByCodes 批量删除字典数据信息
func (r *ServiceSysDictData) DeleteDictDataByCodes(dictCodes []string) (int64, error) {
// 检查是否存在
dictDatas := r.sysDictDataRepository.SelectDictDataByCodes(dictCodes)
if len(dictDatas) <= 0 {
return 0, errors.New("does not have permission to access dictionary-encoded data")
}
if len(dictDatas) == len(dictCodes) {
for _, v := range dictDatas {
// 刷新缓存
r.sysDictTypeService.ClearDictCache(v.DictType)
r.sysDictTypeService.LoadingDictCache(v.DictType)
}
rows := r.sysDictDataRepository.DeleteDictDataByCodes(dictCodes)
return rows, nil
}
return 0, errors.New("failed to delete dictionary data information")
}
// InsertDictData 新增字典数据信息
func (r *ServiceSysDictData) InsertDictData(sysDictData model.SysDictData) string {
insertId := r.sysDictDataRepository.InsertDictData(sysDictData)
if insertId != "" {
r.sysDictTypeService.LoadingDictCache(sysDictData.DictType)
}
return insertId
}
// UpdateDictData 修改字典数据信息
func (r *ServiceSysDictData) UpdateDictData(sysDictData model.SysDictData) int64 {
rows := r.sysDictDataRepository.UpdateDictData(sysDictData)
if rows > 0 {
r.sysDictTypeService.LoadingDictCache(sysDictData.DictType)
}
return rows
}

View File

@@ -1,253 +0,0 @@
package sysdicttype
import (
"fmt"
"net/http"
"strings"
"nms_cxy/features/sys_dict_type/model"
sysDictTypeService "nms_cxy/features/sys_dict_type/service"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/midware"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
)
// 字典类型信息接口添加到路由
func Routers() []services.RouterItem {
// 实例化控制层 SysDictTypeApi 结构体
var apis = &SysDictTypeApi{
sysDictTypeService: *sysDictTypeService.NewServiceSysDictType,
}
rs := [...]services.RouterItem{
{
Method: "GET",
Pattern: "/dictTypes",
Handler: apis.List,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/dictType/{dictId}",
Handler: apis.Info,
Middleware: midware.Authorize(nil),
},
{
Method: "POST",
Pattern: "/dictType",
Handler: apis.Add,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/dictType",
Handler: apis.Edit,
Middleware: midware.Authorize(nil),
},
{
Method: "DELETE",
Pattern: "/dictType/{dictIds}",
Handler: apis.Remove,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/dictType/refreshCache",
Handler: apis.RefreshCache,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/dictTypes/optionselect",
Handler: apis.DictOptionselect,
Middleware: midware.Authorize(nil),
},
// 添加更多的 Router 对象...
}
// 生成两组前缀路由
rsPrefix := []services.RouterItem{}
for _, v := range rs {
path := "/dictTypegManage/{apiVersion}" + v.Pattern
// 固定前缀
v.Pattern = config.DefaultUriPrefix + path
rsPrefix = append(rsPrefix, v)
// 可配置
v.Pattern = config.UriPrefix + path
rsPrefix = append(rsPrefix, v)
}
return rsPrefix
}
// 字典类型信息
//
// PATH /dictTypegManage
type SysDictTypeApi struct {
// 字典类型服务
sysDictTypeService sysDictTypeService.ServiceSysDictType
}
// 字典类型列表
//
// GET /list
func (s *SysDictTypeApi) List(w http.ResponseWriter, r *http.Request) {
querys := ctx.QueryMap(r)
data := s.sysDictTypeService.SelectDictTypePage(querys)
ctx.JSON(w, 200, result.Ok(data))
}
// 字典类型信息
//
// GET /:dictId
func (s *SysDictTypeApi) Info(w http.ResponseWriter, r *http.Request) {
dictId := ctx.Param(r, "dictId")
if dictId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
data := s.sysDictTypeService.SelectDictTypeByID(dictId)
if data.DictID == dictId {
ctx.JSON(w, 200, result.OkData(data))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 字典类型新增
//
// POST /
func (s *SysDictTypeApi) Add(w http.ResponseWriter, r *http.Request) {
var body model.SysDictType
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.DictID != "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查字典名称唯一
uniqueDictName := s.sysDictTypeService.CheckUniqueDictName(body.DictName, "")
if !uniqueDictName {
msg := fmt.Sprintf("Failed to add dictionary '%s', dictionary name already exists", body.DictName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查字典类型唯一
uniqueDictType := s.sysDictTypeService.CheckUniqueDictType(body.DictType, "")
if !uniqueDictType {
msg := fmt.Sprintf("Failed to add dictionary '%s', dictionary type already exists", body.DictType)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.CreateBy = ctx.LoginUserToUserName(r)
insertId := s.sysDictTypeService.InsertDictType(body)
if insertId != "" {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 字典类型修改
//
// PUT /
func (s *SysDictTypeApi) Edit(w http.ResponseWriter, r *http.Request) {
var body model.SysDictType
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.DictID == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查数据是否存在
dictInfo := s.sysDictTypeService.SelectDictTypeByID(body.DictID)
if dictInfo.DictID != body.DictID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary type data!"))
return
}
// 检查字典名称唯一
uniqueDictName := s.sysDictTypeService.CheckUniqueDictName(body.DictName, body.DictID)
if !uniqueDictName {
msg := fmt.Sprintf("Dictionary modification failed for [%s], dictionary name already exists", body.DictName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查字典类型唯一
uniqueDictType := s.sysDictTypeService.CheckUniqueDictType(body.DictType, body.DictID)
if !uniqueDictType {
msg := fmt.Sprintf("Dictionary modification failed for [%s], dictionary type already exists", body.DictType)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.UpdateBy = ctx.LoginUserToUserName(r)
rows := s.sysDictTypeService.UpdateDictType(body)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 字典类型删除
//
// DELETE /:dictIds
func (s *SysDictTypeApi) Remove(w http.ResponseWriter, r *http.Request) {
dictIds := ctx.Param(r, "dictIds")
if dictIds == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 处理字符转id数组后去重
ids := strings.Split(dictIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
ctx.JSON(w, 200, result.Err(nil))
return
}
rows, err := s.sysDictTypeService.DeleteDictTypeByIDs(uniqueIDs)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
msg := fmt.Sprintf("Successfully deleted: %d", rows)
ctx.JSON(w, 200, result.OkMsg(msg))
}
// 字典类型刷新缓存
//
// PUT /refreshCache
func (s *SysDictTypeApi) RefreshCache(w http.ResponseWriter, r *http.Request) {
s.sysDictTypeService.ResetDictCache()
ctx.JSON(w, 200, result.Ok(nil))
}
// 字典类型选择框列表
//
// GET /getDictOptionselect
func (s *SysDictTypeApi) DictOptionselect(w http.ResponseWriter, r *http.Request) {
data := s.sysDictTypeService.SelectDictTypeList(model.SysDictType{
Status: "1",
})
type labelValue struct {
Label string `json:"label"`
Value string `json:"value"`
}
// 数据组
arr := []labelValue{}
for _, v := range data {
arr = append(arr, labelValue{
Label: v.DictName,
Value: v.DictType,
})
}
ctx.JSON(w, 200, result.OkData(arr))
}

View File

@@ -1,23 +0,0 @@
package model
// SysDictType 字典类型对象 sys_dict_type
type SysDictType struct {
// 字典主键
DictID string `json:"dictId"`
// 字典名称
DictName string `json:"dictName" binding:"required"`
// 字典类型
DictType string `json:"dictType" binding:"required"`
// 状态0停用 1正常
Status string `json:"status"`
// 创建者
CreateBy string `json:"createBy"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 更新者
UpdateBy string `json:"updateBy"`
// 更新时间
UpdateTime int64 `json:"updateTime"`
// 备注
Remark string `json:"remark"`
}

View File

@@ -1,330 +0,0 @@
package repo
import (
"fmt"
"strings"
"time"
"nms_cxy/features/sys_dict_type/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/date"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysDictType 结构体
var NewRepoSysDictType = &RepoSysDictType{
selectSql: `select
dict_id, dict_name, dict_type, status, create_by, create_time, remark
from sys_dict_type`,
resultMap: map[string]string{
"dict_id": "DictID",
"dict_name": "DictName",
"dict_type": "DictType",
"remark": "Remark",
"status": "Status",
"create_by": "CreateBy",
"create_time": "CreateTime",
"update_by": "UpdateBy",
"update_time": "UpdateTime",
},
}
// RepoSysDictType 字典类型表 数据层处理
type RepoSysDictType struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoSysDictType) convertResultRows(rows []map[string]any) []model.SysDictType {
arr := make([]model.SysDictType, 0)
for _, row := range rows {
sysDictType := model.SysDictType{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&sysDictType, keyMapper, value)
}
}
arr = append(arr, sysDictType)
}
return arr
}
// SelectDictTypePage 根据条件分页查询字典类型
func (r *RepoSysDictType) SelectDictTypePage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["dictName"]; ok && v != "" {
conditions = append(conditions, "dict_name like concat(?, '%')")
params = append(params, v)
}
if v, ok := query["dictType"]; ok && v != "" {
conditions = append(conditions, "dict_type like concat(?, '%')")
params = append(params, v)
}
if v, ok := query["status"]; ok && v != "" {
conditions = append(conditions, "status = ?")
params = append(params, v)
}
beginTime, ok := query["beginTime"]
if !ok {
beginTime, ok = query["params[beginTime]"]
}
if ok && beginTime != "" {
conditions = append(conditions, "create_time >= ?")
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
params = append(params, beginDate.UnixMilli())
}
endTime, ok := query["endTime"]
if !ok {
endTime, ok = query["params[endTime]"]
}
if ok && endTime != "" {
conditions = append(conditions, "create_time <= ?")
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
params = append(params, endDate.UnixMilli())
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from sys_dict_type"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return map[string]any{
"total": total,
"rows": []model.SysDictType{},
}
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 查询数据
querySql := r.selectSql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
rows := r.convertResultRows(results)
return map[string]any{
"total": total,
"rows": rows,
}
}
// SelectDictTypeList 根据条件查询字典类型
func (r *RepoSysDictType) SelectDictTypeList(sysDictType model.SysDictType) []model.SysDictType {
// 查询条件拼接
var conditions []string
var params []any
if sysDictType.DictName != "" {
conditions = append(conditions, "dict_name like concat(?, '%')")
params = append(params, sysDictType.DictName)
}
if sysDictType.DictType != "" {
conditions = append(conditions, "dict_type like concat(?, '%')")
params = append(params, sysDictType.DictType)
}
if sysDictType.Status != "" {
conditions = append(conditions, "status = ?")
params = append(params, sysDictType.Status)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := r.selectSql + whereSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysDictType{}
}
// 转换实体
return r.convertResultRows(results)
}
// SelectDictTypeByIDs 根据字典类型ID查询信息
func (r *RepoSysDictType) SelectDictTypeByIDs(dictIDs []string) []model.SysDictType {
placeholder := datasource.KeyPlaceholderByQuery(len(dictIDs))
querySql := r.selectSql + " where dict_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(dictIDs)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysDictType{}
}
// 转换实体
return r.convertResultRows(results)
}
// SelectDictTypeByType 根据字典类型查询信息
func (r *RepoSysDictType) SelectDictTypeByType(dictType string) model.SysDictType {
querySql := r.selectSql + " where dict_type = ?"
results, err := datasource.RawDB("", querySql, []any{dictType})
if err != nil {
log.Errorf("query err => %v", err)
return model.SysDictType{}
}
// 转换实体
rows := r.convertResultRows(results)
if len(rows) > 0 {
return rows[0]
}
return model.SysDictType{}
}
// CheckUniqueDictType 校验字典是否唯一
func (r *RepoSysDictType) CheckUniqueDictType(sysDictType model.SysDictType) string {
// 查询条件拼接
var conditions []string
var params []any
if sysDictType.DictName != "" {
conditions = append(conditions, "dict_name = ?")
params = append(params, sysDictType.DictName)
}
if sysDictType.DictType != "" {
conditions = append(conditions, "dict_type = ?")
params = append(params, sysDictType.DictType)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select dict_id as 'str' from sys_dict_type " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}
// InsertDictType 新增字典类型信息
func (r *RepoSysDictType) InsertDictType(sysDictType model.SysDictType) string {
// 参数拼接
params := make(map[string]any)
if sysDictType.DictName != "" {
params["dict_name"] = sysDictType.DictName
}
if sysDictType.DictType != "" {
params["dict_type"] = sysDictType.DictType
}
if sysDictType.Status != "" {
params["status"] = sysDictType.Status
}
if sysDictType.Remark != "" {
params["remark"] = sysDictType.Remark
}
if sysDictType.CreateBy != "" {
params["create_by"] = sysDictType.CreateBy
params["create_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
sql := "insert into sys_dict_type (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
// 执行插入
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
return fmt.Sprint(insertId)
}
// UpdateDictType 修改字典类型信息
func (r *RepoSysDictType) UpdateDictType(sysDictType model.SysDictType) int64 {
// 参数拼接
params := make(map[string]any)
if sysDictType.DictName != "" {
params["dict_name"] = sysDictType.DictName
}
if sysDictType.DictType != "" {
params["dict_type"] = sysDictType.DictType
}
if sysDictType.Status != "" {
params["status"] = sysDictType.Status
}
if sysDictType.Remark != "" {
params["remark"] = sysDictType.Remark
}
if sysDictType.UpdateBy != "" {
params["update_by"] = sysDictType.UpdateBy
params["update_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, values := datasource.KeyValueByUpdate(params)
sql := "update sys_dict_type set " + strings.Join(keys, ",") + " where dict_id = ?"
// 执行更新
values = append(values, sysDictType.DictID)
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}
// DeleteDictTypeByIDs 批量删除字典类型信息
func (r *RepoSysDictType) DeleteDictTypeByIDs(dictIDs []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(dictIDs))
sql := "delete from sys_dict_type where dict_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(dictIDs)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}

View File

@@ -1,211 +0,0 @@
package service
import (
"encoding/json"
"errors"
"fmt"
sysDictDataModel "nms_cxy/features/sys_dict_data/model"
sysDictDataRepo "nms_cxy/features/sys_dict_data/repo"
sysDictTypeModel "nms_cxy/features/sys_dict_type/model"
"nms_cxy/features/sys_dict_type/repo"
"nms_cxy/lib/core/cache"
"nms_cxy/lib/core/constants/cachekey"
)
// 实例化服务层 ServiceSysDictType 结构体
var NewServiceSysDictType = &ServiceSysDictType{
sysDictTypeRepository: *repo.NewRepoSysDictType,
sysDictDataRepository: *sysDictDataRepo.NewRepoSysDictData,
}
// ServiceSysDictType 字典类型 服务层处理
type ServiceSysDictType struct {
// 字典类型服务
sysDictTypeRepository repo.RepoSysDictType
// 字典数据服务
sysDictDataRepository sysDictDataRepo.RepoSysDictData
}
// SelectDictTypePage 根据条件分页查询字典类型
func (r *ServiceSysDictType) SelectDictTypePage(query map[string]any) map[string]any {
return r.sysDictTypeRepository.SelectDictTypePage(query)
}
// SelectDictTypeList 根据条件查询字典类型
func (r *ServiceSysDictType) SelectDictTypeList(sysDictType sysDictTypeModel.SysDictType) []sysDictTypeModel.SysDictType {
return r.sysDictTypeRepository.SelectDictTypeList(sysDictType)
}
// SelectDictTypeByID 根据字典类型ID查询信息
func (r *ServiceSysDictType) SelectDictTypeByID(dictID string) sysDictTypeModel.SysDictType {
if dictID == "" {
return sysDictTypeModel.SysDictType{}
}
dictTypes := r.sysDictTypeRepository.SelectDictTypeByIDs([]string{dictID})
if len(dictTypes) > 0 {
return dictTypes[0]
}
return sysDictTypeModel.SysDictType{}
}
// SelectDictTypeByType 根据字典类型查询信息
func (r *ServiceSysDictType) SelectDictTypeByType(dictType string) sysDictTypeModel.SysDictType {
return r.sysDictTypeRepository.SelectDictTypeByType(dictType)
}
// CheckUniqueDictName 校验字典名称是否唯一
func (r *ServiceSysDictType) CheckUniqueDictName(dictName, dictID string) bool {
uniqueId := r.sysDictTypeRepository.CheckUniqueDictType(sysDictTypeModel.SysDictType{
DictName: dictName,
})
if uniqueId == dictID {
return true
}
return uniqueId == ""
}
// CheckUniqueDictType 校验字典类型是否唯一
func (r *ServiceSysDictType) CheckUniqueDictType(dictType, dictID string) bool {
uniqueId := r.sysDictTypeRepository.CheckUniqueDictType(sysDictTypeModel.SysDictType{
DictType: dictType,
})
if uniqueId == dictID {
return true
}
return uniqueId == ""
}
// InsertDictType 新增字典类型信息
func (r *ServiceSysDictType) InsertDictType(sysDictType sysDictTypeModel.SysDictType) string {
insertId := r.sysDictTypeRepository.InsertDictType(sysDictType)
if insertId != "" {
r.LoadingDictCache(sysDictType.DictType)
}
return insertId
}
// UpdateDictType 修改字典类型信息
func (r *ServiceSysDictType) UpdateDictType(sysDictType sysDictTypeModel.SysDictType) int64 {
data := r.sysDictTypeRepository.SelectDictTypeByIDs([]string{sysDictType.DictID})
if len(data) == 0 {
return 0
}
// 修改字典类型key时同步更新其字典数据的类型key
oldDictType := data[0].DictType
rows := r.sysDictTypeRepository.UpdateDictType(sysDictType)
if rows > 0 && oldDictType != "" && oldDictType != sysDictType.DictType {
r.sysDictDataRepository.UpdateDictDataType(oldDictType, sysDictType.DictType)
}
// 刷新缓存
r.ClearDictCache(oldDictType)
r.LoadingDictCache(sysDictType.DictType)
return rows
}
// DeleteDictTypeByIDs 批量删除字典类型信息
func (r *ServiceSysDictType) DeleteDictTypeByIDs(dictIDs []string) (int64, error) {
// 检查是否存在
dictTypes := r.sysDictTypeRepository.SelectDictTypeByIDs(dictIDs)
if len(dictTypes) <= 0 {
return 0, errors.New("no permission to access dictionary type data")
}
for _, v := range dictTypes {
// 字典类型下级含有数据
useCount := r.sysDictDataRepository.CountDictDataByType(v.DictType)
if useCount > 0 {
msg := fmt.Sprintf("[%s] Dictionary data exists and cannot be deleted. ", v.DictName)
return 0, errors.New(msg)
}
// 清除缓存
r.ClearDictCache(v.DictType)
}
if len(dictTypes) == len(dictIDs) {
rows := r.sysDictTypeRepository.DeleteDictTypeByIDs(dictIDs)
return rows, nil
}
return 0, errors.New("failed to delete dictionary data information")
}
// ResetDictCache 重置字典缓存数据
func (r *ServiceSysDictType) ResetDictCache() {
r.ClearDictCache("*")
r.LoadingDictCache("")
}
// getCacheKey 组装缓存key
func (r *ServiceSysDictType) getDictCache(dictType string) string {
return cachekey.SYS_DICT_KEY + dictType
}
// LoadingDictCache 加载字典缓存数据
func (r *ServiceSysDictType) LoadingDictCache(dictType string) {
sysDictData := sysDictDataModel.SysDictData{
Status: "1",
}
// 指定字典类型
if dictType != "" {
sysDictData.DictType = dictType
// 删除缓存
key := r.getDictCache(dictType)
cache.DeleteLocal(key)
}
sysDictDataList := r.sysDictDataRepository.SelectDictDataList(sysDictData)
if len(sysDictDataList) == 0 {
return
}
// 将字典数据按类型分组
m := make(map[string][]sysDictDataModel.SysDictData, 0)
for _, v := range sysDictDataList {
key := v.DictType
if item, ok := m[key]; ok {
m[key] = append(item, v)
} else {
m[key] = []sysDictDataModel.SysDictData{v}
}
}
// 放入缓存
for k, v := range m {
key := r.getDictCache(k)
values, _ := json.Marshal(v)
cache.SetLocal(key, string(values))
}
}
// ClearDictCache 清空字典缓存数据
func (r *ServiceSysDictType) ClearDictCache(dictType string) bool {
key := r.getDictCache(dictType)
keys := cache.GetLocalKeys(key)
for _, v := range keys {
cache.DeleteLocal(v)
}
return len(keys) > 0
}
// DictDataCache 获取字典数据缓存数据
func (r *ServiceSysDictType) DictDataCache(dictType string) []sysDictDataModel.SysDictData {
data := []sysDictDataModel.SysDictData{}
key := r.getDictCache(dictType)
jsonAny, ok := cache.GetLocal(key)
if jsonAny != nil && ok {
err := json.Unmarshal([]byte(jsonAny.(string)), &data)
if err != nil {
data = []sysDictDataModel.SysDictData{}
}
} else {
data = r.sysDictDataRepository.SelectDictDataList(sysDictDataModel.SysDictData{
Status: "1",
DictType: dictType,
})
if len(data) > 0 {
cache.DeleteLocal(key)
values, _ := json.Marshal(data)
cache.SetLocal(key, string(values))
}
}
return data
}

View File

@@ -1,354 +0,0 @@
package sysmenu
import (
"fmt"
"net/http"
"nms_cxy/features/sys_menu/consts"
"nms_cxy/features/sys_menu/model"
"nms_cxy/features/sys_menu/service"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/utils/regular"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/midware"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
srcConfig "nms_cxy/src/framework/config"
)
// 菜单接口添加到路由
func Routers() []services.RouterItem {
// 实例化控制层 SysMenuApi 结构体
var apis = &SysMenuApi{
sysMenuService: service.NewServiceSysMenu,
}
rs := [...]services.RouterItem{
{
Method: "GET",
Pattern: "/menus",
Handler: apis.List,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/menu/{menuId}",
Handler: apis.Info,
Middleware: midware.Authorize(nil),
},
{
Method: "POST",
Pattern: "/menu",
Handler: apis.Add,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/menu",
Handler: apis.Edit,
Middleware: midware.Authorize(nil),
},
{
Method: "DELETE",
Pattern: "/menu/{menuId}",
Handler: apis.Remove,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/menus/treeSelect",
Handler: apis.TreeSelect,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/menu/roleMenuTreeSelect/{roleId}",
Handler: apis.RoleMenuTreeSelect,
Middleware: midware.Authorize(nil),
},
// 添加更多的 Router 对象...
}
// 生成两组前缀路由
rsPrefix := []services.RouterItem{}
for _, v := range rs {
path := "/menuManage/{apiVersion}" + v.Pattern
// 固定前缀
v.Pattern = config.DefaultUriPrefix + path
rsPrefix = append(rsPrefix, v)
// 可配置
v.Pattern = config.UriPrefix + path
rsPrefix = append(rsPrefix, v)
}
return rsPrefix
}
// // 实例化控制层 SysMenuApi 结构体
// var NewSysMenu = &SysMenuApi{
// sysMenuService: NewServiceSysMenu,
// }
// 菜单信息
//
// PATH /menuManage
type SysMenuApi struct {
// 菜单服务
sysMenuService *service.ServiceSysMenu
}
// 菜单列表
//
// GET /list
func (s *SysMenuApi) List(w http.ResponseWriter, r *http.Request) {
query := model.SysMenu{}
if v := ctx.GetQuery(r, "menuName"); v != "" {
query.MenuName = v
}
if v := ctx.GetQuery(r, "status"); v != "" {
query.Status = v
}
userId := ctx.LoginUserToUserID(r)
if srcConfig.IsAdmin(userId) {
userId = "*"
}
data := s.sysMenuService.SelectMenuList(query, userId)
ctx.JSON(w, 200, result.OkData(data))
}
// 菜单信息
//
// GET /:menuId
func (s *SysMenuApi) Info(w http.ResponseWriter, r *http.Request) {
menuId := ctx.Param(r, "menuId")
if menuId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
data := s.sysMenuService.SelectMenuById(menuId)
if data.MenuID == menuId {
ctx.JSON(w, 200, result.OkData(data))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 菜单新增
//
// POST /
func (s *SysMenuApi) Add(w http.ResponseWriter, r *http.Request) {
var body model.SysMenu
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.MenuID != "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 目录和菜单检查地址唯一
if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType {
uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, "")
if !uniqueNenuPath {
msg := fmt.Sprintf("菜单新增【%s】失败菜单路由地址已存在", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
}
// 检查名称唯一
uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, "")
if !uniqueNenuName {
msg := fmt.Sprintf("菜单新增【%s】失败菜单名称已存在", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 外链菜单需要符合网站http(s)开头
if body.IsFrame == "0" && !regular.ValidHttp(body.Path) {
msg := fmt.Sprintf("菜单新增【%s】失败非内部地址必须以http(s)://开头", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.CreateBy = ctx.LoginUserToUserName(r)
insertId := s.sysMenuService.InsertMenu(body)
if insertId != "" {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 菜单修改
//
// PUT /
func (s *SysMenuApi) Edit(w http.ResponseWriter, r *http.Request) {
var body model.SysMenu
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.MenuID == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 上级菜单不能选自己
if body.MenuID == body.ParentID {
msg := fmt.Sprintf("Menu modification failed for [%s], parent menu cannot select itself", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查数据是否存在
menuInfo := s.sysMenuService.SelectMenuById(body.MenuID)
if menuInfo.MenuID != body.MenuID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data"))
return
}
// 父级ID不为0是要检查
if body.ParentID != "0" {
menuParent := s.sysMenuService.SelectMenuById(body.ParentID)
if menuParent.MenuID != body.ParentID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data"))
return
}
// 禁用菜单时检查父菜单是否使用
if body.Status == "1" && menuParent.Status == "0" {
ctx.JSON(w, 200, result.ErrMsg("Parent menu not enabled!"))
return
}
}
// 目录和菜单检查地址唯一
if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType {
uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.MenuID)
if !uniqueNenuPath {
msg := fmt.Sprintf("菜单修改【%s】失败菜单路由地址已存在", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
}
// 检查名称唯一
uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, body.MenuID)
if !uniqueNenuName {
msg := fmt.Sprintf("菜单修改【%s】失败菜单名称已存在", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 外链菜单需要符合网站http(s)开头
if body.IsFrame == "0" && !regular.ValidHttp(body.Path) {
msg := fmt.Sprintf("菜单修改【%s】失败非内部地址必须以http(s)://开头", body.MenuName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 禁用菜单时检查子菜单是否使用
if body.Status == "0" {
hasStatus := s.sysMenuService.HasChildByMenuIdAndStatus(body.MenuID, "1")
if hasStatus > 0 {
msg := fmt.Sprintf("不允许禁用,存在使用子菜单数:%d", hasStatus)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
}
body.UpdateBy = ctx.LoginUserToUserName(r)
rows := s.sysMenuService.UpdateMenu(body)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 菜单删除
//
// DELETE /:menuId
func (s *SysMenuApi) Remove(w http.ResponseWriter, r *http.Request) {
menuId := ctx.Param(r, "menuId")
if menuId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查数据是否存在
menu := s.sysMenuService.SelectMenuById(menuId)
if menu.MenuID != menuId {
ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data!"))
return
}
// 检查是否存在子菜单
hasChild := s.sysMenuService.HasChildByMenuIdAndStatus(menuId, "")
if hasChild > 0 {
msg := fmt.Sprintf("Deletion not allowed, there are sub orders: %d", hasChild)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 检查是否分配给角色
existRole := s.sysMenuService.CheckMenuExistRole(menuId)
if existRole > 0 {
msg := fmt.Sprintf("Deletion not allowed, menu already assigned to roles: %d", existRole)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
rows := s.sysMenuService.DeleteMenuById(menuId)
if rows > 0 {
msg := fmt.Sprintf("Successfully deleted: %d", rows)
ctx.JSON(w, 200, result.OkMsg(msg))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 菜单树结构列表
//
// GET /treeSelect
func (s *SysMenuApi) TreeSelect(w http.ResponseWriter, r *http.Request) {
query := model.SysMenu{}
if v := ctx.GetQuery(r, "menuName"); v != "" {
query.MenuName = v
}
if v := ctx.GetQuery(r, "status"); v != "" {
query.Status = v
}
userId := ctx.LoginUserToUserID(r)
if srcConfig.IsAdmin(userId) {
userId = "*"
}
data := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId)
ctx.JSON(w, 200, result.OkData(data))
}
// 菜单树结构列表(指定角色)
//
// GET /roleMenuTreeSelect/:roleId
func (s *SysMenuApi) RoleMenuTreeSelect(w http.ResponseWriter, r *http.Request) {
roleId := ctx.Param(r, "roleId")
if roleId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
query := model.SysMenu{}
if v := ctx.GetQuery(r, "menuName"); v != "" {
query.MenuName = v
}
if v := ctx.GetQuery(r, "status"); v != "" {
query.Status = v
}
userId := ctx.LoginUserToUserID(r)
if srcConfig.IsAdmin(userId) {
userId = "*"
}
menuTreeSelect := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId)
checkedKeys := s.sysMenuService.SelectMenuListByRoleId(roleId)
ctx.JSON(w, 200, result.OkData(map[string]any{
"menus": menuTreeSelect,
"checkedKeys": checkedKeys,
}))
}

View File

@@ -1,24 +0,0 @@
package consts
// 系统菜单常量信息
const (
// 组件布局类型-基础布局组件标识
COMPONENT_LAYOUT_BASIC = "BasicLayout"
// 组件布局类型-空白布局组件标识
COMPONENT_LAYOUT_BLANK = "BlankLayout"
// 组件布局类型-内链接布局组件标识
COMPONENT_LAYOUT_LINK = "LinkLayout"
)
const (
// 菜单类型-目录
TYPE_DIR = "D"
// 菜单类型-菜单
TYPE_MENU = "M"
// 菜单类型-按钮
TYPE_BUTTON = "B"
)
// 菜单内嵌地址标识-带/前缀
const PATH_INLINE = "/inline"

View File

@@ -1,46 +0,0 @@
package model
// SysMenu 菜单权限对象 sys_menu
type SysMenu struct {
// 菜单ID
MenuID string `json:"menuId"`
// 菜单名称
MenuName string `json:"menuName" binding:"required"`
// 父菜单ID 默认0
ParentID string `json:"parentId" binding:"required"`
// 显示顺序
MenuSort int `json:"menuSort"`
// 路由地址
Path string `json:"path"`
// 组件路径
Component string `json:"component"`
// 是否内部跳转0否 1是
IsFrame string `json:"isFrame"`
// 是否缓存0不缓存 1缓存
IsCache string `json:"isCache"`
// 菜单类型D目录 M菜单 B按钮
MenuType string `json:"menuType" binding:"required"`
// 是否显示0隐藏 1显示
Visible string `json:"visible"`
// 菜单状态0停用 1正常
Status string `json:"status"`
// 权限标识
Perms string `json:"perms"`
// 菜单图标(#无图标)
Icon string `json:"icon"`
// 创建者
CreateBy string `json:"createBy"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 更新者
UpdateBy string `json:"updateBy"`
// 更新时间
UpdateTime int64 `json:"updateTime"`
// 备注
Remark string `json:"remark"`
// ====== 非数据库字段属性 ======
// 子菜单
Children []SysMenu `json:"children,omitempty"`
}

View File

@@ -1,475 +0,0 @@
package service
import (
"fmt"
"strings"
"time"
"nms_cxy/features/sys_menu/consts"
"nms_cxy/features/sys_menu/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysMenu 结构体
var NewRepoSysMenu = &RepoSysMenu{
selectSql: `select
m.menu_id, m.menu_name, m.parent_id, m.menu_sort, m.path, m.component, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, ifnull(m.perms,'') as perms, m.icon, m.create_time, m.remark
from sys_menu m`,
selectSqlByUser: `select distinct
m.menu_id, m.menu_name, m.parent_id, m.menu_sort, m.path, m.component, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, ifnull(m.perms,'') as perms, m.icon, m.create_time, m.remark
from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id
left join sys_role ro on ur.role_id = ro.role_id`,
resultMap: map[string]string{
"menu_id": "MenuID",
"menu_name": "MenuName",
"parent_name": "ParentName",
"parent_id": "ParentID",
"path": "Path",
"menu_sort": "MenuSort",
"component": "Component",
"is_frame": "IsFrame",
"is_cache": "IsCache",
"menu_type": "MenuType",
"visible": "Visible",
"status": "Status",
"perms": "Perms",
"icon": "Icon",
"create_by": "CreateBy",
"create_time": "CreateTime",
"update_by": "UpdateBy",
"update_time": "UpdateTime",
"remark": "Remark",
},
}
// RepoSysMenu 菜单表 数据层处理
type RepoSysMenu struct {
// 查询视图对象SQL
selectSql string
// 查询视图用户对象SQL
selectSqlByUser string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoSysMenu) convertResultRows(rows []map[string]any) []model.SysMenu {
arr := make([]model.SysMenu, 0)
for _, row := range rows {
sysMenu := model.SysMenu{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&sysMenu, keyMapper, value)
}
}
arr = append(arr, sysMenu)
}
return arr
}
// SelectMenuList 查询系统菜单列表
func (r *RepoSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu {
// 查询条件拼接
var conditions []string
var params []any
if sysMenu.MenuName != "" {
conditions = append(conditions, "m.menu_name like concat('%', concat(?, '%'))")
params = append(params, sysMenu.MenuName)
}
if sysMenu.Visible != "" {
conditions = append(conditions, "m.visible = ?")
params = append(params, sysMenu.Visible)
}
if sysMenu.Status != "" {
conditions = append(conditions, "m.status = ?")
params = append(params, sysMenu.Status)
}
fromSql := r.selectSql
// 个人菜单
if userId != "*" {
fromSql = r.selectSqlByUser
conditions = append(conditions, "ur.user_id = ?")
params = append(params, userId)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
orderSql := " order by m.parent_id, m.menu_sort"
querySql := fromSql + whereSql + orderSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysMenu{}
}
// 转换实体
return r.convertResultRows(results)
}
// SelectMenuPermsByUserId 根据用户ID查询权限
func (r *RepoSysMenu) SelectMenuPermsByUserId(userId string) []string {
querySql := `select distinct m.perms as 'str' from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id
left join sys_role r on r.role_id = ur.role_id
where m.status = '1' and m.perms != '' and r.status = '1' and ur.user_id = ? `
// 查询结果
results, err := datasource.RawDB("", querySql, []any{userId})
if err != nil {
log.Errorf("query err => %v", err)
return []string{}
}
// 读取结果
rows := make([]string, 0)
for _, m := range results {
rows = append(rows, fmt.Sprintf("%v", m["str"]))
}
return rows
}
// SelectMenuTreeByUserId 根据用户ID查询菜单
func (r *RepoSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu {
var params []any
var querySql string
if userId == "*" {
// 管理员全部菜单
querySql = r.selectSql + ` where
m.menu_type in (?,?) and m.status = '1'
order by m.parent_id, m.menu_sort`
params = append(params, consts.TYPE_DIR)
params = append(params, consts.TYPE_MENU)
} else {
// 用户ID权限
querySql = r.selectSqlByUser + ` where
m.menu_type in (?, ?) and m.status = '1'
and ur.user_id = ? and ro.status = '1'
order by m.parent_id, m.menu_sort`
params = append(params, consts.TYPE_DIR)
params = append(params, consts.TYPE_MENU)
params = append(params, userId)
}
// 查询结果
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysMenu{}
}
return r.convertResultRows(results)
}
// SelectMenuListByRoleId 根据角色ID查询菜单树信息
func (r *RepoSysMenu) SelectMenuListByRoleId(roleId string, menuCheckStrictly bool) []string {
querySql := `select m.menu_id as 'str' from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id
where rm.role_id = ? `
var params []any
params = append(params, roleId)
// 展开
if menuCheckStrictly {
querySql += ` and m.menu_id not in
(select m.parent_id from sys_menu m
inner join sys_role_menu rm on m.menu_id = rm.menu_id
and rm.role_id = ?) `
params = append(params, roleId)
}
// 查询结果
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []string{}
}
if len(results) > 0 {
ids := make([]string, 0)
for _, v := range results {
ids = append(ids, fmt.Sprintf("%v", v["str"]))
}
return ids
}
return []string{}
}
// SelectMenuByIds 根据菜单ID查询信息
func (r *RepoSysMenu) SelectMenuByIds(menuIds []string) []model.SysMenu {
placeholder := datasource.KeyPlaceholderByQuery(len(menuIds))
querySql := r.selectSql + " where m.menu_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(menuIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysMenu{}
}
// 转换实体
return r.convertResultRows(results)
}
// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态
func (r *RepoSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 {
querySql := "select count(1) as 'total' from sys_menu where parent_id = ?"
params := []any{menuId}
// 菜单状态
if status != "" {
querySql += " and status = ?"
params = append(params, status)
}
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return 0
}
if len(results) > 0 {
return parse.Number(results[0]["total"])
}
return 0
}
// InsertMenu 新增菜单信息
func (r *RepoSysMenu) InsertMenu(sysMenu model.SysMenu) string {
// 参数拼接
params := make(map[string]any)
if sysMenu.MenuID != "" {
params["menu_id"] = sysMenu.MenuID
}
if sysMenu.ParentID != "" {
params["parent_id"] = sysMenu.ParentID
}
if sysMenu.MenuName != "" {
params["menu_name"] = sysMenu.MenuName
}
if sysMenu.MenuSort > 0 {
params["menu_sort"] = sysMenu.MenuSort
}
if sysMenu.Path != "" {
params["path"] = sysMenu.Path
}
if sysMenu.Component != "" {
params["component"] = sysMenu.Component
}
if sysMenu.IsFrame != "" {
params["is_frame"] = sysMenu.IsFrame
}
if sysMenu.IsCache != "" {
params["is_cache"] = sysMenu.IsCache
}
if sysMenu.MenuType != "" {
params["menu_type"] = sysMenu.MenuType
}
if sysMenu.Visible != "" {
params["visible"] = sysMenu.Visible
}
if sysMenu.Status != "" {
params["status"] = sysMenu.Status
}
if sysMenu.Perms != "" {
params["perms"] = sysMenu.Perms
}
if sysMenu.Icon != "" {
params["icon"] = sysMenu.Icon
} else {
params["icon"] = "#"
}
if sysMenu.Remark != "" {
params["remark"] = sysMenu.Remark
}
if sysMenu.CreateBy != "" {
params["create_by"] = sysMenu.CreateBy
params["create_time"] = time.Now().UnixMilli()
}
// 根据菜单类型重置参数
if sysMenu.MenuType == consts.TYPE_BUTTON {
params["component"] = ""
params["path"] = ""
params["icon"] = "#"
params["is_cache"] = "1"
params["is_frame"] = "1"
params["visible"] = "1"
params["status"] = "1"
}
if sysMenu.MenuType == consts.TYPE_DIR {
params["component"] = ""
params["perms"] = ""
}
// 构建执行语句
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
sql := "insert into sys_menu (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
// 执行插入
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
return fmt.Sprint(insertId)
}
// UpdateMenu 修改菜单信息
func (r *RepoSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 {
// 参数拼接
params := make(map[string]any)
if sysMenu.MenuID != "" {
params["menu_id"] = sysMenu.MenuID
}
if sysMenu.ParentID != "" {
params["parent_id"] = sysMenu.ParentID
}
if sysMenu.MenuName != "" {
params["menu_name"] = sysMenu.MenuName
}
if sysMenu.MenuSort > 0 {
params["menu_sort"] = sysMenu.MenuSort
}
if sysMenu.Path != "" {
params["path"] = sysMenu.Path
}
if sysMenu.Component != "" {
params["component"] = sysMenu.Component
}
if sysMenu.IsFrame != "" {
params["is_frame"] = sysMenu.IsFrame
}
if sysMenu.IsCache != "" {
params["is_cache"] = sysMenu.IsCache
}
if sysMenu.MenuType != "" {
params["menu_type"] = sysMenu.MenuType
}
if sysMenu.Visible != "" {
params["visible"] = sysMenu.Visible
}
if sysMenu.Status != "" {
params["status"] = sysMenu.Status
}
if sysMenu.Perms != "" {
params["perms"] = sysMenu.Perms
}
if sysMenu.Icon != "" {
params["icon"] = sysMenu.Icon
} else {
params["icon"] = "#"
}
if sysMenu.Remark != "" {
params["remark"] = sysMenu.Remark
}
if sysMenu.UpdateBy != "" {
params["update_by"] = sysMenu.UpdateBy
params["update_time"] = time.Now().UnixMilli()
}
// 根据菜单类型重置参数
if sysMenu.MenuType == consts.TYPE_BUTTON {
params["component"] = ""
params["path"] = ""
params["icon"] = "#"
params["is_cache"] = "1"
params["is_frame"] = "1"
params["visible"] = "1"
params["status"] = "1"
}
if sysMenu.MenuType == consts.TYPE_DIR {
params["component"] = ""
params["perms"] = ""
}
// 构建执行语句
keys, values := datasource.KeyValueByUpdate(params)
sql := "update sys_menu set " + strings.Join(keys, ",") + " where menu_id = ?"
// 执行更新
values = append(values, sysMenu.MenuID)
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}
// DeleteMenuById 删除菜单管理信息
func (r *RepoSysMenu) DeleteMenuById(menuId string) int64 {
sql := "delete from sys_menu where menu_id = ?"
results, err := datasource.ExecDB("", sql, []any{menuId})
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// CheckUniqueMenu 校验菜单是否唯一
func (r *RepoSysMenu) CheckUniqueMenu(sysMenu model.SysMenu) string {
// 查询条件拼接
var conditions []string
var params []any
if sysMenu.MenuName != "" {
conditions = append(conditions, "menu_name = ?")
params = append(params, sysMenu.MenuName)
}
if sysMenu.ParentID != "" {
conditions = append(conditions, "parent_id = ?")
params = append(params, sysMenu.ParentID)
}
if sysMenu.Path != "" {
conditions = append(conditions, "path = ?")
params = append(params, sysMenu.Path)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
if whereSql == "" {
return ""
}
// 查询数据
querySql := "select menu_id as 'str' from sys_menu " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}

View File

@@ -1,408 +0,0 @@
package service
import (
"encoding/base64"
"strings"
"nms_cxy/features/sys_menu/consts"
"nms_cxy/features/sys_menu/model"
sysRoleService "nms_cxy/features/sys_role/service"
sysrolemenu "nms_cxy/features/sys_role_menu"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/utils/regular"
"nms_cxy/lib/core/vo"
)
// 实例化服务层 ServiceSysMenu 结构体
var NewServiceSysMenu = &ServiceSysMenu{
sysMenuRepository: NewRepoSysMenu,
sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu,
sysRoleRepository: sysRoleService.NewRepoSysRole,
}
// ServiceSysMenu 菜单 服务层处理
type ServiceSysMenu struct {
// 菜单服务
sysMenuRepository *RepoSysMenu
// 角色与菜单关联服务
sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu
// 角色服务
sysRoleRepository *sysRoleService.RepoSysRole
}
// SelectMenuList 查询系统菜单列表
func (r *ServiceSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu {
return r.sysMenuRepository.SelectMenuList(sysMenu, userId)
}
// SelectMenuPermsByUserId 根据用户ID查询权限
func (r *ServiceSysMenu) SelectMenuPermsByUserId(userId string) []string {
return r.sysMenuRepository.SelectMenuPermsByUserId(userId)
}
// SelectMenuTreeByUserId 根据用户ID查询菜单
func (r *ServiceSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu {
sysMenus := r.sysMenuRepository.SelectMenuTreeByUserId(userId)
return r.parseDataToTree(sysMenus)
}
// SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息
func (r *ServiceSysMenu) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect {
sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId)
// 过滤旧前端菜单
sysMenusF := []model.SysMenu{}
for _, v := range sysMenus {
if v.Perms != "page" {
continue
}
sysMenusF = append(sysMenusF, v)
}
menus := r.parseDataToTree(sysMenusF)
tree := make([]vo.TreeSelect, 0)
for _, menu := range menus {
tree = append(tree, sysMenuTreeSelect(menu))
}
return tree
}
// sysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象
func sysMenuTreeSelect(sysMenu model.SysMenu) vo.TreeSelect {
t := vo.TreeSelect{}
t.ID = sysMenu.MenuID
t.Label = sysMenu.MenuName
t.Title = sysMenu.MenuName
if len(sysMenu.Children) > 0 {
for _, menu := range sysMenu.Children {
child := sysMenuTreeSelect(menu)
t.Children = append(t.Children, child)
}
} else {
t.Children = []vo.TreeSelect{}
}
return t
}
// SelectMenuListByRoleId 根据角色ID查询菜单树信息 TODO
func (r *ServiceSysMenu) SelectMenuListByRoleId(roleId string) []string {
roles := r.sysRoleRepository.SelectRoleByIds([]string{roleId})
if len(roles) > 0 {
role := roles[0]
if role.RoleID == roleId {
return r.sysMenuRepository.SelectMenuListByRoleId(
role.RoleID,
role.MenuCheckStrictly == "1",
)
}
}
return []string{}
}
// SelectMenuById 根据菜单ID查询信息
func (r *ServiceSysMenu) SelectMenuById(menuId string) model.SysMenu {
if menuId == "" {
return model.SysMenu{}
}
menus := r.sysMenuRepository.SelectMenuByIds([]string{menuId})
if len(menus) > 0 {
return menus[0]
}
return model.SysMenu{}
}
// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态
func (r *ServiceSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 {
return r.sysMenuRepository.HasChildByMenuIdAndStatus(menuId, status)
}
// CheckMenuExistRole 查询菜单是否存在角色
func (r *ServiceSysMenu) CheckMenuExistRole(menuId string) int64 {
return r.sysRoleMenuRepository.CheckMenuExistRole(menuId)
}
// InsertMenu 新增菜单信息
func (r *ServiceSysMenu) InsertMenu(sysMenu model.SysMenu) string {
return r.sysMenuRepository.InsertMenu(sysMenu)
}
// UpdateMenu 修改菜单信息
func (r *ServiceSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 {
return r.sysMenuRepository.UpdateMenu(sysMenu)
}
// DeleteMenuById 删除菜单管理信息
func (r *ServiceSysMenu) DeleteMenuById(menuId string) int64 {
// 删除菜单与角色关联
r.sysRoleMenuRepository.DeleteMenuRole([]string{menuId})
return r.sysMenuRepository.DeleteMenuById(menuId)
}
// CheckUniqueMenuName 校验菜单名称是否唯一
func (r *ServiceSysMenu) CheckUniqueMenuName(menuName, parentId, menuId string) bool {
uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{
MenuName: menuName,
ParentID: parentId,
})
if uniqueId == menuId {
return true
}
return uniqueId == ""
}
// CheckUniqueMenuPath 校验路由地址是否唯一(针对目录和菜单)
func (r *ServiceSysMenu) CheckUniqueMenuPath(path, menuId string) bool {
uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{
Path: path,
})
if uniqueId == menuId {
return true
}
return uniqueId == ""
}
// BuildRouteMenus 构建前端路由所需要的菜单
func (r *ServiceSysMenu) BuildRouteMenus(sysMenus []model.SysMenu, prefix string) []vo.Router {
routers := []vo.Router{}
for _, item := range sysMenus {
router := vo.Router{}
router.Name = r.getRouteName(item)
router.Path = r.getRouterPath(item)
router.Component = r.getComponent(item)
router.Meta = r.getRouteMeta(item)
// 子项菜单 目录类型 非路径链接
cMenus := item.Children
if len(cMenus) > 0 && item.MenuType == consts.TYPE_DIR && !regular.ValidHttp(item.Path) {
// 获取重定向地址
redirectPrefix, redirectPath := r.getRouteRedirect(
cMenus,
router.Path,
prefix,
)
router.Redirect = redirectPath
// 子菜单进入递归
router.Children = r.BuildRouteMenus(cMenus, redirectPrefix)
} else if item.ParentID == "0" && item.IsFrame == "1" && item.MenuType == consts.TYPE_MENU {
// 父菜单 内部跳转 菜单类型
menuPath := "/" + item.MenuID
childPath := menuPath + r.getRouterPath(item)
children := vo.Router{
Name: r.getRouteName(item),
Path: childPath,
Component: item.Component,
Meta: r.getRouteMeta(item),
}
router.Meta.HideChildInMenu = true
router.Children = append(router.Children, children)
router.Name = item.MenuID
router.Path = menuPath
router.Redirect = childPath
router.Component = consts.COMPONENT_LAYOUT_BASIC
} else if item.ParentID == "0" && item.IsFrame == "1" && regular.ValidHttp(item.Path) {
// 父菜单 内部跳转 路径链接
menuPath := "/" + item.MenuID
childPath := menuPath + r.getRouterPath(item)
children := vo.Router{
Name: r.getRouteName(item),
Path: childPath,
Component: consts.COMPONENT_LAYOUT_LINK,
Meta: r.getRouteMeta(item),
}
router.Meta.HideChildInMenu = true
router.Children = append(router.Children, children)
router.Name = item.MenuID
router.Path = menuPath
router.Redirect = childPath
router.Component = consts.COMPONENT_LAYOUT_BASIC
}
routers = append(routers, router)
}
return routers
}
// getRouteName 获取路由名称 路径英文首字母大写
func (r *ServiceSysMenu) getRouteName(sysMenu model.SysMenu) string {
routerName := parse.FirstUpper(sysMenu.Path)
// 路径链接
if regular.ValidHttp(sysMenu.Path) {
return routerName[:5] + "Link" + sysMenu.MenuID
}
return routerName
}
// getRouterPath 获取路由地址
func (r *ServiceSysMenu) getRouterPath(sysMenu model.SysMenu) string {
routerPath := sysMenu.Path
// 显式路径
if routerPath == "" || strings.HasPrefix(routerPath, "/") {
return routerPath
}
// 路径链接 内部跳转
if regular.ValidHttp(routerPath) && sysMenu.IsFrame == "1" {
routerPath = regular.Replace(routerPath, `/^http(s)?:\/\/+/`, "")
routerPath = base64.StdEncoding.EncodeToString([]byte(routerPath))
}
// 父菜单 内部跳转
if sysMenu.ParentID == "0" && sysMenu.IsFrame == "1" {
routerPath = "/" + routerPath
}
return routerPath
}
// getComponent 获取组件信息
func (r *ServiceSysMenu) getComponent(sysMenu model.SysMenu) string {
// 内部跳转 路径链接
if sysMenu.IsFrame == "1" && regular.ValidHttp(sysMenu.Path) {
return consts.COMPONENT_LAYOUT_LINK
}
// 非父菜单 目录类型
if sysMenu.ParentID != "0" && sysMenu.MenuType == consts.TYPE_DIR {
return consts.COMPONENT_LAYOUT_BLANK
}
// 组件路径 内部跳转 菜单类型
if sysMenu.Component != "" && sysMenu.IsFrame == "1" && sysMenu.MenuType == consts.TYPE_MENU {
// 父菜单套外层布局
if sysMenu.ParentID == "0" {
return consts.COMPONENT_LAYOUT_BASIC
}
return sysMenu.Component
}
return consts.COMPONENT_LAYOUT_BASIC
}
// getRouteMeta 获取路由元信息
func (r *ServiceSysMenu) getRouteMeta(sysMenu model.SysMenu) vo.RouterMeta {
meta := vo.RouterMeta{}
if sysMenu.Icon == "#" {
meta.Icon = ""
} else {
meta.Icon = sysMenu.Icon
}
meta.Title = sysMenu.MenuName
meta.HideChildInMenu = false
meta.HideInMenu = sysMenu.Visible == "0"
meta.Cache = sysMenu.IsCache == "1"
meta.Target = ""
// 路径链接 非内部跳转
if regular.ValidHttp(sysMenu.Path) && sysMenu.IsFrame == "0" {
meta.Target = "_blank"
}
return meta
}
// getRouteRedirect 获取路由重定向地址(针对目录)
//
// cMenus 子菜单数组
// routerPath 当前菜单路径
// prefix 菜单重定向路径前缀
func (r *ServiceSysMenu) getRouteRedirect(cMenus []model.SysMenu, routerPath string, prefix string) (string, string) {
redirectPath := ""
// 重定向为首个显示并启用的子菜单
var firstChild *model.SysMenu
for _, item := range cMenus {
if item.IsFrame == "1" && item.Visible == "1" {
firstChild = &item
break
}
}
// 检查内嵌隐藏菜单是否可做重定向
if firstChild == nil {
for _, item := range cMenus {
if item.IsFrame == "1" && item.Visible == "1" && strings.Contains(item.Path, consts.PATH_INLINE) {
firstChild = &item
break
}
}
}
if firstChild != nil {
firstChildPath := r.getRouterPath(*firstChild)
if strings.HasPrefix(firstChildPath, "/") {
redirectPath = firstChildPath
} else {
// 拼接追加路径
if !strings.HasPrefix(routerPath, "/") {
prefix += "/"
}
prefix = prefix + routerPath
redirectPath = prefix + "/" + firstChildPath
}
}
return prefix, redirectPath
}
// parseDataToTree 将数据解析为树结构,构建前端所需要下拉树结构
func (r *ServiceSysMenu) parseDataToTree(sysMenus []model.SysMenu) []model.SysMenu {
// 节点分组
nodesMap := make(map[string][]model.SysMenu)
// 节点id
treeIds := []string{}
// 树节点
tree := []model.SysMenu{}
for _, item := range sysMenus {
parentID := item.ParentID
// 分组
mapItem, ok := nodesMap[parentID]
if !ok {
mapItem = []model.SysMenu{}
}
mapItem = append(mapItem, item)
nodesMap[parentID] = mapItem
// 记录节点ID
treeIds = append(treeIds, item.MenuID)
}
for key, value := range nodesMap {
// 选择不是节点ID的作为树节点
found := false
for _, id := range treeIds {
if id == key {
found = true
break
}
}
if !found {
tree = append(tree, value...)
}
}
for i, node := range tree {
iN := r.parseDataToTreeComponet(node, &nodesMap)
tree[i] = iN
}
return tree
}
// parseDataToTreeComponet 递归函数处理子节点
func (r *ServiceSysMenu) parseDataToTreeComponet(node model.SysMenu, nodesMap *map[string][]model.SysMenu) model.SysMenu {
id := node.MenuID
children, ok := (*nodesMap)[id]
if ok {
node.Children = children
}
if len(node.Children) > 0 {
for i, child := range node.Children {
icN := r.parseDataToTreeComponet(child, nodesMap)
node.Children[i] = icN
}
}
return node
}

View File

@@ -1,368 +0,0 @@
package sysrole
import (
"fmt"
"net/http"
"strings"
"nms_cxy/features/sys_role/model"
"nms_cxy/features/sys_role/service"
userService "nms_cxy/features/sys_user/service"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/midware"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
)
// 角色接口添加到路由
func Routers() []services.RouterItem {
// 实例化控制层 SysRoleApi 结构体
var apis = &SysRoleApi{
sysRoleService: service.NewServiceSysRole,
sysUserService: userService.NewServiceSysUser,
}
rs := [...]services.RouterItem{
{
Method: "GET",
Pattern: "/roles",
Handler: apis.List,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/role/{roleId}",
Handler: apis.Info,
Middleware: midware.Authorize(nil),
},
{
Method: "POST",
Pattern: "/role",
Handler: apis.Add,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/role",
Handler: apis.Edit,
Middleware: midware.Authorize(nil),
},
{
Method: "DELETE",
Pattern: "/role/{roleIds}",
Handler: apis.Remove,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/role/changeStatus",
Handler: apis.Status,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/role/authUser/allocatedList",
Handler: apis.AuthUserAllocatedList,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/role/authUser/checked",
Handler: apis.AuthUserChecked,
Middleware: midware.Authorize(nil),
},
// 添加更多的 Router 对象...
}
// 生成两组前缀路由
rsPrefix := []services.RouterItem{}
for _, v := range rs {
path := "/roleManage/{apiVersion}" + v.Pattern
// 固定前缀
v.Pattern = config.DefaultUriPrefix + path
rsPrefix = append(rsPrefix, v)
// 可配置
v.Pattern = config.UriPrefix + path
rsPrefix = append(rsPrefix, v)
}
return rsPrefix
}
// // 实例化控制层 SysRoleApi 结构体
// var NewSysRole = &SysRoleApi{
// sysRoleService: sysrole.NewServiceSysRole,
// sysUserService: sysuser.NewServiceSysUser,
// }
// 角色信息
//
// PATH /roleManage
type SysRoleApi struct {
// 角色服务
sysRoleService *service.ServiceSysRole
// 用户服务
sysUserService *userService.ServiceSysUser
}
// 角色列表
//
// GET /list
func (s *SysRoleApi) List(w http.ResponseWriter, r *http.Request) {
querys := ctx.QueryMap(r)
data := s.sysRoleService.SelectRolePage(querys)
ctx.JSON(w, 200, result.Ok(data))
}
// 角色信息详情
//
// GET /:roleId
func (s *SysRoleApi) Info(w http.ResponseWriter, r *http.Request) {
roleId := ctx.Param(r, "roleId")
if roleId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
data := s.sysRoleService.SelectRoleById(roleId)
if data.RoleID == roleId {
ctx.JSON(w, 200, result.OkData(data))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 角色信息新增
//
// POST /
func (s *SysRoleApi) Add(w http.ResponseWriter, r *http.Request) {
var body model.SysRole
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.RoleID != "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 判断角色名称是否唯一
uniqueRoleName := s.sysRoleService.CheckUniqueRoleName(body.RoleName, "")
if !uniqueRoleName {
msg := fmt.Sprintf("[%s] Role name already exists", body.RoleName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 判断角色键值是否唯一
uniqueRoleKey := s.sysRoleService.CheckUniqueRoleKey(body.RoleKey, "")
if !uniqueRoleKey {
msg := fmt.Sprintf("[%s] The role key value already exists", body.RoleName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.CreateBy = ctx.LoginUserToUserName(r)
insertId := s.sysRoleService.InsertRole(body)
if insertId != "" {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 角色信息修改
//
// PUT /
func (s *SysRoleApi) Edit(w http.ResponseWriter, r *http.Request) {
var body model.SysRole
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.RoleID == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查是否管理员角色
if body.RoleID == "1" {
ctx.JSON(w, 200, result.ErrMsg("Operation of administrator role is not allowed"))
return
}
// 检查是否存在
role := s.sysRoleService.SelectRoleById(body.RoleID)
if role.RoleID != body.RoleID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!"))
return
}
// 判断角色名称是否唯一
uniqueRoleName := s.sysRoleService.CheckUniqueRoleName(body.RoleName, body.RoleID)
if !uniqueRoleName {
msg := fmt.Sprintf("[%s] Role name already exists", body.RoleName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
// 判断角色键值是否唯一
uniqueRoleKey := s.sysRoleService.CheckUniqueRoleKey(body.RoleKey, body.RoleID)
if !uniqueRoleKey {
msg := fmt.Sprintf("[%s] The role key value already exists", body.RoleName)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.UpdateBy = ctx.LoginUserToUserName(r)
rows := s.sysRoleService.UpdateRole(body)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 角色信息删除
//
// DELETE /:roleIds
func (s *SysRoleApi) Remove(w http.ResponseWriter, r *http.Request) {
roleIds := ctx.Param(r, "roleIds")
if roleIds == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 处理字符转id数组后去重
ids := strings.Split(roleIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
ctx.JSON(w, 200, result.Err(nil))
return
}
// 检查是否管理员角色
for _, id := range uniqueIDs {
if id == "1" {
ctx.JSON(w, 200, result.ErrMsg("Operation of administrator role is not allowed"))
return
}
}
rows, err := s.sysRoleService.DeleteRoleByIds(uniqueIDs)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
msg := fmt.Sprintf("Successfully deleted: %d", rows)
ctx.JSON(w, 200, result.OkMsg(msg))
}
// 角色状态变更
//
// PUT /changeStatus
func (s *SysRoleApi) Status(w http.ResponseWriter, r *http.Request) {
var body struct {
// 角色ID
RoleID string `json:"roleId" binding:"required"`
// 状态
Status string `json:"status" binding:"required"`
}
err := ctx.ShouldBindJSON(r, &body)
if err != nil {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查是否管理员角色
if body.RoleID == "1" {
ctx.JSON(w, 200, result.ErrMsg("Operation of administrator role is not allowed"))
return
}
// 检查是否存在
role := s.sysRoleService.SelectRoleById(body.RoleID)
if role.RoleID != body.RoleID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!"))
return
}
// 与旧值相等不变更
if role.Status == body.Status {
ctx.JSON(w, 200, result.ErrMsg("Change status equals old value!"))
return
}
// 更新状态不刷新缓存
userName := ctx.LoginUserToUserName(r)
SysRoleApi := model.SysRole{
RoleID: body.RoleID,
Status: body.Status,
UpdateBy: userName,
}
rows := s.sysRoleService.UpdateRole(SysRoleApi)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 角色分配用户列表
//
// GET /authUser/allocatedList
func (s *SysRoleApi) AuthUserAllocatedList(w http.ResponseWriter, r *http.Request) {
querys := ctx.QueryMap(r)
roleId, ok := querys["roleId"]
if !ok || roleId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查是否存在
role := s.sysRoleService.SelectRoleById(roleId.(string))
if role.RoleID != roleId {
ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!"))
return
}
data := s.sysUserService.SelectAllocatedPage(querys)
ctx.JSON(w, 200, result.Ok(data))
}
// 角色分配选择授权
//
// PUT /authUser/checked
func (s *SysRoleApi) AuthUserChecked(w http.ResponseWriter, r *http.Request) {
var body struct {
// 角色ID
RoleID string `json:"roleId" binding:"required"`
// 用户ID组
UserIDs string `json:"userIds" binding:"required"`
// 选择操作 添加true 取消false
Checked bool `json:"checked"`
}
err := ctx.ShouldBindJSON(r, &body)
if err != nil {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 处理字符转id数组后去重
ids := strings.Split(body.UserIDs, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
ctx.JSON(w, 200, result.Err(nil))
return
}
// 检查是否存在
role := s.sysRoleService.SelectRoleById(body.RoleID)
if role.RoleID != body.RoleID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!"))
return
}
var rows int64
if body.Checked {
rows = s.sysRoleService.InsertAuthUsers(body.RoleID, uniqueIDs)
} else {
rows = s.sysRoleService.DeleteAuthUsers(body.RoleID, uniqueIDs)
}
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}

View File

@@ -1,38 +0,0 @@
package model
// SysRole 角色对象 sys_role
type SysRole struct {
// 角色ID
RoleID string `json:"roleId"`
// 角色名称
RoleName string `json:"roleName" binding:"required"`
// 角色键值
RoleKey string `json:"roleKey" binding:"required"`
// 显示顺序
RoleSort int `json:"roleSort"`
// 菜单树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示
MenuCheckStrictly string `json:"menuCheckStrictly"`
// 部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示
DeptCheckStrictly string `json:"deptCheckStrictly"`
// 角色状态0停用 1正常
Status string `json:"status"`
// 删除标志0代表存在 1代表删除
DelFlag string `json:"delFlag"`
// 创建者
CreateBy string `json:"createBy"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 更新者
UpdateBy string `json:"updateBy"`
// 更新时间
UpdateTime int64 `json:"updateTime"`
// 备注
Remark string `json:"remark"`
// ====== 非数据库字段属性 ======
// 菜单组
MenuIds []string `json:"menuIds,omitempty"`
// 部门组(数据权限)
DeptIds []string `json:"deptIds,omitempty"`
}

View File

@@ -1,362 +0,0 @@
package service
import (
"fmt"
"strings"
"time"
"nms_cxy/features/sys_role/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/date"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysRole 结构体
var NewRepoSysRole = &RepoSysRole{
selectSql: `select distinct
r.role_id, r.role_name, r.role_key, r.role_sort, r.menu_check_strictly,
r.dept_check_strictly, r.status, r.del_flag, r.create_time, r.remark
from sys_role r
left join sys_user_role ur on ur.role_id = r.role_id
left join user u on u.id = ur.user_id`,
resultMap: map[string]string{
"role_id": "RoleID",
"role_name": "RoleName",
"role_key": "RoleKey",
"role_sort": "RoleSort",
"menu_check_strictly": "MenuCheckStrictly",
"dept_check_strictly": "DeptCheckStrictly",
"status": "Status",
"del_flag": "DelFlag",
"create_by": "CreateBy",
"create_time": "CreateTime",
"update_by": "UpdateBy",
"update_time": "UpdateTime",
"remark": "Remark",
},
}
// RepoSysRole 角色表 数据层处理
type RepoSysRole struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoSysRole) convertResultRows(rows []map[string]any) []model.SysRole {
arr := make([]model.SysRole, 0)
for _, row := range rows {
sysRole := model.SysRole{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&sysRole, keyMapper, value)
}
}
arr = append(arr, sysRole)
}
return arr
}
// SelectRolePage 根据条件分页查询角色数据
func (r *RepoSysRole) SelectRolePage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["roleId"]; ok && v != "" {
conditions = append(conditions, "r.role_id = ?")
params = append(params, v)
}
if v, ok := query["roleName"]; ok && v != "" {
conditions = append(conditions, "r.role_name like concat('%', concat(?, '%'))")
params = append(params, v)
}
if v, ok := query["roleKey"]; ok && v != "" {
conditions = append(conditions, "r.role_key like concat('%', concat(?, '%'))")
params = append(params, v)
}
if v, ok := query["status"]; ok && v != "" {
conditions = append(conditions, "r.status = ?")
params = append(params, v)
}
beginTime, ok := query["beginTime"]
if !ok {
beginTime, ok = query["params[beginTime]"]
}
if ok && beginTime != "" {
conditions = append(conditions, "r.create_time >= ?")
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
params = append(params, beginDate.UnixMilli())
}
endTime, ok := query["endTime"]
if !ok {
endTime, ok = query["params[endTime]"]
}
if ok && endTime != "" {
conditions = append(conditions, "r.create_time <= ?")
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
params = append(params, endDate.UnixMilli())
}
// 构建查询条件语句
whereSql := " where r.del_flag = '0' "
if len(conditions) > 0 {
whereSql += " and " + strings.Join(conditions, " and ")
}
// 查询数量 长度为0直接返回
totalSql := `select count(distinct r.role_id) as 'total' from sys_role r
left join sys_user_role ur on ur.role_id = r.role_id
left join user u on u.id = ur.user_id`
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return map[string]any{
"total": total,
"rows": []model.SysRole{},
}
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " order by r.role_sort asc limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 查询数据
querySql := r.selectSql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
rows := r.convertResultRows(results)
return map[string]any{
"total": total,
"rows": rows,
}
}
// SelectRoleList 根据条件查询角色数据
func (r *RepoSysRole) SelectRoleList(sysRole model.SysRole) []model.SysRole {
// 查询条件拼接
var conditions []string
var params []any
if sysRole.RoleID != "" {
conditions = append(conditions, "r.role_id = ?")
params = append(params, sysRole.RoleID)
}
if sysRole.RoleKey != "" {
conditions = append(conditions, "r.role_key like concat('%', concat(?, '%'))")
params = append(params, sysRole.RoleKey)
}
if sysRole.RoleName != "" {
conditions = append(conditions, "r.role_name like concat('%', concat(?, '%'))")
params = append(params, sysRole.RoleName)
}
if sysRole.Status != "" {
conditions = append(conditions, "r.status = ?")
params = append(params, sysRole.Status)
}
// 构建查询条件语句
whereSql := " where r.del_flag = '0' "
if len(conditions) > 0 {
whereSql += " and " + strings.Join(conditions, " and ")
}
// 查询数据
orderSql := " order by r.role_sort"
querySql := r.selectSql + whereSql + orderSql
rows, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysRole{}
}
return r.convertResultRows(rows)
}
// SelectRoleListByUserId 根据用户ID获取角色选择框列表
func (r *RepoSysRole) SelectRoleListByUserId(userId string) []model.SysRole {
querySql := r.selectSql + " where r.del_flag = '0' and ur.user_id = ?"
results, err := datasource.RawDB("", querySql, []any{userId})
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysRole{}
}
return r.convertResultRows(results)
}
// SelectRoleByIds 通过角色ID查询角色
func (r *RepoSysRole) SelectRoleByIds(roleIds []string) []model.SysRole {
placeholder := datasource.KeyPlaceholderByQuery(len(roleIds))
querySql := r.selectSql + " where r.role_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(roleIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
log.Errorf("query err => %v", err)
return []model.SysRole{}
}
// 转换实体
return r.convertResultRows(results)
}
// UpdateRole 修改角色信息
func (r *RepoSysRole) UpdateRole(sysRole model.SysRole) int64 {
// 参数拼接
params := make(map[string]any)
if sysRole.RoleName != "" {
params["role_name"] = sysRole.RoleName
}
if sysRole.RoleKey != "" {
params["role_key"] = sysRole.RoleKey
}
if sysRole.RoleSort > 0 {
params["role_sort"] = sysRole.RoleSort
}
if sysRole.MenuCheckStrictly != "" {
params["menu_check_strictly"] = sysRole.MenuCheckStrictly
}
if sysRole.DeptCheckStrictly != "" {
params["dept_check_strictly"] = sysRole.DeptCheckStrictly
}
if sysRole.Status != "" {
params["status"] = sysRole.Status
}
if sysRole.Remark != "" {
params["remark"] = sysRole.Remark
}
if sysRole.UpdateBy != "" {
params["update_by"] = sysRole.UpdateBy
params["update_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, values := datasource.KeyValueByUpdate(params)
sql := "update sys_role set " + strings.Join(keys, ",") + " where role_id = ?"
// 执行更新
values = append(values, sysRole.RoleID)
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}
// InsertRole 新增角色信息
func (r *RepoSysRole) InsertRole(sysRole model.SysRole) string {
// 参数拼接
params := make(map[string]any)
if sysRole.RoleID != "" {
params["role_id"] = sysRole.RoleID
}
if sysRole.RoleName != "" {
params["role_name"] = sysRole.RoleName
}
if sysRole.RoleKey != "" {
params["role_key"] = sysRole.RoleKey
}
if sysRole.RoleSort > 0 {
params["role_sort"] = sysRole.RoleSort
}
if sysRole.MenuCheckStrictly != "" {
params["menu_check_strictly"] = sysRole.MenuCheckStrictly
}
if sysRole.DeptCheckStrictly != "" {
params["dept_check_strictly"] = sysRole.DeptCheckStrictly
}
if sysRole.Status != "" {
params["status"] = sysRole.Status
}
if sysRole.Remark != "" {
params["remark"] = sysRole.Remark
}
if sysRole.CreateBy != "" {
params["create_by"] = sysRole.CreateBy
params["create_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
sql := "insert into sys_role (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
// 执行插入
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
return fmt.Sprint(insertId)
}
// DeleteRoleByIds 批量删除角色信息
func (r *RepoSysRole) DeleteRoleByIds(roleIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(roleIds))
sql := "update sys_role set del_flag = '1' where role_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(roleIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// CheckUniqueRole 校验角色是否唯一
func (r *RepoSysRole) CheckUniqueRole(sysRole model.SysRole) string {
// 查询条件拼接
var conditions []string
var params []any
if sysRole.RoleName != "" {
conditions = append(conditions, "r.role_name = ?")
params = append(params, sysRole.RoleName)
}
if sysRole.RoleKey != "" {
conditions = append(conditions, "r.role_key = ?")
params = append(params, sysRole.RoleKey)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select role_id as 'str' from sys_role r " + whereSql + " and r.del_flag = '0' limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}

View File

@@ -1,165 +0,0 @@
package service
import (
"errors"
"fmt"
"nms_cxy/features/sys_role/model"
sysrolemenu "nms_cxy/features/sys_role_menu"
sysuserrole "nms_cxy/features/sys_user_role"
)
// 实例化服务层 ServiceSysRole 结构体
var NewServiceSysRole = &ServiceSysRole{
sysRoleRepository: NewRepoSysRole,
sysUserRoleRepository: sysuserrole.NewRepoSysUserRole,
sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu,
}
// ServiceSysRole 角色 服务层处理
type ServiceSysRole struct {
// 角色服务
sysRoleRepository *RepoSysRole
// 用户与角色关联服务
sysUserRoleRepository *sysuserrole.RepoSysUserRole
// 角色与菜单关联服务
sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu
}
// SelectRolePage 根据条件分页查询角色数据
func (r *ServiceSysRole) SelectRolePage(query map[string]any) map[string]any {
return r.sysRoleRepository.SelectRolePage(query)
}
// SelectRoleList 根据条件查询角色数据
func (r *ServiceSysRole) SelectRoleList(sysRole model.SysRole) []model.SysRole {
return r.sysRoleRepository.SelectRoleList(sysRole)
}
// SelectRoleListByUserId 根据用户ID获取角色选择框列表
func (r *ServiceSysRole) SelectRoleListByUserId(userId string) []model.SysRole {
return r.sysRoleRepository.SelectRoleListByUserId(userId)
}
// SelectRoleById 通过角色ID查询角色
func (r *ServiceSysRole) SelectRoleById(roleId string) model.SysRole {
if roleId == "" {
return model.SysRole{}
}
posts := r.sysRoleRepository.SelectRoleByIds([]string{roleId})
if len(posts) > 0 {
return posts[0]
}
return model.SysRole{}
}
// UpdateRole 修改角色信息
func (r *ServiceSysRole) UpdateRole(sysRole model.SysRole) int64 {
rows := r.sysRoleRepository.UpdateRole(sysRole)
if rows > 0 {
// 删除角色与菜单关联
r.sysRoleMenuRepository.DeleteRoleMenu([]string{sysRole.RoleID})
if len(sysRole.MenuIds) > 0 {
r.insertRoleMenu(sysRole.RoleID, sysRole.MenuIds)
}
}
return rows
}
// InsertRole 新增角色信息
func (r *ServiceSysRole) InsertRole(sysRole model.SysRole) string {
insertId := r.sysRoleRepository.InsertRole(sysRole)
if insertId != "" && len(sysRole.MenuIds) > 0 {
r.insertRoleMenu(insertId, sysRole.MenuIds)
}
return insertId
}
// insertRoleMenu 新增角色菜单信息
func (r *ServiceSysRole) insertRoleMenu(roleId string, menuIds []string) int64 {
if roleId == "" || len(menuIds) <= 0 {
return 0
}
sysRoleMenus := []sysrolemenu.SysRoleMenu{}
for _, menuId := range menuIds {
if menuId == "" {
continue
}
sysRoleMenus = append(sysRoleMenus, sysrolemenu.NewSysRoleMenu(roleId, menuId))
}
return r.sysRoleMenuRepository.BatchRoleMenu(sysRoleMenus)
}
// DeleteRoleByIds 批量删除角色信息
func (r *ServiceSysRole) DeleteRoleByIds(roleIds []string) (int64, error) {
// 检查是否存在
roles := r.sysRoleRepository.SelectRoleByIds(roleIds)
if len(roles) <= 0 {
return 0, errors.New("no permission to access role data")
}
for _, role := range roles {
// 检查是否为已删除
if role.DelFlag == "1" {
return 0, errors.New(role.RoleID + " The character information has been deleted")
}
// 检查分配用户
userCount := r.sysUserRoleRepository.CountUserRoleByRoleId(role.RoleID)
if userCount > 0 {
msg := fmt.Sprintf("[%s] has been assigned to a user and cannot be deleted", role.RoleName)
return 0, errors.New(msg)
}
}
if len(roles) == len(roleIds) {
// 删除角色与菜单关联
r.sysRoleMenuRepository.DeleteRoleMenu(roleIds)
rows := r.sysRoleRepository.DeleteRoleByIds(roleIds)
return rows, nil
}
return 0, errors.New("failed to delete role information")
}
// CheckUniqueRoleName 校验角色名称是否唯一
func (r *ServiceSysRole) CheckUniqueRoleName(roleName, roleId string) bool {
uniqueId := r.sysRoleRepository.CheckUniqueRole(model.SysRole{
RoleName: roleName,
})
if uniqueId == roleId {
return true
}
return uniqueId == ""
}
// CheckUniqueRoleKey 校验角色权限是否唯一
func (r *ServiceSysRole) CheckUniqueRoleKey(roleKey, roleId string) bool {
uniqueId := r.sysRoleRepository.CheckUniqueRole(model.SysRole{
RoleKey: roleKey,
})
if uniqueId == roleId {
return true
}
return uniqueId == ""
}
// DeleteAuthUsers 批量取消授权用户角色
func (r *ServiceSysRole) DeleteAuthUsers(roleId string, userIds []string) int64 {
return r.sysUserRoleRepository.DeleteUserRoleByRoleId(roleId, userIds)
}
// InsertAuthUsers 批量新增授权用户角色
func (r *ServiceSysRole) InsertAuthUsers(roleId string, userIds []string) int64 {
if roleId == "" || len(userIds) <= 0 {
return 0
}
sysUserRoles := []sysuserrole.SysUserRole{}
for _, userId := range userIds {
if userId == "" {
continue
}
sysUserRoles = append(sysUserRoles, sysuserrole.NewSysUserRole(userId, roleId))
}
return r.sysUserRoleRepository.BatchUserRole(sysUserRoles)
}

View File

@@ -1,15 +0,0 @@
package sysrolemenu
// SysRoleMenu 角色和菜单关联对象 sys_role_menu
type SysRoleMenu struct {
RoleID string `json:"roleId"` // 角色ID
MenuID string `json:"menuId"` // 菜单ID
}
// NewSysRoleMenu 创建角色和菜单关联对象的构造函数
func NewSysRoleMenu(roleID string, menuID string) SysRoleMenu {
return SysRoleMenu{
RoleID: roleID,
MenuID: menuID,
}
}

View File

@@ -1,86 +0,0 @@
package sysrolemenu
import (
"fmt"
"strings"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysRoleMenu 结构体
var NewRepoSysRoleMenu = &RepoSysRoleMenu{}
// RepoSysRoleMenu 角色与菜单关联表 数据层处理
type RepoSysRoleMenu struct{}
// CheckMenuExistRole 查询菜单分配给角色使用数量
func (r *RepoSysRoleMenu) CheckMenuExistRole(menuId string) int64 {
querySql := "select count(1) as 'total' from sys_role_menu where menu_id = ?"
results, err := datasource.RawDB("", querySql, []any{menuId})
if err != nil {
log.Errorf("query err => %v", err)
return 0
}
if len(results) > 0 {
return parse.Number(results[0]["total"])
}
return 0
}
// DeleteRoleMenu 批量删除角色和菜单关联
func (r *RepoSysRoleMenu) DeleteRoleMenu(roleIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(roleIds))
sql := "delete from sys_role_menu where role_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(roleIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// DeleteMenuRole 批量删除菜单和角色关联
func (r *RepoSysRoleMenu) DeleteMenuRole(menuIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(menuIds))
sql := "delete from sys_role_menu where menu_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(menuIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// BatchRoleMenu 批量新增角色菜单信息
func (r *RepoSysRoleMenu) BatchRoleMenu(sysRoleMenus []SysRoleMenu) int64 {
keyValues := make([]string, 0)
for _, item := range sysRoleMenus {
keyValues = append(keyValues, fmt.Sprintf("(%s,%s)", item.RoleID, item.MenuID))
}
sql := "insert into sys_role_menu(role_id, menu_id) values " + strings.Join(keyValues, ",")
results, err := datasource.ExecDB("", sql, nil)
if err != nil {
log.Errorf("insert err => %v", err)
return 0
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return 0
}
return insertId
}

View File

@@ -1,323 +0,0 @@
package sysuser
import (
"fmt"
"net/http"
"strings"
sysRoleModel "nms_cxy/features/sys_role/model"
sysRoleService "nms_cxy/features/sys_role/service"
sysUserModel "nms_cxy/features/sys_user/model"
"nms_cxy/features/sys_user/service"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/midware"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
srcConfig "nms_cxy/src/framework/config"
)
// 用户接口添加到路由
func Routers() []services.RouterItem {
// 实例化控制层 SysUserApi 结构体
var apis = &SysUserApi{
sysUserService: service.NewServiceSysUser,
sysRoleService: sysRoleService.NewServiceSysRole,
}
rs := [...]services.RouterItem{
{
Method: "GET",
Pattern: "/users",
Handler: apis.List,
Middleware: midware.Authorize(nil),
},
{
Method: "GET",
Pattern: "/user/{userId}",
Handler: apis.Info,
Middleware: midware.Authorize(nil),
},
{
Method: "POST",
Pattern: "/user",
Handler: apis.Add,
Middleware: midware.Authorize(nil),
},
{
Method: "PUT",
Pattern: "/user",
Handler: apis.Edit,
Middleware: midware.Authorize(nil),
},
{
Method: "DELETE",
Pattern: "/user/{userIds}",
Handler: apis.Remove,
Middleware: midware.Authorize(nil),
},
// 添加更多的 Router 对象...
}
// 生成两组前缀路由
rsPrefix := []services.RouterItem{}
for _, v := range rs {
path := "/userManage/{apiVersion}" + v.Pattern
// 固定前缀
v.Pattern = config.DefaultUriPrefix + path
rsPrefix = append(rsPrefix, v)
// 可配置
v.Pattern = config.UriPrefix + path
rsPrefix = append(rsPrefix, v)
}
return rsPrefix
}
// // 实例化控制层 SysUserApi 结构体
// var NewSysUser = &SysUserApi{
// sysUserService: service.NewSysUserImpl,
// sysRoleService: service.NewSysRoleImpl,
// sysPostService: service.NewSysPostImpl,
// sysDictDataService: service.NewSysDictDataImpl,
// }
// 用户信息
//
// PATH /system/user
type SysUserApi struct {
// 用户服务
sysUserService *service.ServiceSysUser
// 角色服务
sysRoleService *sysRoleService.ServiceSysRole
}
// 用户信息列表
//
// GET /list
func (s *SysUserApi) List(w http.ResponseWriter, r *http.Request) {
querys := ctx.QueryMap(r)
data := s.sysUserService.SelectUserPage(querys)
ctx.JSON(w, 200, result.Ok(data))
}
// 用户信息详情
//
// GET /:userId
func (s *SysUserApi) Info(w http.ResponseWriter, r *http.Request) {
userId := ctx.Param(r, "userId")
if userId == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 查询系统角色列表
roles := s.sysRoleService.SelectRoleList(sysRoleModel.SysRole{})
// 不是系统指定管理员需要排除其角色
if !srcConfig.IsAdmin(userId) {
rolesFilter := make([]sysRoleModel.SysRole, 0)
for _, r := range roles {
if r.RoleID != "1" {
rolesFilter = append(rolesFilter, r)
}
}
roles = rolesFilter
}
// 新增用户时用户ID为0
if userId == "0" {
ctx.JSON(w, 200, result.OkData(map[string]any{
"user": map[string]any{},
"roleIds": []string{},
"roles": roles,
}))
return
}
// 检查用户是否存在
user := s.sysUserService.SelectUserById(userId)
if user.Id != userId {
ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!"))
return
}
// 角色ID组
roleIds := make([]string, 0)
for _, r := range user.Roles {
roleIds = append(roleIds, r.RoleID)
}
ctx.JSON(w, 200, result.OkData(map[string]any{
"user": user,
"roleIds": roleIds,
"roles": roles,
}))
}
// 用户信息新增
//
// POST /
func (s *SysUserApi) Add(w http.ResponseWriter, r *http.Request) {
var body sysUserModel.SysUser
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.Id != "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查用户登录账号是否唯一
uniqueUserName := s.sysUserService.CheckUniqueUserName(body.AccountId, "")
if !uniqueUserName {
msg := fmt.Sprintf("[%s] Login account already exists", body.AccountId)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
insertId := s.sysUserService.InsertUser(body)
if insertId != "" {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 用户信息修改
//
// POST /
func (s *SysUserApi) Edit(w http.ResponseWriter, r *http.Request) {
var body sysUserModel.SysUser
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.Id == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查是否管理员用户
// if srcConfig.IsAdmin(body.Id) {
// ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员用户"))
// return
// }
user := s.sysUserService.SelectUserById(body.Id)
if user.Id != body.Id {
ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!"))
return
}
// 检查用户登录账号是否唯一
uniqueUserName := s.sysUserService.CheckUniqueUserName(body.AccountId, body.Id)
if !uniqueUserName {
msg := fmt.Sprintf("[%s] Login account already exists", body.AccountId)
ctx.JSON(w, 200, result.ErrMsg(msg))
return
}
body.AccountId = "" // 忽略修改登录用户名称
// body.Password = "" // 忽略修改密码
rows := s.sysUserService.UpdateUserAndRolePost(body)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 用户信息删除
//
// DELETE /:userIds
func (s *SysUserApi) Remove(w http.ResponseWriter, r *http.Request) {
userIds := ctx.Param(r, "userIds")
if userIds == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 处理字符转id数组后去重
ids := strings.Split(userIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
ctx.JSON(w, 200, result.Err(nil))
return
}
rows, err := s.sysUserService.DeleteUserByIds(uniqueIDs)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
msg := fmt.Sprintf("Successfully deleted: %d", rows)
ctx.JSON(w, 200, result.OkMsg(msg))
}
// 用户重置密码
//
// PUT /resetPwd
func (s *SysUserApi) ResetPwd(w http.ResponseWriter, r *http.Request) {
var body struct {
UserID string `json:"userId" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := ctx.ShouldBindJSON(r, &body); err != nil {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查是否管理员用户
if srcConfig.IsAdmin(body.UserID) {
ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!"))
return
}
user := s.sysUserService.SelectUserById(body.UserID)
if user.Id != body.UserID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!"))
return
}
SysUserApi := sysUserModel.SysUser{
Id: body.UserID,
Password: body.Password,
}
rows := s.sysUserService.UpdateUser(SysUserApi)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}
// 用户状态修改
//
// PUT /changeStatus
func (s *SysUserApi) Status(w http.ResponseWriter, r *http.Request) {
var body struct {
UserID string `json:"userId" binding:"required"`
Status string `json:"status" binding:"required"`
}
if err := ctx.ShouldBindJSON(r, &body); err != nil {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
// 检查是否存在
user := s.sysUserService.SelectUserById(body.UserID)
if user.Id != body.UserID {
ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!"))
return
}
// 与旧值相等不变更
if user.Status == body.Status {
ctx.JSON(w, 200, result.ErrMsg("Change status equals old value!"))
return
}
SysUserApi := sysUserModel.SysUser{
Id: body.UserID,
Status: body.Status,
}
rows := s.sysUserService.UpdateUser(SysUserApi)
if rows > 0 {
ctx.JSON(w, 200, result.Ok(nil))
return
}
ctx.JSON(w, 200, result.Err(nil))
}

View File

@@ -1,42 +0,0 @@
package model
import "nms_cxy/features/sys_role/model"
type SysUser struct {
Id string `json:"id" xorm:"pk 'id' autoincr"`
AccountId string `json:"accountId" xorm:"account_id"`
Name string `json:"name" xorm:"name"`
Sn string `json:"sn"`
Gender string `json:"gender"`
Description string `json:"description"`
TelephoneNumber string `json:"telephoneNumber" xorm:"telephone_number"`
Mobile string `json:"mobile"`
Email string `json:"email" xorm:"email"`
StartTime string `json:"startTime" xorm:"start_time"`
EndTime string `json:"endTime" xorm:"end_time"`
IdCardNumber string `json:"idCardNumber"`
EmployeeNumber string `json:"employeeNumber"`
Organize string `json:"organize"`
EmployeeType string `json:"employeeType"`
SupporterCorpName string `json:"supporterCorpName"`
RealName string `json:"realName" xorm:"real_name"`
Password string `json:"password" xorm:"-"`
PasswordSha512 string `json:"-" xorm:"-"`
ChangePasswordFlag int `json:"changePasswordFlag"`
PasswordExpiration string `json:"passwordExpiration" xorm:"password_expiration"`
Status string `json:"status"`
UserExpiration string `json:"userExpiration" xorm:"user_expiration"`
GroupName string `json:"groupName" xorm:"group_name"`
Profile string `json:"-" xorm:"profile"`
Phone string `json:"phone" xorm:"phone"`
CreateTime string `json:"createTime" xorm:"create_time"`
UpdateTime string `json:"updateTime" xorm:"update_time"`
Unit string `json:"unit" xorm:"unit"`
// 角色对象组
Roles []model.SysRole `json:"roles"`
// 角色ID - 参数提交绑定
RoleID string `json:"roleId,omitempty"`
// 角色组 - 参数提交绑定
RoleIDs []string `json:"roleIds,omitempty"`
}

View File

@@ -1,578 +0,0 @@
package service
import (
"fmt"
"strings"
"time"
sysRoleModel "nms_cxy/features/sys_role/model"
sysUserModel "nms_cxy/features/sys_user/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/date"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
"nms_cxy/src/framework/utils/crypto"
)
// 实例化数据层 RepoSysUser 结构体
var NewRepoSysUser = &RepoSysUser{
selectSql: `select u.id,
u.account_id, u.name, u.sn, u.gender, u.description, u.telephone_number, u.mobile, u.email,
u.start_time, u.end_time, u.id_card_number, u.employee_number,
u.organize, u.employee_type, u.supporter_corp_name, u.real_name, u.password, u.password_sha512,
u.change_password_flag,u.password_expiration, u.status, u.user_expiration, u.group_name,
u.profile, u.phone, u.create_time, u.update_time, u.unit,
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
from user u
left join sys_user_role ur on u.id = ur.user_id
left join sys_role r on r.role_id = ur.role_id`,
sysUserMap: map[string]string{
"id": "Id",
"account_id": "AccountId",
"name": "Name",
"sn": "Sn",
"gender": "Gender",
"description": "Description",
"telephone_number": "TelephoneNumber",
"mobile": "Mobile",
"email": "Email",
"start_time": "StartTime",
"end_time": "EndTime",
"id_card_number": "IdCardNumber",
"employee_number": "EmployeeNumber",
"organize": "Organize",
"employee_type": "EmployeeType",
"supporter_corp_name": "SupporterCorpName",
"real_name": "RealName",
"password": "Password",
"password_sha512": "PasswordSha512",
"change_password_flag": "ChangePasswordFlag",
"password_expiration": "PasswordExpiration",
"status": "Status",
"user_expiration": "UserExpiration",
"group_name": "GroupName",
"profile": "Profile",
"phone": "Phone",
"create_time": "CreateTime",
"update_time": "UpdateTime",
"unit": "Unit",
},
sysRoleMap: map[string]string{
"role_id": "RoleID",
"role_name": "RoleName",
"role_key": "RoleKey",
"role_sort": "RoleSort",
"data_scope": "DataScope",
"role_status": "Status",
},
}
// RepoSysUser 用户表 数据层处理
type RepoSysUser struct {
// 查询视图对象SQL
selectSql string
// 用户信息实体映射
sysUserMap map[string]string
// 用户角色实体映射 一对多
sysRoleMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoSysUser) convertResultRows(rows []map[string]any) []sysUserModel.SysUser {
arr := make([]sysUserModel.SysUser, 0)
for _, row := range rows {
sysUser := sysUserModel.SysUser{}
sysRole := sysRoleModel.SysRole{}
sysUser.Roles = []sysRoleModel.SysRole{}
for key, value := range row {
if keyMapper, ok := r.sysUserMap[key]; ok {
datasource.SetFieldValue(&sysUser, keyMapper, value)
}
if keyMapper, ok := r.sysRoleMap[key]; ok {
datasource.SetFieldValue(&sysRole, keyMapper, value)
}
}
if sysRole.RoleKey != "" {
sysUser.Roles = append(sysUser.Roles, sysRole)
}
one := true
for i, a := range arr {
if a.Id == sysUser.Id {
arrUser := &arr[i]
arrUser.Roles = append(arrUser.Roles, sysUser.Roles...)
one = false
break
}
}
if one {
arr = append(arr, sysUser)
}
}
return arr
}
// SelectUserPage 根据条件分页查询用户列表
func (r *RepoSysUser) SelectUserPage(query map[string]any) map[string]any {
selectUserSql := `select u.id,
u.account_id, u.name, u.sn, u.gender, u.description, u.telephone_number, u.mobile, u.email,
u.start_time, u.end_time, u.id_card_number, u.employee_number,
u.organize, u.employee_type, u.supporter_corp_name, u.real_name,
u.change_password_flag,u.password_expiration, u.status, u.user_expiration, u.group_name,
u.profile, u.phone, u.create_time, u.update_time, u.unit
from user u`
selectUserTotalSql := `select count(distinct u.id) as 'total' from user u`
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["accountId"]; ok && v != "" {
conditions = append(conditions, "u.account_id = ?")
params = append(params, v)
}
if v, ok := query["name"]; ok && v != "" {
conditions = append(conditions, "u.name concat('%', concat(?, '%'))")
params = append(params, v)
}
if v, ok := query["status"]; ok && v != "" {
conditions = append(conditions, "u.status = ?")
params = append(params, v)
}
if v, ok := query["phonenumber"]; ok && v != "" {
conditions = append(conditions, "u.phonenumber like concat('%', concat(?, '%'))")
params = append(params, v)
}
beginTime, ok := query["beginTime"]
if !ok {
beginTime, ok = query["params[beginTime]"]
}
if ok && beginTime != "" {
conditions = append(conditions, "u.login_date >= ?")
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
params = append(params, beginDate.UnixMilli())
}
endTime, ok := query["endTime"]
if !ok {
endTime, ok = query["params[endTime]"]
}
if ok && endTime != "" {
conditions = append(conditions, "u.login_date <= ?")
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
params = append(params, endDate.UnixMilli())
}
if v, ok := query["deptId"]; ok && v != "" {
conditions = append(conditions, "(u.dept_id = ? or u.dept_id in ( select t.dept_id from sys_dept t where find_in_set(?, ancestors) ))")
params = append(params, v)
params = append(params, v)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数量 长度为0直接返回
totalSql := selectUserTotalSql + whereSql
totalRows, err := datasource.RawDB("", totalSql, params)
if err != nil {
log.Errorf("total err => %v", err)
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return map[string]any{
"total": total,
"rows": []sysUserModel.SysUser{},
}
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 查询数据
querySql := selectUserSql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
rows := r.convertResultRows(results)
return map[string]any{
"total": total,
"rows": rows,
}
}
// SelectAllocatedPage 根据条件分页查询分配用户角色列表
func (r *RepoSysUser) SelectAllocatedPage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["name"]; ok && v != "" {
conditions = append(conditions, "u.name like concat('%', concat(?, '%'))")
params = append(params, v)
}
if v, ok := query["phone"]; ok && v != "" {
conditions = append(conditions, "u.phone like concat('%', concat(?, '%'))")
params = append(params, v)
}
if v, ok := query["status"]; ok && v != "" {
conditions = append(conditions, "u.status = ?")
params = append(params, v)
}
// 分配角色用户
if allocated, ok := query["allocated"]; ok && allocated != "" {
if roleId, ok := query["roleId"]; ok && roleId != "" {
if parse.Boolean(allocated) {
conditions = append(conditions, "r.role_id = ?")
params = append(params, roleId)
} else {
conditions = append(conditions, `(r.role_id != ? or r.role_id IS NULL)
and u.id not in (
select u.id from user u
inner join sys_user_role ur on u.id = ur.user_id
and ur.role_id = ?
)`)
params = append(params, roleId)
params = append(params, roleId)
}
}
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数量 长度为0直接返回
totalSql := `select count(distinct u.id) as 'total' from user u
left join sys_user_role ur on u.id = ur.user_id
left join sys_role r on r.role_id = ur.role_id`
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return map[string]any{
"total": total,
"rows": []sysUserModel.SysUser{},
}
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 查询数据
querySql := `select distinct
u.id, u.account_id, u.name, u.gender, u.email,
u.phone, u.status, u.create_time, u.real_name
from user u
left join sys_user_role ur on u.id = ur.user_id
left join sys_role r on r.role_id = ur.role_id`
querySql = querySql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
rows := r.convertResultRows(results)
return map[string]any{
"total": total,
"rows": rows,
}
}
// SelectUserList 根据条件查询用户列表
func (r *RepoSysUser) SelectUserList(sysUser sysUserModel.SysUser, dataScopeSQL string) []sysUserModel.SysUser {
selectUserSql := `select
u.id, u.account_id, u.name, u.real_name, u.email, u.gender, u.phone, u.create_time, u.status, u.description
from user u`
// 查询条件拼接
var conditions []string
var params []any
if sysUser.AccountId != "" {
conditions = append(conditions, "u.account_id = ?")
params = append(params, sysUser.AccountId)
}
if sysUser.Name != "" {
conditions = append(conditions, "u.name like concat('%', concat(?, '%'))")
params = append(params, sysUser.Name)
}
if sysUser.Status != "" {
conditions = append(conditions, "u.status = ?")
params = append(params, sysUser.Status)
}
if sysUser.Phone != "" {
conditions = append(conditions, "u.phone like concat('%', concat(?, '%'))")
params = append(params, sysUser.Phone)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := selectUserSql + whereSql + dataScopeSQL
rows, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return []sysUserModel.SysUser{}
}
return r.convertResultRows(rows)
}
// SelectUserByIds 通过用户ID查询用户
func (r *RepoSysUser) SelectUserByIds(userIds []string) []sysUserModel.SysUser {
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
querySql := r.selectSql + " where u.id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(userIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
log.Errorf("query err => %v", err)
return []sysUserModel.SysUser{}
}
// 转换实体
return r.convertResultRows(results)
}
// SelectUserByUserName 通过用户登录账号查询用户
func (r *RepoSysUser) SelectUserByUserName(userName string) sysUserModel.SysUser {
querySql := r.selectSql + " where u.name = ?"
results, err := datasource.RawDB("", querySql, []any{userName})
if err != nil {
log.Errorf("query err => %v", err)
return sysUserModel.SysUser{}
}
// 转换实体
rows := r.convertResultRows(results)
if len(rows) > 0 {
return rows[0]
}
return sysUserModel.SysUser{}
}
// InsertUser 新增用户信息
func (r *RepoSysUser) InsertUser(sysUser sysUserModel.SysUser) string {
// 参数拼接
params := make(map[string]any)
if sysUser.AccountId != "" {
params["account_id"] = sysUser.AccountId
}
if sysUser.Name != "" {
params["name"] = sysUser.Name
}
if sysUser.Sn != "" {
params["sn"] = sysUser.Sn
} else {
params["sn"] = ""
}
if sysUser.RealName != "" {
params["real_name"] = sysUser.RealName
} else {
params["real_name"] = ""
}
if sysUser.Gender != "" {
params["gender"] = sysUser.Gender
}
if sysUser.Email != "" {
params["email"] = sysUser.Email
} else {
params["email"] = ""
}
if sysUser.Phone != "" {
params["phone"] = sysUser.Phone
} else {
params["phone"] = ""
}
if sysUser.Unit != "" {
params["unit"] = sysUser.Unit
} else {
params["unit"] = ""
}
if sysUser.Organize != "" {
params["organize"] = sysUser.Organize
}
if sysUser.Password != "" {
password := crypto.BcryptHash(sysUser.Password)
params["password"] = password
}
if sysUser.Status != "" {
params["status"] = sysUser.Status
}
if sysUser.PasswordExpiration != "" {
params["password_expiration"] = sysUser.PasswordExpiration
}
if sysUser.UserExpiration != "" {
params["user_expiration"] = sysUser.UserExpiration
}
if sysUser.GroupName != "" {
params["group_name"] = sysUser.GroupName
}
params["create_time"] = time.Now()
// 构建执行语句
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
sql := "insert into user (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
// 执行插入
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
insertId, err := results.LastInsertId()
if err != nil {
log.Errorf("insert row : %v", err.Error())
return ""
}
return fmt.Sprint(insertId)
}
// UpdateUser 修改用户信息
func (r *RepoSysUser) UpdateUser(sysUser sysUserModel.SysUser) int64 {
// 参数拼接
params := make(map[string]any)
if sysUser.Name != "" {
params["name"] = sysUser.Name
}
if sysUser.Sn != "" {
params["sn"] = sysUser.Sn
} else {
params["sn"] = ""
}
if sysUser.RealName != "" {
params["real_name"] = sysUser.RealName
} else {
params["real_name"] = ""
}
if sysUser.Gender != "" {
params["gender"] = sysUser.Gender
}
if sysUser.Email != "" {
params["email"] = sysUser.Email
} else {
params["email"] = ""
}
if sysUser.Phone != "" {
params["phone"] = sysUser.Phone
} else {
params["phone"] = ""
}
if sysUser.Unit != "" {
params["unit"] = sysUser.Unit
} else {
params["unit"] = ""
}
if sysUser.Organize != "" {
params["organize"] = sysUser.Organize
}
if sysUser.Password != "" {
password := crypto.BcryptHash(sysUser.Password)
params["password"] = password
}
if sysUser.Status != "" {
params["status"] = sysUser.Status
}
if sysUser.PasswordExpiration != "" {
params["password_expiration"] = sysUser.PasswordExpiration
}
if sysUser.UserExpiration != "" {
params["user_expiration"] = sysUser.UserExpiration
}
if sysUser.GroupName != "" {
params["group_name"] = sysUser.GroupName
}
params["update_time"] = time.Now()
// 构建执行语句
keys, values := datasource.KeyValueByUpdate(params)
sql := "update user set " + strings.Join(keys, ",") + " where id = ?"
// 执行更新
values = append(values, sysUser.Id)
results, err := datasource.ExecDB("", sql, values)
if err != nil {
log.Errorf("update row : %v", err.Error())
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("update err => %v", err)
return 0
}
return affected
}
// DeleteUserByIds 批量删除用户信息
func (r *RepoSysUser) DeleteUserByIds(userIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
sql := "delete from user where id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(userIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// CheckUniqueUser 校验用户信息是否唯一
func (r *RepoSysUser) CheckUniqueUser(sysUser sysUserModel.SysUser) string {
// 查询条件拼接
var conditions []string
var params []any
if sysUser.Name != "" {
conditions = append(conditions, "name = ?")
params = append(params, sysUser.Name)
}
if sysUser.AccountId != "" {
conditions = append(conditions, "account_id = ?")
params = append(params, sysUser.AccountId)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select id as 'str' from user " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err %v", err)
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}

View File

@@ -1,150 +0,0 @@
package service
import (
"errors"
"fmt"
sysUserModel "nms_cxy/features/sys_user/model"
sysuserrole "nms_cxy/features/sys_user_role"
)
// 实例化服务层 ServiceSysUser 结构体
var NewServiceSysUser = &ServiceSysUser{
sysUserRepository: NewRepoSysUser,
sysUserRoleRepository: sysuserrole.NewRepoSysUserRole,
}
// ServiceSysUser 用户 服务层处理
type ServiceSysUser struct {
// 用户服务
sysUserRepository *RepoSysUser
// 用户与角色服务
sysUserRoleRepository *sysuserrole.RepoSysUserRole
}
// SelectUserPage 根据条件分页查询用户列表
func (r *ServiceSysUser) SelectUserPage(query map[string]any) map[string]any {
return r.sysUserRepository.SelectUserPage(query)
}
// SelectUserList 根据条件查询用户列表
func (r *ServiceSysUser) SelectUserList(sysUser sysUserModel.SysUser) []sysUserModel.SysUser {
return []sysUserModel.SysUser{}
}
// SelectAllocatedPage 根据条件分页查询分配用户角色列表
func (r *ServiceSysUser) SelectAllocatedPage(query map[string]any) map[string]any {
return r.sysUserRepository.SelectAllocatedPage(query)
}
// SelectUserByUserName 通过用户名查询用户
func (r *ServiceSysUser) SelectUserByUserName(userName string) sysUserModel.SysUser {
return r.sysUserRepository.SelectUserByUserName(userName)
}
// SelectUserById 通过用户ID查询用户
func (r *ServiceSysUser) SelectUserById(userId string) sysUserModel.SysUser {
if userId == "" {
return sysUserModel.SysUser{}
}
users := r.sysUserRepository.SelectUserByIds([]string{userId})
if len(users) > 0 {
return users[0]
}
return sysUserModel.SysUser{}
}
// InsertUser 新增用户信息
func (r *ServiceSysUser) InsertUser(sysUser sysUserModel.SysUser) string {
// 新增用户信息
insertId := r.sysUserRepository.InsertUser(sysUser)
if insertId != "" {
// 新增用户角色信息
r.insertUserRole(insertId, sysUser.RoleIDs)
}
return insertId
}
// insertUserRole 新增用户角色信息
func (r *ServiceSysUser) insertUserRole(userId string, roleIds []string) int64 {
if userId == "" || len(roleIds) <= 0 {
return 0
}
sysUserRoles := []sysuserrole.SysUserRole{}
for _, roleId := range roleIds {
// 管理员角色禁止操作只能通过配置指定用户ID分配
if roleId == "" || roleId == "1" {
continue
}
sysUserRoles = append(sysUserRoles, sysuserrole.NewSysUserRole(userId, roleId))
}
return r.sysUserRoleRepository.BatchUserRole(sysUserRoles)
}
// UpdateUser 修改用户信息
func (r *ServiceSysUser) UpdateUser(sysUser sysUserModel.SysUser) int64 {
return r.sysUserRepository.UpdateUser(sysUser)
}
// UpdateUserAndRolePost 修改用户信息同时更新角色和岗位
func (r *ServiceSysUser) UpdateUserAndRolePost(sysUser sysUserModel.SysUser) int64 {
userId := fmt.Sprint(sysUser.Id)
// 删除用户与角色关联
r.sysUserRoleRepository.DeleteUserRole([]string{userId})
// 新增用户角色信息
r.insertUserRole(userId, sysUser.RoleIDs)
return r.sysUserRepository.UpdateUser(sysUser)
}
// DeleteUserByIds 批量删除用户信息
func (r *ServiceSysUser) DeleteUserByIds(userIds []string) (int64, error) {
// 检查是否存在
users := r.sysUserRepository.SelectUserByIds(userIds)
if len(users) <= 0 {
return 0, errors.New("no permission to access user data")
}
if len(users) == len(userIds) {
// 删除用户与角色关联
r.sysUserRoleRepository.DeleteUserRole(userIds)
// ... 注意其他userId进行关联的表
// 删除用户
rows := r.sysUserRepository.DeleteUserByIds(userIds)
return rows, nil
}
return 0, errors.New("failed to delete user information")
}
// CheckUniqueUserName 校验用户名称是否唯一
func (r *ServiceSysUser) CheckUniqueUserName(accountId, userId string) bool {
uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{
AccountId: accountId,
})
if uniqueId == userId {
return true
}
return uniqueId == ""
}
// CheckUniquePhone 校验手机号码是否唯一
func (r *ServiceSysUser) CheckUniquePhone(phonenumber, userId string) bool {
uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{
Phone: phonenumber,
})
if uniqueId == userId {
return true
}
return uniqueId == ""
}
// CheckUniqueEmail 校验email是否唯一
func (r *ServiceSysUser) CheckUniqueEmail(email, userId string) bool {
uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{
Email: email,
})
if uniqueId == userId {
return true
}
return uniqueId == ""
}

View File

@@ -1,15 +0,0 @@
package sysuserrole
// SysUserRole 用户和角色关联对象 sys_user_role
type SysUserRole struct {
UserID string `json:"userId"` // 用户ID
RoleID string `json:"roleId"` // 角色ID
}
// NewSysUserRole 创建用户和角色关联对象的构造函数
func NewSysUserRole(userID string, roleID string) SysUserRole {
return SysUserRole{
UserID: userID,
RoleID: roleID,
}
}

View File

@@ -1,87 +0,0 @@
package sysuserrole
import (
"fmt"
"strings"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoSysUserRole 结构体
var NewRepoSysUserRole = &RepoSysUserRole{}
// RepoSysUserRole 用户与角色关联表 数据层处理
type RepoSysUserRole struct{}
// CountUserRoleByRoleId 通过角色ID查询角色使用数量
func (r *RepoSysUserRole) CountUserRoleByRoleId(roleId string) int64 {
querySql := "select count(1) as total from sys_user_role where role_id = ?"
results, err := datasource.RawDB("", querySql, []any{roleId})
if err != nil {
log.Errorf("query err => %v", err)
return 0
}
if len(results) > 0 {
return parse.Number(results[0]["total"])
}
return 0
}
// BatchUserRole 批量新增用户角色信息
func (r *RepoSysUserRole) BatchUserRole(sysUserRoles []SysUserRole) int64 {
keyValues := make([]string, 0)
for _, item := range sysUserRoles {
keyValues = append(keyValues, fmt.Sprintf("(%s,%s)", item.UserID, item.RoleID))
}
sql := "insert into sys_user_role(user_id, role_id) values " + strings.Join(keyValues, ",")
results, err := datasource.ExecDB("", sql, nil)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// DeleteUserRole 批量删除用户和角色关联
func (r *RepoSysUserRole) DeleteUserRole(userIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
sql := "delete from sys_user_role where user_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(userIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}
// DeleteUserRoleByRoleId 批量取消授权用户角色
func (r *RepoSysUserRole) DeleteUserRoleByRoleId(roleId string, userIds []string) int64 {
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
sql := "delete from sys_user_role where role_id= ? and user_id in (" + placeholder + ")"
parameters := datasource.ConvertIdsSlice(userIds)
parameters = append([]any{roleId}, parameters...)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
affected, err := results.RowsAffected()
if err != nil {
log.Errorf("delete err => %v", err)
return 0
}
return affected
}

View File

@@ -1,339 +0,0 @@
package trace
import (
"fmt"
"net"
"net/http"
"strings"
"time"
"nms_cxy/lib/core/conf"
"nms_cxy/lib/core/utils/ctx"
"nms_cxy/lib/core/vo/result"
"nms_cxy/lib/dborm"
"nms_cxy/lib/log"
"nms_cxy/omc/config"
"nms_cxy/src/framework/utils/cmd"
"nms_cxy/src/framework/utils/ssh"
)
var (
UriTcpdumpTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask"
CustomUriTcpdumpTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" // decode message api
UriTcpdumpPcapDownload = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload"
CustomUriTcpdumpPcapDownload = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" // decode message api
UriTcpdumpNeUPFTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask"
CustomUriTcpdumpNeUPFTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" // decode message api
)
// NeInfo 网元信息
func NeInfo(neType, neId string) (*dborm.NeInfo, error) {
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
return nil, err
}
if neInfo == nil || neInfo.Ip == "" {
return nil, fmt.Errorf("not ne_info or not IP")
}
return neInfo, nil
}
// TcpdumpNeTask 网元发送执行 pcap
func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) {
var body struct {
NeType string `json:"neType"` // 网元类型
NeId string `json:"neId"` // 网元ID
Timeout int `json:"timeout"` // 超时时间
Cmd string `json:"cmd"` // 命令
}
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.NeType == "" || body.NeId == "" || body.Timeout < 5 || body.Cmd == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
neInfo, err := NeInfo(body.NeType, body.NeId)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli())
fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli())
writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件放置弹出code 127
cmdStr := fmt.Sprintf("cd /tmp \nsudo timeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName)
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": cmdStr,
"msg": msg,
"fileName": filePcapName,
}))
}
// TcpdumpPcapDownload 网元抓包pcap文件下载
func TcpdumpPcapDownload(w http.ResponseWriter, r *http.Request) {
var body struct {
NeType string `json:"neType"` // 网元类型
NeId string `json:"neId"` // 网元ID
FileName string `json:"fileName"` // 文件名
}
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.NeType == "" || body.NeId == "" || body.FileName == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
neInfo, err := NeInfo(body.NeType, body.NeId)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
nePath := fmt.Sprintf("/tmp/%s", body.FileName)
localPath := fmt.Sprintf("%s/tcpdump/pcap/%s", conf.Get("ne.omcdir"), body.FileName)
err = ssh.FileSCPNeToLocal(neInfo.Ip, nePath, localPath)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
ctx.FileAttachment(w, r, localPath, body.FileName)
}
// TcpdumpNeUPFTask 网元UPF发送执行 pcap
func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) {
var body struct {
NeType string `json:"neType"` // 网元类型
NeId string `json:"neId"` // 网元ID
Cmd string `json:"cmd"` // 命令
RunType string `json:"runType"` // 执行开始start还是停止stop
}
err := ctx.ShouldBindJSON(r, &body)
if err != nil || body.NeType != "UPF" || body.NeId == "" || body.Cmd == "" {
ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
return
}
neInfo, err := NeInfo(body.NeType, body.NeId)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
// 开始telnet
if body.RunType == "start_telnet" {
// 创建TCP连接
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002))
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
defer conn.Close()
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
cmdStr := fmt.Sprintf("pcap dispatch trace on max 100000 file %s", filePcapName)
fmt.Fprintln(conn, cmdStr)
// 读取内容
time.Sleep(time.Duration(200) * time.Millisecond)
buf := make([]byte, 1024*8)
n, err := conn.Read(buf)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
} else {
str := string(buf[0:n])
s := strings.Index(str, "pcap dispatch trace:")
if s != -1 {
e := strings.Index(str, "\r\nupfd1#")
str = str[s:e]
} else {
str = fmt.Sprintf("Executed, please stop before proceeding %d", n)
}
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": cmdStr,
"msg": str,
"fileName": filePcapName,
}))
}
conn.Close()
return
}
// 停止telnet
if body.RunType == "stop_telnet" {
// 创建TCP连接
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002))
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
defer conn.Close()
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
cmdStr := "pcap dispatch trace off"
fmt.Fprintln(conn, cmdStr)
// 读取内容
time.Sleep(time.Duration(200) * time.Millisecond)
buf := make([]byte, 1024*8)
n, err := conn.Read(buf)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
} else {
str := string(buf[0:n])
s := strings.Index(str, "pcap dispatch trace:")
if s == -1 {
s = strings.Index(str, "Write ")
}
if s != -1 {
e := strings.Index(str, "\r\nupfd1#")
str = str[s:e]
} else {
str = "No stoppable found"
}
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": cmdStr,
"msg": str,
"fileName": filePcapName,
}))
}
conn.Close()
return
}
// 开始 -脚本
if body.RunType == "start2" {
fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
// 复制文件到网元上
err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\omc\\backup\\upf_pcap", "/tmp")
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件放置弹出code 127
cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace on max 100000 file %s' %s ", fileLogName, writeLog)
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
} else {
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": cmdStr,
"msg": msg,
"fileName": filePcapName,
}))
}
return
}
// 停止 -脚本
if body.RunType == "stop2" {
fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
// cmdStr := "cd /tmp \nexpect /tmp/cat.sh "
err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\omc\\backup\\upf_pcap", "/tmp")
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
return
}
writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件放置弹出code 127
cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace off' %s ", writeLog)
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
} else {
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": cmdStr,
"msg": msg,
"fileName": filePcapName,
}))
}
return
}
// 开始-脚本字符串
if body.RunType == "start_str" {
fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\""
writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出避免弹出code 127
capCmdStr := fmt.Sprintf("%s file %s", body.Cmd, filePcapName)
cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog)
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
} else {
s := strings.Index(msg, "pcap dispatch trace:")
if s != -1 {
e := strings.Index(msg, "\r\nupfd1#")
msg = msg[s:e]
} else {
msg = "Executed, please stop before proceeding"
}
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": capCmdStr,
"msg": msg,
"fileName": filePcapName,
}))
}
return
}
// 停止-脚本字符串
if body.RunType == "stop_str" {
fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\""
writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出避免弹出code 127
capCmdStr := body.Cmd
cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog)
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
if err != nil {
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
} else {
s := strings.Index(msg, "pcap dispatch trace:")
if s == -1 {
s = strings.Index(msg, "Write ")
}
if s != -1 {
e := strings.Index(msg, "\r\nupfd1#")
msg = msg[s:e]
} else {
msg = "No stoppable found"
}
ctx.JSON(w, 200, result.OkData(map[string]any{
"cmd": capCmdStr,
"msg": msg,
"fileName": filePcapName,
}))
}
return
}
ctx.JSON(w, 200, result.ErrMsg("runType is start or stop"))
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
package model
// UdmAuthUser UDM鉴权用户
type UdmAuthUser struct {
ID string `json:"id" xorm:"pk 'id' autoincr"`
Imsi string `json:"imsi" xorm:"imsi"` // SIM卡号
Amf string `json:"amf" xorm:"amf"` // ANF
Status string `json:"status" xorm:"status"` // 状态
Ki string `json:"ki" xorm:"ki"` // ki
AlgoIndex string `json:"algoIndex" xorm:"algo_index"` //
Opc string `json:"opc" xorm:"opc"`
NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统
}

View File

@@ -1,29 +0,0 @@
package model
// UdmSubUser UDM签约用户
type UdmSubUser struct {
ID string `json:"id" xorm:"pk 'id' autoincr"`
Msisdn string `json:"msisdn" xorm:"msisdn"` // 相当手机号
Imsi string `json:"imsi" xorm:"imsi"` // SIM卡号
Ambr string `json:"ambr" xorm:"ambr"`
Nssai string `json:"nssai" xorm:"nssai"`
Rat string `json:"rat" xorm:"rat"`
Arfb string `json:"arfb" xorm:"arfb"`
Sar string `json:"sar" xorm:"sar"`
Cn string `json:"cn" xorm:"cn"`
SmData string `json:"smData" xorm:"sm_data"`
SmfSel string `json:"smfSel" xorm:"smf_sel"`
EpsDat string `json:"epsDat" xorm:"eps_dat"`
NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统
EpsFlag string `json:"epsFlag" xorm:"eps_flag"`
EpsOdb string `json:"epsOdb" xorm:"eps_odb"`
HplmnOdb string `json:"hplmnOdb" xorm:"hplmn_odb"`
Ard string `json:"ard" xorm:"ard"`
Epstpl string `json:"epstpl" xorm:"epstpl"`
ContextId string `json:"contextId" xorm:"context_id"`
ApnContext string `json:"apnContext" xorm:"apn_context"`
StaticIp string `json:"staticIp" xorm:"static_ip"`
SubNum string `json:"subNum,omitempty" xorm:"-"` // 批量数
}

View File

@@ -1,276 +0,0 @@
package repo
import (
"strconv"
"strings"
"nms_cxy/features/udm_user/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoUdmAuthUser 结构体
var NewRepoUdmAuthUser = &RepoUdmAuthUser{
selectSql: `select
id, imsi, amf, status, ki, algo_index, opc, ne_id
from u_auth_user`,
resultMap: map[string]string{
"id": "ID",
"imsi": "Imsi",
"amf": "Amf",
"status": "Status",
"ki": "Ki",
"algo_index": "AlgoIndex",
"opc": "Opc",
"ne_id": "NeID",
},
}
// RepoUdmAuthUser UDM鉴权用户 数据层处理
type RepoUdmAuthUser struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoUdmAuthUser) convertResultRows(rows []map[string]any) []model.UdmAuthUser {
arr := make([]model.UdmAuthUser, 0)
for _, row := range rows {
UdmUser := model.UdmAuthUser{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&UdmUser, keyMapper, value)
}
}
arr = append(arr, UdmUser)
}
return arr
}
// SelectPage 根据条件分页查询
func (r *RepoUdmAuthUser) SelectPage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["imsi"]; ok && v != "" {
conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
params = append(params, v)
}
if v, ok := query["neId"]; ok && v != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, v)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.UdmAuthUser{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from u_auth_user"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
return result
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return result
} else {
result["total"] = total
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 排序
sortSql := ""
if v, ok := query["sortField"]; ok && v != "" {
if v == "imsi" {
sortSql += " order by imsi "
}
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
}
// 查询数据
querySql := r.selectSql + whereSql + sortSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
result["rows"] = r.convertResultRows(results)
return result
}
// SelectList 根据实体查询
func (r *RepoUdmAuthUser) SelectList(auth model.UdmAuthUser) []model.UdmAuthUser {
// 查询条件拼接
var conditions []string
var params []any
if auth.Imsi != "" {
conditions = append(conditions, "imsi = ?")
params = append(params, auth.Imsi)
}
if auth.NeID != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, auth.NeID)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := r.selectSql + whereSql + " order by imsi asc "
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
return r.convertResultRows(results)
}
// ClearAndInsert 清空ne_id后新增实体
func (r *RepoUdmAuthUser) ClearAndInsert(neID string, authArr []model.UdmAuthUser) int64 {
var num int64 = 0
// 清空指定ne_id
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil)
// _, err := datasource.ExecDB("", "DELETE FROM u_auth_user WHERE ne_id = ?", []any{neID})
if err != nil {
log.Errorf("TRUNCATE err => %v", err)
}
n := len(authArr)
batchSize := 2000
for i := 0; i < n; i += batchSize {
end := i + batchSize
if end > n {
end = n
}
batch := authArr[i:end]
// 调用 InsertMulti 函数将批量数据插入数据库
results, err := datasource.DefaultDB().Table("u_auth_user").InsertMulti(batch)
if err != nil {
log.Errorf("InsertMulti err => %v", err)
continue
}
num += results
}
return num
}
// Insert 新增实体
func (r *RepoUdmAuthUser) Insert(authUser model.UdmAuthUser) int64 {
results, err := datasource.DefaultDB().Table("u_auth_user").Insert(authUser)
if err != nil {
log.Errorf("Insert err => %v", err)
return results
}
return results
}
// Insert 批量添加
func (r *RepoUdmAuthUser) Inserts(authUsers []model.UdmAuthUser) int64 {
var num int64
n := len(authUsers)
batchSize := 2000
for i := 0; i < n; i += batchSize {
end := i + batchSize
if end > n {
end = n
}
batch := authUsers[i:end]
// 调用 InsertMulti 函数将批量数据插入数据库
results, err := datasource.DefaultDB().Table("u_auth_user").InsertMulti(batch)
if err != nil {
log.Errorf("Insert err => %v", err)
continue
}
num += results
}
return num
}
// Update 修改更新
func (r *RepoUdmAuthUser) Update(neID string, authUser model.UdmAuthUser) int64 {
// 查询先
var user model.UdmAuthUser
has, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", authUser.Imsi, neID).Get(&user)
if !has || err != nil {
return 0
}
if authUser.Ki != "" && authUser.Ki != user.Ki {
user.Ki = authUser.Ki
}
if authUser.Amf != "" && authUser.Amf != user.Amf {
user.Amf = authUser.Amf
}
if authUser.AlgoIndex != "" && authUser.AlgoIndex != user.AlgoIndex {
user.AlgoIndex = authUser.AlgoIndex
}
if authUser.Opc != "" && authUser.Opc != user.Opc {
user.Opc = authUser.Opc
}
results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", user.Imsi, user.NeID).Update(user)
if err != nil {
return 0
}
return results
}
// Delete 删除实体
func (r *RepoUdmAuthUser) Delete(neID, imsi string) int64 {
results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", imsi, neID).Delete()
if err != nil {
return results
}
return results
}
// Delete 删除范围实体
func (r *RepoUdmAuthUser) Deletes(neID, imsi, num string) int64 {
imsiV, err := strconv.Atoi(imsi)
if err != nil {
return 0
}
numV, err := strconv.Atoi(num)
if err != nil {
return 0
}
results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete()
if err != nil {
return results
}
return results
}

View File

@@ -1,450 +0,0 @@
package repo
import (
"fmt"
"strconv"
"strings"
"nms_cxy/features/udm_user/model"
"nms_cxy/lib/core/datasource"
"nms_cxy/lib/core/utils/parse"
"nms_cxy/lib/log"
)
// 实例化数据层 RepoUdmSubUser 结构体
var NewRepoUdmSubUser = &RepoUdmSubUser{
selectSql: `select
id, msisdn, imsi, ambr, nssai, rat, arfb, sar, cn, sm_data, smf_sel, eps_dat, ne_id, eps_flag, eps_odb, hplmn_odb, ard, epstpl, context_id, apn_context, static_ip
from u_sub_user`,
resultMap: map[string]string{
"id": "ID",
"msisdn": "Msisdn",
"imsi": "Imsi",
"ambr": "Ambr",
"nssai": "Nssai",
"rat": "Rat",
"arfb": "Arfb",
"sar": "Sar",
"cn": "Cn",
"sm_data": "SmData",
"smf_sel": "SmfSel",
"eps_dat": "EpsDat",
"ne_id": "NeID",
"eps_flag": "EpsFlag",
"eps_odb": "EpsOdb",
"hplmn_odb": "HplmnOdb",
"ard": "Ard",
"epstpl": "Epstpl",
"context_id": "ContextId",
"apn_context": "ApnContext",
"static_ip": "StaticIp",
},
}
// RepoUdmSubUser UDM签约用户 数据层处理
type RepoUdmSubUser struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *RepoUdmSubUser) convertResultRows(rows []map[string]any) []model.UdmSubUser {
arr := make([]model.UdmSubUser, 0)
for _, row := range rows {
UdmUser := model.UdmSubUser{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
datasource.SetFieldValue(&UdmUser, keyMapper, value)
}
}
arr = append(arr, UdmUser)
}
return arr
}
// SelectPage 根据条件分页查询字典类型
func (r *RepoUdmSubUser) SelectPage(query map[string]any) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if v, ok := query["msisdn"]; ok && v != "" {
conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')")
params = append(params, v)
}
if v, ok := query["imsi"]; ok && v != "" {
conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
params = append(params, v)
}
if v, ok := query["neId"]; ok && v != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, v)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.UdmAuthUser{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from u_sub_user"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
log.Errorf("total err => %v", err)
return result
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return result
} else {
result["total"] = total
}
// 分页
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 排序
sortSql := ""
if v, ok := query["sortField"]; ok && v != "" {
if v == "imsi" {
sortSql += " order by imsi "
}
if v == "msisdn" {
sortSql += " order by msisdn "
}
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
}
// 查询数据
querySql := r.selectSql + whereSql + sortSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
return result
}
// 转换实体
result["rows"] = r.convertResultRows(results)
return result
}
// SelectList 根据实体查询
func (r *RepoUdmSubUser) SelectList(auth model.UdmSubUser) []model.UdmSubUser {
// 查询条件拼接
var conditions []string
var params []any
if auth.Imsi != "" {
conditions = append(conditions, "imsi = ?")
params = append(params, auth.Imsi)
}
if auth.NeID != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, auth.NeID)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := r.selectSql + whereSql + " order by imsi asc "
results, err := datasource.RawDB("", querySql, params)
if err != nil {
log.Errorf("query err => %v", err)
}
// 转换实体
return r.convertResultRows(results)
}
// ClearAndInsert 清空ne_id后新增实体
func (r *RepoUdmSubUser) ClearAndInsert(neID string, subArr []model.UdmSubUser) int64 {
var num int64 = 0
// 清空指定ne_id
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil)
// _, err := datasource.ExecDB("", "DELETE FROM u_sub_user WHERE ne_id = ?", []any{neID})
if err != nil {
log.Errorf("TRUNCATE err => %v", err)
}
n := len(subArr)
batchSize := 2000
for i := 0; i < n; i += batchSize {
end := i + batchSize
if end > n {
end = n
}
batch := subArr[i:end]
// 调用 InsertMulti 函数将批量数据插入数据库
results, err := datasource.DefaultDB().Table("u_sub_user").InsertMulti(batch)
if err != nil {
log.Errorf("InsertMulti err => %v", err)
continue
}
num += results
}
// for _, u := range subArr {
// u.NeID = neID
// results, err := datasource.DefaultDB().Table("u_sub_user").Insert(u)
// if err != nil {
// return num
// }
// num += results
// }
return num
}
// Insert 新增实体
func (r *RepoUdmSubUser) Insert(subUser model.UdmSubUser) int64 {
results, err := datasource.DefaultDB().Table("u_sub_user").Insert(subUser)
if err != nil {
log.Errorf("Insert err => %v", err)
return results
}
return results
}
// Insert 批量添加
func (r *RepoUdmSubUser) Inserts(subUser []model.UdmSubUser) int64 {
var num int64
n := len(subUser)
batchSize := 2000
for i := 0; i < n; i += batchSize {
end := i + batchSize
if end > n {
end = n
}
batch := subUser[i:end]
// 调用 InsertMulti 函数将批量数据插入数据库
results, err := datasource.DefaultDB().Table("u_sub_user").InsertMulti(batch)
if err != nil {
log.Errorf("Insert err => %v", err)
continue
}
num += results
}
return num
}
// Insert4G 批量添加4G用户
func (r *RepoUdmSubUser) Insert4G(neID string, subUser model.UdmSubUser) int64 {
var insertNum int64
imsiV, err := strconv.Atoi(subUser.Imsi)
if err != nil {
return 0
}
numV, err := strconv.Atoi(subUser.SubNum)
if err != nil {
return 0
}
subUser.NeID = neID
for i := 0; i < numV; i++ {
subUser.Imsi = fmt.Sprint(imsiV + i)
results, err := datasource.DefaultDB().Table("u_sub_user").Insert(subUser)
if err == nil {
log.Errorf("Insert err => %v", err)
insertNum += results
}
}
return insertNum
}
// Update 修改更新
func (r *RepoUdmSubUser) Update(neID string, authUser model.UdmSubUser) int64 {
// 查询先
var user model.UdmSubUser
has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", authUser.Imsi, neID).Get(&user)
if !has || err != nil {
return 0
}
if authUser.Msisdn != "" && authUser.Msisdn != user.Msisdn {
user.Msisdn = authUser.Msisdn
}
if authUser.Ambr != "" && authUser.Ambr != user.Ambr {
user.Ambr = authUser.Ambr
}
if authUser.Arfb != "" && authUser.Arfb != user.Arfb {
user.Arfb = authUser.Arfb
}
if authUser.Sar != "" && authUser.Sar != user.Sar {
user.Sar = authUser.Sar
}
if authUser.Rat != "" && authUser.Rat != user.Rat {
user.Rat = authUser.Rat
}
if authUser.Cn != "" && authUser.Cn != user.Cn {
user.Cn = authUser.Cn
}
if authUser.SmfSel != "" && authUser.SmfSel != user.SmfSel {
user.SmfSel = authUser.SmfSel
}
if authUser.SmData != "" && authUser.SmData != user.SmData {
user.SmData = authUser.SmData
}
if authUser.EpsDat != "" && authUser.EpsDat != user.EpsDat {
user.EpsDat = authUser.EpsDat
}
if authUser.EpsFlag != "" && authUser.EpsFlag != user.EpsFlag {
user.EpsFlag = authUser.EpsFlag
}
if authUser.EpsOdb != "" && authUser.EpsDat != user.EpsDat {
user.EpsOdb = authUser.EpsOdb
}
if authUser.HplmnOdb != "" && authUser.HplmnOdb != user.HplmnOdb {
user.HplmnOdb = authUser.HplmnOdb
}
if authUser.Epstpl != "" && authUser.Epstpl != user.Epstpl {
user.Epstpl = authUser.Epstpl
}
if authUser.Ard != "" && authUser.Ard != user.Ard {
user.Ard = authUser.Ard
}
if authUser.ContextId != "" && authUser.ContextId != user.ContextId {
user.ContextId = authUser.ContextId
}
if authUser.ApnContext != "" && authUser.ApnContext != user.ApnContext {
user.ApnContext = authUser.ApnContext
}
if authUser.StaticIp != "" && authUser.StaticIp != user.StaticIp {
user.StaticIp = authUser.StaticIp
}
results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", user.Imsi, user.NeID).Update(user)
if err != nil {
log.Errorf("Update err => %v", err)
return 0
}
return results
}
// Update4GIP 批量修改4G IP
func (r *RepoUdmSubUser) Update4GIP(neID string, subUser model.UdmSubUser) int64 {
var insertNum int64
imsiV, err := strconv.Atoi(subUser.Imsi)
if err != nil || subUser.StaticIp == "" {
return insertNum
}
numV, err := strconv.Atoi(subUser.SubNum)
if err != nil {
return insertNum
}
for i := 0; i < numV; i++ {
subUser.Imsi = fmt.Sprint(imsiV + i)
// 查询先
var user model.UdmSubUser
has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).Get(&user)
if has && err == nil {
// IP会自动递增
parts := strings.Split(subUser.StaticIp, ".")
lastPart := parts[3]
lastNum, _ := strconv.Atoi(lastPart)
lastNum += i
newLastPart := strconv.Itoa(lastNum)
parts[3] = newLastPart
newIP := strings.Join(parts, ".")
user.StaticIp = newIP
// 更新
results, err := datasource.DefaultDB().Table("u_sub_user").Update(user)
if err == nil {
log.Errorf("Update err => %v", err)
insertNum += results
}
}
}
return insertNum
}
// UpdateSmData 批量修改sm-data
func (r *RepoUdmSubUser) UpdateSmData(neID string, subUser model.UdmSubUser) int64 {
var insertNum int64
imsiV, err := strconv.Atoi(subUser.Imsi)
if err != nil || subUser.StaticIp == "" {
return insertNum
}
numV, err := strconv.Atoi(subUser.SubNum)
if err != nil {
return insertNum
}
for i := 0; i < numV; i++ {
subUser.Imsi = fmt.Sprint(imsiV + i)
// 查询先
var user model.UdmSubUser
has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).Get(&user)
if has && err == nil {
// IP会自动递增需提前规划好DNN对应的IP如dnn不需要绑定IP则不带此字段名
// parts := strings.Split(subUser.SmData, "&")
user.SmData = subUser.SmData
// 更新
results, err := datasource.DefaultDB().Table("u_sub_user").Update(user)
if err == nil {
log.Errorf("Update err => %v", err)
insertNum += results
}
}
}
return insertNum
}
// Delete 删除实体
func (r *RepoUdmSubUser) Delete(neID, imsi string) int64 {
results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", imsi, neID).Delete()
if err != nil {
log.Errorf("Delete err => %v", err)
return results
}
return results
}
// Delete 删除范围实体
func (r *RepoUdmSubUser) Deletes(neID, imsi, num string) int64 {
imsiV, err := strconv.Atoi(imsi)
if err != nil {
return 0
}
numV, err := strconv.Atoi(num)
if err != nil {
return 0
}
results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete()
if err != nil {
log.Errorf("Delete err => %v", err)
return results
}
return results
}

View File

@@ -1,119 +0,0 @@
package service
import (
"strings"
"nms_cxy/features/udm_user/model"
"nms_cxy/src/framework/redis"
)
// phoneImsiList 获取所有imsi
// func phoneImsiList() map[string]string {
// phoneAndImsiArr := make(map[string]string, 0)
// phoneKeys, err := redis.GetKeys("udmuser", "1*********")
// if err != nil {
// return phoneAndImsiArr
// }
// for _, phone := range phoneKeys {
// imsi, err := redis.Get("udmuser", phone)
// if err != nil {
// continue
// }
// phoneAndImsiArr[phone] = imsi
// }
// return phoneAndImsiArr
// }
// redisUdmAuthUserList UDM鉴权用户
func redisUdmAuthUserList() []model.UdmAuthUser {
user := []model.UdmAuthUser{}
ausfArr, err := redis.GetKeys("udmuser", "ausf:*")
if err != nil {
return user
}
for _, key := range ausfArr {
m, err := redis.GetHash("udmuser", key)
if err != nil {
continue
}
// 跳过-号数据
imsi := key[5:]
if strings.Contains(imsi, "-") {
continue
}
status := "0"
if _, ok := m["auth_success"]; ok {
status = "1"
}
amf := ""
if v, ok := m["amf"]; ok {
amf = strings.Replace(v, "\r\n", "", 1)
}
a := model.UdmAuthUser{
Imsi: imsi,
Amf: amf,
Status: status,
Ki: m["ki"],
AlgoIndex: m["algo"],
Opc: m["opc"],
}
user = append(user, a)
}
return user
}
// redisUdmSubUserList UDM签约用户
func redisUdmSubUserList() []model.UdmSubUser {
user := []model.UdmSubUser{}
udmsdArr, err := redis.GetKeys("udmuser", "udm-sd:*")
if err != nil {
return user
}
for _, key := range udmsdArr {
m, err := redis.GetHash("udmuser", key)
if err != nil {
continue
}
a := model.UdmSubUser{
Imsi: key[7:],
Msisdn: m["gpsi"], // 46003550072 strings.TrimPrefix(m["gpsi"], "86"),
SmfSel: m["smf-sel"],
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
}
// def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,-
if v, ok := m["am-dat"]; ok {
arr := strings.Split(v, ",")
a.Ambr = arr[0]
a.Nssai = arr[1]
a.Rat = arr[2]
a.Arfb = arr[3]
a.Sar = arr[4]
a.Cn = arr[5]
}
// 1,64,24,65,def_eps,1,2,010200000000,-
if v, ok := m["eps-dat"]; ok {
arr := strings.Split(v, ",")
// 跳过非常规数据
if len(arr) > 9 {
continue
}
a.EpsDat = v
a.EpsFlag = arr[0]
a.EpsOdb = arr[1]
a.HplmnOdb = arr[2]
a.Ard = arr[3]
a.Epstpl = arr[4]
a.ContextId = arr[5]
a.ApnContext = arr[7]
// [6] 是不要的,导入和导出不用
a.StaticIp = arr[8]
}
user = append(user, a)
}
return user
}

View File

@@ -1,151 +0,0 @@
package service
import (
"fmt"
"strconv"
"nms_cxy/features/udm_user/model"
"nms_cxy/features/udm_user/repo"
)
// 实例化服务层 ServiceUdmAuthUser 结构体
var NewServiceUdmAuthUser = &ServiceUdmAuthUser{
repoAuthUser: *repo.NewRepoUdmAuthUser,
}
// ServiceUdmAuthUser UDM鉴权用户 服务层处理
type ServiceUdmAuthUser struct {
repoAuthUser repo.RepoUdmAuthUser
}
// Save UDM鉴权用户-获取全部保存数据库
func (r *ServiceUdmAuthUser) Save(neID string) int64 {
var num int64 = 0
authArr := redisUdmAuthUserList()
// 有数据才清空
if len(authArr) == 0 {
return num
}
go r.repoAuthUser.ClearAndInsert(neID, authArr)
return int64(len(authArr))
}
// Page UDM签约用户-分页查询数据库
func (r *ServiceUdmAuthUser) Page(query map[string]any) map[string]any {
return r.repoAuthUser.SelectPage(query)
}
// List UDM签约用户-查询数据库
func (r *ServiceUdmAuthUser) List(authUser model.UdmAuthUser) []model.UdmAuthUser {
return r.repoAuthUser.SelectList(authUser)
}
// Insert UDM鉴权用户-新增单个
// imsi长度15ki长度32opc长度0或者32
func (r *ServiceUdmAuthUser) Insert(neID string, authUser model.UdmAuthUser) int64 {
authUser.NeID = neID
authUser.Status = "0"
return r.repoAuthUser.Insert(authUser)
}
// Insert UDM鉴权用户-批量添加
func (r *ServiceUdmAuthUser) Inserts(neID string, authUser model.UdmAuthUser, num string) int64 {
var arr []model.UdmAuthUser
imsiVlen := len(authUser.Imsi)
imsiV, err := strconv.Atoi(authUser.Imsi)
if err != nil {
return 0
}
numV, err := strconv.Atoi(num)
if err != nil {
return 0
}
authUser.NeID = neID
authUser.Status = "0"
for i := 0; i < numV; i++ {
imsi := fmt.Sprint(imsiV + i)
if len(imsi) < imsiVlen {
imsi = fmt.Sprintf("%0*s", imsiVlen, imsi)
}
authUser.Imsi = imsi
arr = append(arr, authUser)
}
return r.repoAuthUser.Inserts(arr)
}
// InsertCSV UDM鉴权用户-批量添加
func (r *ServiceUdmAuthUser) InsertCSV(neID string, data []map[string]string) int64 {
var arr []model.UdmAuthUser
for _, v := range data {
var authUser model.UdmAuthUser
authUser.NeID = neID
authUser.Status = "0"
if s, ok := v["imsi"]; ok {
authUser.Imsi = s
}
if s, ok := v["ki"]; ok {
authUser.Ki = s
}
if s, ok := v["algo"]; ok {
authUser.AlgoIndex = s
}
if s, ok := v["amf"]; ok {
authUser.Amf = s
}
if s, ok := v["opc"]; ok {
authUser.Opc = s
}
if authUser.Imsi == "" {
continue
}
arr = append(arr, authUser)
}
return r.repoAuthUser.Inserts(arr)
}
// InsertTxt UDM鉴权用户-批量添加
func (r *ServiceUdmAuthUser) InsertTxt(neID string, data [][]string) int64 {
var arr []model.UdmAuthUser
for _, v := range data {
if len(v) < 4 {
continue
}
var authUser model.UdmAuthUser
authUser.NeID = neID
authUser.Status = "0"
authUser.Imsi = v[0]
authUser.Ki = v[1]
authUser.AlgoIndex = v[2]
authUser.Amf = v[3]
if len(v) == 5 {
authUser.Opc = v[4]
}
if authUser.Imsi == "" {
continue
}
arr = append(arr, authUser)
}
return r.repoAuthUser.Inserts(arr)
}
// Insert UDM鉴权用户-修改更新
func (r *ServiceUdmAuthUser) Update(neID string, authUser model.UdmAuthUser) int64 {
return r.repoAuthUser.Update(neID, authUser)
}
// Insert UDM鉴权用户-删除单个
func (r *ServiceUdmAuthUser) Delete(neID, imsi string) int64 {
return r.repoAuthUser.Delete(neID, imsi)
}
// Insert UDM鉴权用户-删除范围
func (r *ServiceUdmAuthUser) Deletes(neID, imsi, num string) int64 {
return r.repoAuthUser.Deletes(neID, imsi, num)
}

View File

@@ -1,231 +0,0 @@
package service
import (
"fmt"
"strconv"
"strings"
"nms_cxy/features/udm_user/model"
"nms_cxy/features/udm_user/repo"
)
// 实例化服务层 ServiceUdmSubUser 结构体
var NewServiceUdmSubUser = &ServiceUdmSubUser{
repoSunUser: *repo.NewRepoUdmSubUser,
}
// ServiceUdmSubUser UDM签约用户 服务层处理
type ServiceUdmSubUser struct {
repoSunUser repo.RepoUdmSubUser
}
// Save UDM签约用户-获取全部保存数据库
func (r *ServiceUdmSubUser) Save(neID string) int64 {
var num int64 = 0
subArr := redisUdmSubUserList()
// 有数据才清空
if len(subArr) == 0 {
return num
}
go r.repoSunUser.ClearAndInsert(neID, subArr)
return int64(len(subArr))
}
// Page UDM签约用户-分页查询数据库
func (r *ServiceUdmSubUser) Page(query map[string]any) map[string]any {
return r.repoSunUser.SelectPage(query)
}
// List UDM签约用户-查询数据库
func (r *ServiceUdmSubUser) List(subUser model.UdmSubUser) []model.UdmSubUser {
return r.repoSunUser.SelectList(subUser)
}
// Insert UDM签约用户-新增单个
// imsi长度15ki长度32opc长度0或者32
func (r *ServiceUdmSubUser) Insert(neID string, subUser model.UdmSubUser) int64 {
subUser.NeID = neID
return r.repoSunUser.Insert(subUser)
}
// Insert UDM签约用户-批量添加
func (r *ServiceUdmSubUser) Inserts(neID string, subUser model.UdmSubUser, num string) int64 {
var arr []model.UdmSubUser
imsiVlen := len(subUser.Imsi)
imsiV, err := strconv.Atoi(subUser.Imsi)
if err != nil {
return 0
}
msisdnVlen := len(subUser.Msisdn)
msisdnV, err := strconv.Atoi(subUser.Msisdn)
if err != nil {
return 0
}
numV, err := strconv.Atoi(num)
if err != nil {
return 0
}
subUser.NeID = neID
for i := 0; i < numV; i++ {
msisdn := fmt.Sprint(msisdnV + i)
if len(msisdn) < msisdnVlen {
msisdn = fmt.Sprintf("%0*s", msisdnVlen, msisdn)
}
subUser.Msisdn = msisdn
imsi := fmt.Sprint(imsiV + i)
if len(imsi) < imsiVlen {
imsi = fmt.Sprintf("%0*s", imsiVlen, imsi)
}
subUser.Imsi = imsi
// IP会自动递增
if len(subUser.StaticIp) > 5 {
parts := strings.Split(subUser.StaticIp, ".")
lastPart := parts[3]
lastNum, _ := strconv.Atoi(lastPart)
lastNum += i
newLastPart := strconv.Itoa(lastNum)
parts[3] = newLastPart
newIP := strings.Join(parts, ".")
subUser.StaticIp = newIP
}
subUser.EpsDat = fmt.Sprintf("%s,%s,%s,%s,%s,%s,2,%s,%s", subUser.EpsFlag, subUser.EpsOdb, subUser.HplmnOdb, subUser.Ard, subUser.Epstpl, subUser.ContextId, subUser.ApnContext, subUser.StaticIp)
arr = append(arr, subUser)
}
return r.repoSunUser.Inserts(arr)
}
// InsertCSV UDM签约用户-批量添加
func (r *ServiceUdmSubUser) InsertCSV(neID string, data []map[string]string) int64 {
var arr []model.UdmSubUser
for _, v := range data {
var subUser model.UdmSubUser
subUser.NeID = neID
if s, ok := v["imsi"]; ok {
subUser.Imsi = s
}
if s, ok := v["msisdn"]; ok {
subUser.Msisdn = s
}
if s, ok := v["ambr"]; ok {
subUser.Ambr = s
}
if s, ok := v["nssai"]; ok {
subUser.Nssai = s
}
if s, ok := v["arfb"]; ok {
subUser.Arfb = s
}
if s, ok := v["sar"]; ok {
subUser.Sar = s
}
if s, ok := v["rat"]; ok {
subUser.Rat = s
}
if s, ok := v["cn"]; ok {
subUser.Cn = s
}
if s, ok := v["smf_sel"]; ok {
subUser.SmfSel = s
}
if s, ok := v["sm_dat"]; ok {
subUser.SmData = s
}
if s, ok := v["eps_dat"]; ok {
subUser.EpsDat = s
arr := strings.Split(s, ",")
if len(arr) == 8 {
subUser.EpsFlag = arr[0]
subUser.EpsOdb = arr[1]
subUser.HplmnOdb = arr[2]
subUser.Ard = arr[3]
subUser.Epstpl = arr[4]
subUser.ContextId = arr[5]
subUser.ApnContext = arr[6]
subUser.StaticIp = arr[7]
}
}
if subUser.Imsi == "" {
continue
}
arr = append(arr, subUser)
}
return r.repoSunUser.Inserts(arr)
}
// InsertTxt UDM签约用户-批量添加
func (r *ServiceUdmSubUser) InsertTxt(neID string, data [][]string) int64 {
var arr []model.UdmSubUser
for _, v := range data {
if len(v) < 10 {
continue
}
var subUser model.UdmSubUser
subUser.NeID = neID
subUser.Imsi = v[0]
subUser.Msisdn = v[1]
subUser.Ambr = v[2]
subUser.Nssai = v[3]
subUser.Arfb = v[4]
subUser.Sar = v[5]
subUser.Rat = v[6]
subUser.Cn = v[7]
subUser.SmfSel = v[8]
subUser.SmData = v[9]
if len(v) > 17 {
subUser.EpsFlag = v[10]
subUser.EpsOdb = v[11]
subUser.HplmnOdb = v[12]
subUser.Ard = v[13]
subUser.Epstpl = v[14]
subUser.ContextId = v[15]
subUser.ApnContext = v[16]
subUser.StaticIp = v[17]
subUser.EpsDat = strings.Join(v[10:], ",")
}
if subUser.Imsi == "" {
continue
}
arr = append(arr, subUser)
}
return r.repoSunUser.Inserts(arr)
}
// Insert UDM签约用户-批量添加4G用户
func (r *ServiceUdmSubUser) Insert4G(neID string, subUser model.UdmSubUser) int64 {
return r.repoSunUser.Insert4G(neID, subUser)
}
// Insert UDM签约用户-修改更新
func (r *ServiceUdmSubUser) Update(neID string, subUser model.UdmSubUser) int64 {
return r.repoSunUser.Update(neID, subUser)
}
// Update4GIP UDM签约用户-批量修改4G IP
func (r *ServiceUdmSubUser) Update4GIP(neID string, subUser model.UdmSubUser) int64 {
return r.repoSunUser.Update4GIP(neID, subUser)
}
// Update4GIP UDM签约用户-批量修改sm-data
func (r *ServiceUdmSubUser) UpdateSmData(neID string, subUser model.UdmSubUser) int64 {
return r.repoSunUser.UpdateSmData(neID, subUser)
}
// Insert UDM签约用户-删除单个
func (r *ServiceUdmSubUser) Delete(neID, imsi string) int64 {
return r.repoSunUser.Delete(neID, imsi)
}
// Insert UDM签约用户-删除范围
func (r *ServiceUdmSubUser) Deletes(neID, imsi, num string) int64 {
return r.repoSunUser.Deletes(neID, imsi, num)
}

View File

@@ -8,12 +8,14 @@ import (
"strings"
"time"
"nms_cxy/lib/core/ctx"
"nms_cxy/lib/dborm"
"nms_cxy/lib/global"
"nms_cxy/lib/log"
"nms_cxy/lib/services"
"nms_cxy/omc/config"
tokenConst "nms_cxy/src/framework/constants/token"
neService "nms_cxy/src/modules/network_element/service"
"github.com/go-resty/resty/v2"
"github.com/gorilla/mux"
@@ -47,6 +49,7 @@ type SmfUEInfo struct {
UpfN3IP string `json:"upfN3IP"`
RanN3IP string `json:"ranN3IP"`
Activetime string `json:"activeTime"`
UpState string `json:"upState"`
} `json:"pduSessionInfo"`
}
@@ -241,66 +244,38 @@ func GetSubscriptionsFromNSSF(w http.ResponseWriter, r *http.Request) {
// Get UEInfo from NF/NFs
func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) {
log.Info("GetUEInfoFromNF processing... ")
log.Debug("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 {
neId := ctx.GetQuery(r, "neId")
neType := ctx.GetParam(r, "elementTypeValue")
if neType == "" || neId == "" {
log.Error("elementTypeValue/neId is empty")
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 := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId)
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
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)
}
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{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.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
}
services.ResponseWithJson(w, http.StatusOK, response)
}
// POST User Info from NF/NFs